Skip to content
This repository was archived by the owner on Dec 28, 2021. It is now read-only.

Use official @serverless/typescript to improve typings #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions __tests__/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import TypeScriptPlugin from '../src';
import { ServerlessTSInstance, ServerlessTSFunctionMap } from '../src/types';
import {
ServerlessTSInstance,
ServerlessTSFunctionMap,
ServerlessTSProviderRuntimes,
} from '../src/types';

const createInstance = (
slsFunctions?: ServerlessTSFunctionMap,
globalRuntime?: string,
globalRuntime?: ServerlessTSProviderRuntimes,
): ServerlessTSInstance => ({
cli: {
log: jest.fn(),
Expand All @@ -16,9 +20,7 @@ const createInstance = (
name: 'aws',
runtime: globalRuntime,
},
functions: slsFunctions ? slsFunctions : {},
getFunction: jest.fn(),
getAllFunctions: jest.fn(),
functions: slsFunctions ?? {},
},
pluginManager: {
spawn: jest.fn(),
Expand Down Expand Up @@ -69,7 +71,9 @@ describe('functions', () => {
const slsInstance = createInstance(functions, 'nodejs10.x');
const plugin = new TypeScriptPlugin(slsInstance, {});

expect(Object.values(plugin.functions).map((fn) => fn.handler)).toEqual([
expect(
Object.values(plugin.functions ?? {}).map((fn) => fn.handler),
).toEqual([
'tests/assets/hello.handler',
'tests/assets/world.handler',
'tests/assets/jsfile.create',
Expand All @@ -82,9 +86,9 @@ describe('functions', () => {
const slsInstance = createInstance(functions, 'python2.7');
const plugin = new TypeScriptPlugin(slsInstance, {});

expect(Object.values(plugin.functions).map((fn) => fn.handler)).toEqual([
'tests/assets/world.handler',
]);
expect(
Object.values(plugin.functions ?? {}).map((fn) => fn.handler),
).toEqual(['tests/assets/world.handler']);
});
});

Expand All @@ -93,7 +97,9 @@ describe('functions', () => {
const slsInstance = createInstance(functions);
const plugin = new TypeScriptPlugin(slsInstance, {});

expect(Object.values(plugin.functions).map((fn) => fn.handler)).toEqual([
expect(
Object.values(plugin.functions ?? {}).map((fn) => fn.handler),
).toEqual([
'tests/assets/hello.handler',
'tests/assets/world.handler',
'tests/assets/jsfile.create',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@
"node": ">=10.0.0"
},
"devDependencies": {
"@serverless/typescript": "2.14.0",
"@types/fs-extra": "9.0.4",
"@types/jest": "26.0.16",
"@types/lodash": "4.14.165",
"@types/node": "14.14.10",
"@types/serverless": "1.78.12",
"@typescript-eslint/eslint-plugin": "4.9.0",
"@typescript-eslint/parser": "4.9.0",
"eslint": "7.15.0",
Expand Down
55 changes: 28 additions & 27 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import * as path from 'path';
import * as fse from 'fs-extra';
import _ from 'lodash';
import globby from 'globby';
import { unwatchFile, watchFile, Stats } from 'fs-extra';

import {
ServerlessTSFunctionMap,
ServerlessTSInstance,
ServerlessTSOptions,
ServerlessTSFunction,
} from './types';
import {
extractFileNames,
Expand All @@ -15,7 +16,6 @@ import {
getSourceFiles,
getFiles,
} from './utils';
import { unwatchFile, watchFile, Stats } from 'fs-extra';

const SERVERLESS_FOLDER = '.serverless';
const BUILD_FOLDER = '.build';
Expand Down Expand Up @@ -97,17 +97,18 @@ class TypeScriptPlugin {
};
}

get functions(): { [key: string]: ServerlessTSFunction } {
const { options } = this;
const { service } = this.serverless;
get functions(): ServerlessTSFunctionMap {
const options = this.options;
const service = this.serverless.service;

const allFunctions = options.function
? {
[options.function]: service.functions[options.function],
}
: service.functions;
const allFunctions =
options.function && service.functions
? {
[options.function]: service.functions[options.function],
}
: service.functions;

if (Object.keys(allFunctions).length === 0) {
if (Object.keys(allFunctions ?? {}).length === 0) {
throw new Error('There are no functions to package/deploy!');
}
// Ensure we only handle runtimes that support Typescript
Expand Down Expand Up @@ -213,18 +214,19 @@ class TypeScriptPlugin {
*/
async copyExtras(): Promise<void> {
this.serverless.cli.log('Copying Extras...');
const { service } = this.serverless;
// include any "extras" from the "include" section
for await (const fn of Object.values(service.functions)) {
this.copyIncludes(fn.package.include);
const service = this.serverless.service;
// include any "extras" from the "include" section. The copy should be
// awaited for each extra before continuing.
for (const fn of Object.values(service.functions ?? {})) {
await this.copyIncludes(fn.package?.include);
}
if (this.serverless.package?.include) {
this.copyIncludes(this.serverless.package.include);
await this.copyIncludes(this.serverless.package.include);
}
this.serverless.cli.log('Finished Copying Extras');
}

private async copyIncludes(include: string[]): Promise<void> {
private async copyIncludes(include: string[] | undefined): Promise<void> {
if (!include) return;

const files = await globby(include);
Expand Down Expand Up @@ -292,35 +294,34 @@ class TypeScriptPlugin {
* packaging preferences.
*/
async moveArtifacts(): Promise<void> {
const { service } = this.serverless;
const service = this.serverless.service;

await fse.copy(
path.join(this.originalServicePath, BUILD_FOLDER, SERVERLESS_FOLDER),
path.join(this.originalServicePath, SERVERLESS_FOLDER),
);

if (this.options.function) {
if (this.options.function && service.functions) {
const fn = service.functions[this.options.function];
const artifact = fn.package.artifact;
if (artifact) {
if (fn.package?.artifact) {
fn.package.artifact = path.join(
this.originalServicePath,
SERVERLESS_FOLDER,
path.basename(artifact),
path.basename(fn.package.artifact),
);
}
return;
}

if (this.serverless.package?.individually) {
const functionNames = Object.keys(this.functions);
const functionNames = Object.keys(this.functions ?? {});
functionNames.forEach((name) => {
const artifact = service.functions[name].package.artifact;
if (artifact) {
service.functions[name].package.artifact = path.join(
const pkg = service.functions?.[name].package;
if (pkg?.artifact) {
pkg.artifact = path.join(
this.originalServicePath,
SERVERLESS_FOLDER,
path.basename(artifact),
path.basename(pkg.artifact),
);
}
});
Expand Down
22 changes: 5 additions & 17 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FunctionDefinition } from 'serverless';
import { AWS } from '@serverless/typescript';

export type ServerlessTSFunctionMap = Record<string, ServerlessTSFunction>;
export type ServerlessTSFunctionMap = AWS['functions'];
export type ServerlessTSProviderRuntimes = AWS['provider']['runtime'];

export interface ServerlessTSInstance {
cli: {
Expand All @@ -14,11 +15,8 @@ export interface ServerlessTSInstance {
pluginManager: ServerlessTSPluginManager;
}

export interface ServerlessTSService {
provider: {
name: string;
runtime?: string;
};
export interface ServerlessTSService
extends Pick<AWS, 'custom' | 'provider' | 'functions'> {
custom?: {
/**
* Custom options to be passed to this plugin.
Expand All @@ -32,9 +30,6 @@ export interface ServerlessTSService {
exclude?: string[];
};
};
functions: ServerlessTSFunctionMap;
getAllFunctions(): string[];
getFunction(functionName: string): FunctionDefinition;
}

/** CLI Options */
Expand All @@ -49,13 +44,6 @@ export interface ServerlessTSOptions {
tsconfigFilePath?: string;
}

export interface ServerlessTSFunction
extends Pick<FunctionDefinition, 'handler' | 'runtime'> {
handler: string;
package: ServerlessTSPackage;
runtime?: string;
}

/** Optional deployment packaging configuration */
export interface ServerlessTSPackage {
/** Specify the directories and files which should be included in the deployment package */
Expand Down
12 changes: 6 additions & 6 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import * as fse from 'fs-extra';
import _ from 'lodash';
import * as path from 'path';
import globby from 'globby';

import { ServerlessTSFunction } from './types';
import { ServerlessTSFunctionMap } from './types';

export const makeDefaultTypescriptConfig = (): CompilerOptions => {
const defaultTypescriptConfig: CompilerOptions = {
Expand All @@ -34,7 +33,7 @@ export const makeDefaultTypescriptConfig = (): CompilerOptions => {
export const extractFileNames = (
cwd: string,
provider: string,
functions?: { [key: string]: ServerlessTSFunction },
functions?: ServerlessTSFunctionMap,
): string[] => {
// The Google provider will use the entrypoint not from the definition of the
// handler function, but instead from the package.json:main field, or via a
Expand Down Expand Up @@ -69,15 +68,16 @@ export const extractFileNames = (
return _.values(functions)
.map((fn) => fn.handler)
.map((h) => {
const fnName = _.last(h.split('.'));
const fnName = _.last(h?.split('.'));
if (!fnName) {
throw new Error(
`Couldn't get exported function name; missing name after '.' in ${h}`,
);
}
const fnNameLastAppearanceIndex = h.lastIndexOf(fnName);
// TODO: the handler name should exist.
const fnNameLastAppearanceIndex = h?.lastIndexOf(fnName);
// replace only last instance to allow the same name for file and handler
const fileName = h.substring(0, fnNameLastAppearanceIndex);
const fileName = h?.substring(0, fnNameLastAppearanceIndex);

// Check if the .ts files exists. If so return that to watch
if (fse.existsSync(path.join(cwd, fileName + 'ts'))) {
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,11 @@
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.0"

"@serverless/typescript@^2.14.0":
version "2.14.0"
resolved "https://registry.yarnpkg.com/@serverless/typescript/-/typescript-2.14.0.tgz#79b04fd1d62622394bdc7c29e1d2f07f4ba91561"
integrity sha512-nL8jolUVHi6yxTwCxOymMsun2mtsG2osOYtSmirjyRllJZBQ79BESjoMPNmKR0ZDWyxjzPLP7rTe7XtTVeZvJA==

"@sinonjs/commons@^1.7.0":
version "1.8.1"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217"
Expand Down Expand Up @@ -621,11 +626,6 @@
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00"
integrity sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==

"@types/serverless@1.78.12":
version "1.78.12"
resolved "https://registry.yarnpkg.com/@types/serverless/-/serverless-1.78.12.tgz#bd2d7bc448a482cc55822d3185a0669fde83171e"
integrity sha512-uUq3dg4PlRg1/n8pyKfCxOw9K9w/Gp2FPQMvgBJklCx6zIc9Dskpx23n1YLnSJ0k98Ri8boMu6ns6Eugap+muQ==

"@types/stack-utils@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
Expand Down