[tests] Unify linting and autoformatting (#2914)

* add prettier and eslint on root

* remove eslint from now-cli

* adjust root package.json

* adjust eslintignore

* adjust now-cli rules

* remove @zeit/git-hooks in packages

* adjust now-client eslint config

* add lint-staged and hook on pre-commit

* add pre-commit script

* replace @zeit/git-hooks with husky

* remove unnecessary script

* fix eslint errors

* trigger tests

* fix fixable errors

* fix fixable errors (bis)

* revert two changes
This commit is contained in:
Luc
2019-08-29 21:17:40 +02:00
committed by Andy Bitz
parent 84af278e86
commit 59e7367e03
43 changed files with 1033 additions and 1019 deletions

29
.eslintignore Normal file
View File

@@ -0,0 +1,29 @@
node_modules
dist
# now-cli
packages/now-cli/@types
packages/now-cli/download
packages/now-cli/dist
packages/now-cli/test/fixtures
packages/now-cli/test/dev/fixtures
packages/now-cli/bin
packages/now-cli/link
packages/now-cli/src/util/dev/templates/*.ts
# now-client
packages/now-client/tests/fixtures
packages/now-client/lib
# now-next
packages/now-next/test/fixtures
# now-node
packages/now-node/src/bridge.ts
packages/now-node/test/fixtures
# now-node-bridge
packages/now-node-bridge/bridge.*
# now-static-build
packages/now-static-build/test/fixtures

64
.eslintrc.json Normal file
View File

@@ -0,0 +1,64 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"modules": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"env": {
"node": true,
"jest": true,
"es6": true
},
"rules": {
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-use-before-define": 0
},
"overrides": [
{
"files": ["**/*.js"],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
},
{
"files": ["packages/now-cli/**/*"],
"rules": {
"lines-between-class-members": 0,
"no-async-promise-executor": 0,
"no-control-regex": 0,
"no-empty": 0,
"prefer-const": 0,
"prefer-destructuring": 0,
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/consistent-type-assertions": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-inferrable-types": 0,
"@typescript-eslint/no-var-requires": 0
}
},
{
"files": ["packages/now-client/**/*"],
"rules": {
"prefer-const": 0,
"require-atomic-updates": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/no-explicit-any": 0
}
}
]
}

3
.prettierrc Normal file
View File

@@ -0,0 +1,3 @@
{
"singleQuote": true
}

View File

@@ -15,10 +15,17 @@
"lerna": "3.16.4"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "2.0.0",
"@typescript-eslint/parser": "2.0.0",
"@zeit/ncc": "0.20.4",
"async-retry": "1.2.3",
"buffer-replace": "1.0.0",
"node-fetch": "2.6.0"
"eslint": "6.2.2",
"eslint-config-prettier": "6.1.0",
"husky": "3.0.4",
"lint-staged": "9.2.5",
"node-fetch": "2.6.0",
"prettier": "1.18.2"
},
"scripts": {
"lerna": "lerna",
@@ -31,6 +38,23 @@
"test-unit": "node run.js test-unit",
"test-integration": "node run.js test-integration",
"test-integration-once": "node run.js test-integration-once",
"test-integration-now-dev": "node run.js test-integration-now-dev"
"test-integration-now-dev": "node run.js test-integration-now-dev",
"lint": "eslint . --ext .ts,.js"
},
"lint-staged": {
"*.{js,ts}": [
"prettier --write",
"eslint",
"git add"
],
"*.{json,md}": [
"prettier --write",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
}

View File

@@ -10,20 +10,20 @@ interface Options {
tag?: 'canary' | 'latest' | string;
}
const src: string = 'package.json';
const src = 'package.json';
const config: Config = { zeroConfig: true };
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
code: 'missing_build_script',
message:
'Your `package.json` file is missing a `build` property inside the `script` property.' +
'\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script',
'\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script'
};
// Static builders are special cased in `@now/static-build`
function getBuilders(): Map<string, Builder> {
return new Map<string, Builder>([
['next', { src, use: '@now/next', config }],
['next', { src, use: '@now/next', config }]
]);
}
@@ -35,7 +35,7 @@ function getApiBuilders(): Builder[] {
{ src: 'api/**/*.ts', use: '@now/node', config },
{ src: 'api/**/*.go', use: '@now/go', config },
{ src: 'api/**/*.py', use: '@now/python', config },
{ src: 'api/**/*.rb', use: '@now/ruby', config },
{ src: 'api/**/*.rb', use: '@now/ruby', config }
];
}
@@ -96,8 +96,8 @@ async function detectApiBuilders(files: string[]): Promise<Builder[]> {
.sort(sortFiles)
.filter(ignoreApiFilter)
.map(file => {
const result = getApiBuilders().find(
({ src }): boolean => minimatch(file, src)
const result = getApiBuilders().find(({ src }): boolean =>
minimatch(file, src)
);
return result ? { ...result, src: file } : null;
@@ -138,7 +138,7 @@ export async function detectBuilders(
builders.push({
use: '@now/static',
src: 'public/**/*',
config,
config
});
} else if (builders.length > 0) {
// We can't use pattern matching, since `!(api)` and `!(api)/**/*`
@@ -150,7 +150,7 @@ export async function detectBuilders(
.map(name => ({
use: '@now/static',
src: name,
config,
config
}))
);
}
@@ -177,6 +177,6 @@ export async function detectBuilders(
return {
builders: builders.length ? builders : null,
errors: errors.length ? errors : null,
errors: errors.length ? errors : null
};
}

View File

@@ -43,11 +43,10 @@ function getSegmentName(segment: string): string | null {
function createRouteFromPath(filePath: string): Route {
const parts = filePath.split('/');
let counter: number = 1;
let counter = 1;
const query: string[] = [];
const srcParts = parts.map(
(segment, index): string => {
const srcParts = parts.map((segment, index): string => {
const name = getSegmentName(segment);
const isLast = index === parts.length - 1;
@@ -63,7 +62,7 @@ function createRouteFromPath(filePath: string): Route {
const names = [
prefix,
prefix + escapeName(fileName),
prefix + escapeName(fileName) + escapeName(ext),
prefix + escapeName(fileName) + escapeName(ext)
].filter(Boolean);
// Either filename with extension, filename without extension
@@ -72,8 +71,7 @@ function createRouteFromPath(filePath: string): Route {
}
return segment;
}
);
});
const { name: fileName } = parsePath(filePath);
const isIndex = fileName === 'index';
@@ -230,8 +228,8 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
message:
`The segment "${conflictingSegment}" occurres more than ` +
`one time in your path "${file}". Please make sure that ` +
`every segment in a path is unique`,
},
`every segment in a path is unique`
}
};
}
@@ -251,8 +249,8 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
message:
`Two or more files have conflicting paths or names. ` +
`Please make sure path segments and filenames, without their extension, are unique. ` +
`The path "${file}" has conflicts with ${messagePaths}`,
},
`The path "${file}" has conflicts with ${messagePaths}`
}
};
}
@@ -263,7 +261,7 @@ async function detectApiRoutes(files: string[]): Promise<RoutesResult> {
if (defaultRoutes.length) {
defaultRoutes.push({
status: 404,
src: '/api(\\/.*)?$',
src: '/api(\\/.*)?$'
});
}
@@ -289,7 +287,7 @@ export async function detectRoutes(
if (routesResult.defaultRoutes && hasPublicBuilder(builders)) {
routesResult.defaultRoutes.push({
src: '/(.*)',
dest: '/public/$1',
dest: '/public/$1'
});
}

View File

@@ -1,20 +1,16 @@
/* global beforeAll, expect, it, jest */
const path = require('path');
const fs = require('fs-extra');
// eslint-disable-next-line import/no-extraneous-dependencies
const execa = require('execa');
const assert = require('assert');
const { createZip } = require('../dist/lambda');
const {
glob, download, detectBuilders, detectRoutes,
} = require('../');
const { glob, download, detectBuilders, detectRoutes } = require('../');
const {
getSupportedNodeVersion,
defaultSelection,
defaultSelection
} = require('../dist/fs/node-version');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment');
jest.setTimeout(4 * 60 * 1000);
@@ -42,7 +38,7 @@ it('should re-create symlinks properly', async () => {
const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')),
fs.lstat(path.join(outDir, 'a.txt'))
]);
assert(linkStat.isSymbolicLink());
assert(aStat.isFile());
@@ -64,7 +60,7 @@ it('should create zip files with symlinks properly', async () => {
const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
fs.lstat(path.join(outDir, 'a.txt')),
fs.lstat(path.join(outDir, 'a.txt'))
]);
assert(linkStat.isSymbolicLink());
assert(aStat.isFile());
@@ -86,33 +82,33 @@ it('should match all semver ranges', () => {
// See https://docs.npmjs.com/files/package.json#engines
expect(getSupportedNodeVersion('10.0.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('10.x')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10')).resolves.toHaveProperty('major', 10);
expect(getSupportedNodeVersion('>=10.3.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('8.5.0 - 10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('>=9.0.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('>=9.5.0 <=10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('~10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
expect(getSupportedNodeVersion('^10.5.0')).resolves.toHaveProperty(
'major',
10,
10
);
});
@@ -124,7 +120,7 @@ it('should support require by path for legacy builders', () => {
const glob2 = require('@now/build-utils/fs/glob.js');
const rename2 = require('@now/build-utils/fs/rename.js');
const {
runNpmInstall: runNpmInstall2,
runNpmInstall: runNpmInstall2
} = require('@now/build-utils/fs/run-user-scripts.js');
const streamToBuffer2 = require('@now/build-utils/fs/stream-to-buffer.js');
@@ -162,8 +158,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}
@@ -176,7 +172,7 @@ const buildersToTestWith = ['now-next', 'now-node', 'now-static-build'];
for (const builder of buildersToTestWith) {
const fixturesPath2 = path.resolve(
__dirname,
`../../${builder}/test/fixtures`,
`../../${builder}/test/fixtures`
);
// eslint-disable-next-line no-restricted-syntax
@@ -188,8 +184,8 @@ for (const builder of buildersToTestWith) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath2, fixture),
),
path.join(fixturesPath2, fixture)
)
).resolves.toBeDefined();
});
}
@@ -210,7 +206,7 @@ it('Test `detectBuilders`', async () => {
// package.json + no build + next
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
@@ -222,7 +218,7 @@ it('Test `detectBuilders`', async () => {
// package.json + no build + next
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
@@ -286,7 +282,7 @@ it('Test `detectBuilders`', async () => {
const files = [
'api/_utils/handler.js',
'api/[endpoint]/.helper.js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files);
@@ -299,7 +295,7 @@ it('Test `detectBuilders`', async () => {
// api + next + public
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'api/endpoint.js', 'public/index.html'];
@@ -315,7 +311,7 @@ it('Test `detectBuilders`', async () => {
// api + next + raw static
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'api/endpoint.js', 'index.html'];
@@ -347,7 +343,7 @@ it('Test `detectBuilders`', async () => {
'api/endpoint.js',
'public/index.html',
'public/favicon.ico',
'README.md',
'README.md'
];
const { builders } = await detectBuilders(files);
@@ -371,7 +367,7 @@ it('Test `detectBuilders`', async () => {
// next + public
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['package.json', 'public/index.html', 'README.md'];
@@ -385,7 +381,7 @@ it('Test `detectBuilders`', async () => {
// nuxt
const pkg = {
scripts: { build: 'nuxt build' },
dependencies: { nuxt: '2.8.1' },
dependencies: { nuxt: '2.8.1' }
};
const files = ['package.json', 'pages/index.js'];
@@ -437,12 +433,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + canary
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files, pkg, { tag: 'canary' });
@@ -456,12 +452,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + latest
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files, pkg, { tag: 'latest' });
@@ -475,12 +471,12 @@ it('Test `detectBuilders`', async () => {
// package.json + api + random tag
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
dependencies: { next: '9.0.0' }
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files, pkg, { tag: 'haha' });
@@ -549,7 +545,7 @@ it('Test `detectRoutes`', async () => {
const files = [
'public/index.html',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
'api/[endpoint]/[id].js'
];
const { builders } = await detectBuilders(files);
@@ -564,7 +560,7 @@ it('Test `detectRoutes`', async () => {
{
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
devDependencies: { next: '9.0.0' }
};
const files = ['public/index.html', 'api/[endpoint].js'];
@@ -592,7 +588,7 @@ it('Test `detectRoutes`', async () => {
expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe(
'^/api/date(\\/|\\/index|\\/index\\.js)?$',
'^/api/date(\\/|\\/index|\\/index\\.js)?$'
);
expect(defaultRoutes[0].dest).toBe('/api/date/index.js');
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
@@ -607,7 +603,7 @@ it('Test `detectRoutes`', async () => {
expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe(
'^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$',
'^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$'
);
expect(defaultRoutes[0].dest).toBe('/api/[date]/index.js?date=$1');
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
@@ -621,7 +617,7 @@ it('Test `detectRoutes`', async () => {
'api/users/index.ts',
'api/users/index.d.ts',
'api/food.ts',
'api/ts/gold.ts',
'api/ts/gold.ts'
];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
@@ -645,39 +641,39 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
{
path: '/api/my-endpoint',
mustContain: 'my-endpoint',
status: 200,
status: 200
},
{
path: '/api/other-endpoint',
mustContain: 'other-endpoint',
status: 200,
status: 200
},
{
path: '/api/team/zeit',
mustContain: 'team/zeit',
status: 200,
status: 200
},
{
path: '/api/user/myself',
mustContain: 'user/myself',
status: 200,
status: 200
},
{
path: '/api/not-okay/',
status: 404,
status: 404
},
{
path: '/api',
status: 404,
status: 404
},
{
path: '/api/',
status: 404,
status: 404
},
{
path: '/',
mustContain: 'hello from index.txt',
},
mustContain: 'hello from index.txt'
}
];
const { builders } = await detectBuilders(files, pkg);
@@ -686,12 +682,12 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile(
path.join(fixture, 'now.json'),
JSON.stringify(nowConfig, null, 2),
JSON.stringify(nowConfig, null, 2)
);
const deployment = await testDeployment(
{ builderUrl, buildUtilsUrl },
fixture,
fixture
);
expect(deployment).toBeDefined();
});
@@ -705,32 +701,32 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
const probes = [
{
path: '/api/not-okay',
status: 404,
status: 404
},
{
path: '/api',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/index',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/index.js',
mustContain: 'hello from api/index.js',
status: 200,
status: 200
},
{
path: '/api/date.js',
mustContain: 'hello from api/date.js',
status: 200,
status: 200
},
{
// Someone might expect this to be `date.js`,
@@ -739,27 +735,27 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
// so it is not special cased
path: '/api/date',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/api/date/',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/api/date/index',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/api/date/index.js',
mustContain: 'hello from api/date/index.js',
status: 200,
status: 200
},
{
path: '/',
mustContain: 'hello from index.txt',
},
mustContain: 'hello from index.txt'
}
];
const { builders } = await detectBuilders(files, pkg);
@@ -768,12 +764,12 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile(
path.join(fixture, 'now.json'),
JSON.stringify(nowConfig, null, 2),
JSON.stringify(nowConfig, null, 2)
);
const deployment = await testDeployment(
{ builderUrl, buildUtilsUrl },
fixture,
fixture
);
expect(deployment).toBeDefined();
});

View File

@@ -1,17 +1,15 @@
const path = require('path');
const { mkdirp, copyFile } = require('fs-extra');
const glob = require('@now/build-utils/fs/glob'); // eslint-disable-line import/no-extraneous-dependencies
const download = require('@now/build-utils/fs/download'); // eslint-disable-line import/no-extraneous-dependencies
const { createLambda } = require('@now/build-utils/lambda'); // eslint-disable-line import/no-extraneous-dependencies
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory'); // eslint-disable-line import/no-extraneous-dependencies
const { shouldServe } = require('@now/build-utils'); // eslint-disable-line import/no-extraneous-dependencies
const glob = require('@now/build-utils/fs/glob');
const download = require('@now/build-utils/fs/download');
const { createLambda } = require('@now/build-utils/lambda');
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory');
const { shouldServe } = require('@now/build-utils');
exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.build = async ({
workPath, files, entrypoint, meta,
}) => {
exports.build = async ({ workPath, files, entrypoint, meta }) => {
console.log('downloading files...');
const outDir = await getWritableDirectory();
@@ -26,7 +24,7 @@ exports.build = async ({
// For now only the entrypoint file is copied into the lambda
await copyFile(
path.join(workPath, entrypoint),
path.join(outDir, entrypoint),
path.join(outDir, entrypoint)
);
const lambda = await createLambda({
@@ -34,12 +32,12 @@ exports.build = async ({
handler: 'handler',
runtime: 'go1.x',
environment: {
SCRIPT_FILENAME: entrypoint,
},
SCRIPT_FILENAME: entrypoint
}
});
return {
[entrypoint]: lambda,
[entrypoint]: lambda
};
};

View File

@@ -1,8 +0,0 @@
@types
download
dist
test/fixtures
test/dev/fixtures
bin
link
src/util/dev/templates/*.ts

View File

@@ -1,86 +0,0 @@
module.exports = {
'extends': [
'airbnb',
'prettier'
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 2018,
'sourceType': 'module',
'modules': true
},
'plugins': [
'@typescript-eslint'
],
'settings': {
'import/resolver': {
'typescript': {
}
}
},
'rules': {
'quotes': [
2,
'single',
{
'allowTemplateLiterals': true
}
],
'class-methods-use-this': 0,
'consistent-return': 0,
'func-names': 0,
'global-require': 0,
'guard-for-in': 0,
'import/no-duplicates': 0,
'import/no-dynamic-require': 0,
'import/no-extraneous-dependencies': 0,
'import/prefer-default-export': 0,
'lines-between-class-members': 0,
'no-await-in-loop': 0,
'no-bitwise': 0,
'no-console': 0,
'no-continue': 0,
'no-control-regex': 0,
'no-empty': 0,
'no-loop-func': 0,
'no-nested-ternary': 0,
'no-param-reassign': 0,
'no-plusplus': 0,
'no-restricted-globals': 0,
'no-restricted-syntax': 0,
'no-shadow': 0,
'no-underscore-dangle': 0,
'no-use-before-define': 0,
'prefer-const': 0,
'prefer-destructuring': 0,
'camelcase': 0,
'no-unused-vars': 0, // in favor of '@typescript-eslint/no-unused-vars'
// 'indent': 0 // in favor of '@typescript-eslint/indent'
'@typescript-eslint/no-unused-vars': 'warn',
// '@typescript-eslint/indent': ['error', 2] // this might conflict with a lot ongoing changes
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/adjacent-overload-signatures': 'error',
'@typescript-eslint/class-name-casing': 'error',
'@typescript-eslint/interface-name-prefix': 'error',
'@typescript-eslint/no-empty-interface': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-assertion': 'error',
'@typescript-eslint/no-parameter-properties': 'error',
'@typescript-eslint/no-triple-slash-reference': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/type-annotation-spacing': 'error',
// '@typescript-eslint/array-type': 'error',
// '@typescript-eslint/ban-types': 'error',
// '@typescript-eslint/explicit-function-return-type': 'warn',
// '@typescript-eslint/explicit-member-accessibility': 'error',
// '@typescript-eslint/member-delimiter-style': 'error',
// '@typescript-eslint/no-angle-bracket-type-assertion': 'error',
// '@typescript-eslint/no-explicit-any': 'warn',
// '@typescript-eslint/no-object-literal-type-assertion': 'error',
// '@typescript-eslint/no-use-before-define': 'error',
// '@typescript-eslint/no-var-requires': 'error',
// '@typescript-eslint/prefer-interface': 'error'
}
}

View File

@@ -11,17 +11,15 @@
"directory": "packages/now-cli"
},
"scripts": {
"test": "yarn test-lint",
"preinstall": "node ./scripts/preinstall.js",
"test-unit": "nyc ava test/*unit.js --serial --fail-fast --verbose",
"test-integration": "ava test/integration.js --serial --fail-fast",
"test-integration-now-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
"test-lint": "eslint . --ext .js,.ts",
"prepublishOnly": "yarn build",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
"build": "ts-node ./scripts/build.ts",
"build-dev": "ts-node ./scripts/build.ts --dev",
"format-modified": "prettier --parser typescript --write --single-quote `git diff --name-only HEAD * | grep -e \".*\\.ts$\" -e \".*\\.js$\" | xargs echo`"
"test-lint": "eslint . --ext .ts,.js --ignore-path ../../.eslintignore"
},
"nyc": {
"include": [
@@ -42,12 +40,6 @@
"instrument": true,
"all": true
},
"git": {
"pre-commit": [
"test-lint",
"format-modified"
]
},
"bin": {
"now": "./dist/index.js"
},
@@ -106,11 +98,8 @@
"@types/universal-analytics": "0.4.2",
"@types/which": "1.3.1",
"@types/write-json-file": "2.2.1",
"@typescript-eslint/eslint-plugin": "1.6.0",
"@typescript-eslint/parser": "1.1.0",
"@zeit/dockerignore": "0.0.5",
"@zeit/fun": "0.9.1",
"@zeit/git-hooks": "0.1.4",
"@zeit/ncc": "0.18.5",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.10.2",
@@ -142,13 +131,6 @@
"email-validator": "1.1.1",
"epipebomb": "1.0.0",
"escape-html": "1.0.3",
"eslint": "5.16.0",
"eslint-config-airbnb": "17.1.0",
"eslint-config-prettier": "4.1.0",
"eslint-import-resolver-typescript": "1.1.1",
"eslint-plugin-import": "2.16.0",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.12.4",
"esm": "3.1.4",
"execa": "1.0.0",
"fetch-h2": "2.0.3",
@@ -173,7 +155,6 @@
"pcre-to-regexp": "0.0.5",
"pluralize": "7.0.0",
"pre-commit": "1.2.2",
"prettier": "1.16.2",
"printf": "0.2.5",
"progress": "2.0.3",
"promisepipe": "3.0.0",

View File

@@ -202,7 +202,6 @@ const promptForEnvFields = async (list: string[]) => {
});
}
// eslint-disable-next-line import/no-unassigned-import
require('../../util/input/patch-inquirer');
log('Please enter values for the following environment variables:');

View File

@@ -2,7 +2,6 @@ import inquirer from 'inquirer';
import stripAnsi from 'strip-ansi';
import eraseLines from '../output/erase-lines';
// eslint-disable-next-line import/no-unassigned-import
import './patch-inquirer';
function getLength(string) {

View File

@@ -1,4 +1,3 @@
/* eslint-disable import/no-unresolved */
import path from 'path';
import pkg from '../../package.json';

View File

@@ -7,9 +7,7 @@
"build": "ncc build ./src/index.ts -o ./lib --source-map",
"prepare": "npm run build",
"test-integration-once": "jest --verbose --forceExit",
"test-lint": "eslint --ext .ts ./src",
"lint": "eslint --fix --ext .ts ./src",
"lint-staged": "git diff --diff-filter=ACMRT --cached --name-only '*.ts' | xargs eslint --fix"
"test-lint": "eslint . --ext .js,.ts --ignore-path ../../.eslintignore"
},
"devDependencies": {
"@types/async-retry": "1.4.1",
@@ -19,56 +17,11 @@
"@types/node": "12.0.4",
"@types/node-fetch": "2.3.4",
"@types/recursive-readdir": "2.2.0",
"@typescript-eslint/eslint-plugin": "1.9.0",
"@typescript-eslint/parser": "1.9.0",
"@zeit/git-hooks": "0.1.4",
"@zeit/ncc": "0.18.5",
"eslint": "5.16.0",
"jest": "24.8.0",
"ts-jest": "24.0.2",
"typescript": "3.5.1"
},
"eslintConfig": {
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"env": {
"es6": true,
"node": true,
"jest": true
},
"rules": {
"func-names": [
"error",
"as-needed"
],
"no-shadow": "error",
"no-extra-semi": 0,
"react/prop-types": 0,
"react/react-in-jsx-scope": 0,
"react/no-unescaped-entities": 0,
"react/jsx-no-target-blank": 0,
"react/no-string-refs": 0,
"semi": [
"error",
"never"
],
"@typescript-eslint/indent": [
"error",
2
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-member-accessibility": "off"
}
},
"git": {
"pre-commit": "lint-staged"
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",

View File

@@ -11,7 +11,7 @@ import {
BuildOptions,
shouldServe,
Files,
debug,
debug
} from '@now/build-utils';
import { createGo, getAnalyzedEntrypoint } from './go-helpers';
@@ -38,7 +38,7 @@ async function initPrivateGit(credentials: string) {
'config',
'--global',
'credential.helper',
`store --file ${join(homedir(), '.git-credentials')}`,
`store --file ${join(homedir(), '.git-credentials')}`
]);
await writeFile(join(homedir(), '.git-credentials'), credentials);
@@ -51,7 +51,7 @@ export async function build({
entrypoint,
config,
workPath,
meta = {} as BuildParamsMeta,
meta = {} as BuildParamsMeta
}: BuildParamsType) {
if (process.env.GIT_CREDENTIALS && !meta.isDev) {
debug('Initialize Git credentials...');
@@ -73,9 +73,10 @@ Learn more: https://github.com/golang/go/wiki/Modules
debug('Downloading user files...');
const entrypointArr = entrypoint.split(sep);
// eslint-disable-next-line prefer-const
let [goPath, outDir] = await Promise.all([
getWriteableDirectory(),
getWriteableDirectory(),
getWriteableDirectory()
]);
const srcPath = join(goPath, 'src', 'lambda');
@@ -161,7 +162,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
}
const input = entrypointDirname;
var includedFiles: Files = {};
const includedFiles: Files = {};
if (config && config.includeFiles) {
for (const pattern of config.includeFiles) {
@@ -193,7 +194,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
process.platform,
process.arch,
{
cwd: entrypointDirname,
cwd: entrypointDirname
},
true
);
@@ -222,7 +223,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
const usrModName = goModContents.split('\n')[0].split(' ')[1];
if (entrypointArr.length > 1 && isGoModInRootDir) {
let cleanPackagePath = [...entrypointArr];
const cleanPackagePath = [...entrypointArr];
cleanPackagePath.pop();
goPackageName = `${usrModName}/${cleanPackagePath.join('/')}`;
} else {
@@ -276,7 +277,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
!isGoModExist
) {
await move(downloadedFiles[entrypoint].fsPath, finalDestination, {
overwrite: forceMove,
overwrite: forceMove
});
}
} catch (err) {
@@ -324,7 +325,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
const destPath = join(outDir, 'handler');
try {
let src = [join(baseGoModPath, mainModGoFileName)];
const src = [join(baseGoModPath, mainModGoFileName)];
await go.build(src, destPath, config.ldsflags);
} catch (err) {
@@ -353,7 +354,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
process.platform,
process.arch,
{
cwd: entrypointDirname,
cwd: entrypointDirname
},
false
);
@@ -389,7 +390,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
try {
const src = [
join(entrypointDirname, mainGoFileName),
downloadedFiles[entrypoint].fsPath,
downloadedFiles[entrypoint].fsPath
];
await go.build(src, destPath);
} catch (err) {
@@ -402,13 +403,13 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
files: { ...(await glob('**', outDir)), ...includedFiles },
handler: 'handler',
runtime: 'go1.x',
environment: {},
environment: {}
});
const output = {
[entrypoint]: lambda,
[entrypoint]: lambda
};
let watch = parsedAnalyzed.watch;
const watch = parsedAnalyzed.watch;
let watchSub: string[] = [];
// if `entrypoint` located in subdirectory
// we will need to concat it with return watch array
@@ -419,7 +420,7 @@ Learn more: https://zeit.co/docs/v2/advanced/builders/#go
return {
output,
watch: watch.concat(watchSub),
watch: watch.concat(watchSub)
};
}

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000);

View File

@@ -1,2 +1,4 @@
// needed for @types/JSZip since we aren't building in browser mode
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface Blob {}

View File

@@ -3,10 +3,9 @@ import {
pathExists,
readFile,
unlink as unlinkFile,
writeFile,
writeFile
} from 'fs-extra';
import os from 'os';
import zlib from 'zlib';
import path from 'path';
import semver from 'semver';
import resolveFrom from 'resolve-from';
@@ -27,8 +26,7 @@ import {
Route,
runNpmInstall,
runPackageJsonScript,
debug,
streamToBuffer,
debug
} from '@now/build-utils';
import nodeFileTrace from '@zeit/node-file-trace';
@@ -52,7 +50,7 @@ import {
validateEntrypoint,
createLambdaFromPseudoLayers,
PseudoLayer,
createPseudoLayer,
createPseudoLayer
} from './utils';
interface BuildParamsMeta {
@@ -87,7 +85,10 @@ async function readPackageJson(entryPath: string) {
/**
* Write package.json
*/
async function writePackageJson(workPath: string, packageJson: Object) {
async function writePackageJson(
workPath: string,
packageJson: Record<string, any>
) {
await writeFile(
path.join(workPath, 'package.json'),
JSON.stringify(packageJson, null, 2)
@@ -150,7 +151,7 @@ function startDevServer(entryPath: string, runtimeEnv: EnvConfig) {
// makes it default to `process.env`
const forked = fork(path.join(__dirname, 'dev-server.js'), [encodedEnv], {
cwd: entryPath,
execArgv: [],
execArgv: []
});
const getUrl = () =>
@@ -167,7 +168,7 @@ export const build = async ({
workPath,
entrypoint,
config = {} as Config,
meta = {} as BuildParamsMeta,
meta = {} as BuildParamsMeta
}: BuildParamsType): Promise<{
routes: Route[];
output: Files;
@@ -232,7 +233,7 @@ export const build = async ({
urls[entrypoint]
),
watch: pathsInside,
childProcesses: childProcess ? [childProcess] : [],
childProcesses: childProcess ? [childProcess] : []
};
}
@@ -275,7 +276,7 @@ export const build = async ({
);
pkg.scripts = {
'now-build': 'next build',
...(pkg.scripts || {}),
...(pkg.scripts || {})
};
await writePackageJson(entryPath, pkg);
}
@@ -350,14 +351,14 @@ export const build = async ({
);
const launcherFiles = {
'now__bridge.js': new FileFsRef({
fsPath: path.join(__dirname, 'now__bridge.js'),
}),
fsPath: path.join(__dirname, 'now__bridge.js')
})
};
const nextFiles: { [key: string]: FileFsRef } = {
...nodeModules,
...dotNextRootFiles,
...dotNextServerRootFiles,
...launcherFiles,
...launcherFiles
};
if (filesAfterBuild['next.config.js']) {
nextFiles['next.config.js'] = filesAfterBuild['next.config.js'];
@@ -394,7 +395,7 @@ export const build = async ({
],
[`.next/server/static/${buildId}/pages/${page}`]: filesAfterBuild[
`.next/server/static/${buildId}/pages/${page}`
],
]
};
debug(`Creating lambda for page: "${page}"...`);
@@ -402,10 +403,10 @@ export const build = async ({
files: {
...nextFiles,
...pageFiles,
'now__launcher.js': new FileBlob({ data: launcher }),
'now__launcher.js': new FileBlob({ data: launcher })
},
handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime,
runtime: nodeVersion.runtime
});
debug(`Created lambda for page: "${page}"`);
})
@@ -430,7 +431,7 @@ export const build = async ({
exportedPageRoutes.push({
src: `^${path.join('/', entryDirectory, pathname)}$`,
dest: path.join('/', staticRoute),
dest: path.join('/', staticRoute)
});
});
@@ -469,11 +470,13 @@ export const build = async ({
);
}
let assets: undefined | {
let assets:
| undefined
| {
[filePath: string]: FileFsRef;
};
const pseudoLayers: PseudoLayer[] = []
const pseudoLayers: PseudoLayer[] = [];
const tracedFiles: {
[filePath: string]: FileFsRef;
@@ -504,7 +507,7 @@ export const build = async ({
}
tracedFiles[file] = new FileFsRef({
fsPath: path.join(workPath, file),
fsPath: path.join(workPath, file)
});
});
console.timeEnd(tracingLabel);
@@ -512,8 +515,8 @@ export const build = async ({
const zippingLabel = 'Compressing shared lambda files';
console.time(zippingLabel);
pseudoLayers.push(await createPseudoLayer(tracedFiles))
console.timeEnd(zippingLabel)
pseudoLayers.push(await createPseudoLayer(tracedFiles));
console.timeEnd(zippingLabel);
} else {
// An optional assets folder that is placed alongside every page
// entrypoint.
@@ -536,8 +539,8 @@ export const build = async ({
const launcherPath = path.join(__dirname, 'templated-launcher.js');
const launcherData = await readFile(launcherPath, 'utf8');
const allLambdasLabel = `All lambdas created`
console.time(allLambdasLabel)
const allLambdasLabel = `All lambdas created`;
console.time(allLambdasLabel);
await Promise.all(
pageKeys.map(async page => {
@@ -564,20 +567,22 @@ export const build = async ({
);
const launcherFiles: { [name: string]: FileFsRef | FileBlob } = {
'now__bridge.js': new FileFsRef({
fsPath: path.join(__dirname, 'now__bridge.js'),
fsPath: path.join(__dirname, 'now__bridge.js')
}),
'now__launcher.js': new FileBlob({ data: launcher }),
'now__launcher.js': new FileBlob({ data: launcher })
};
if (requiresTracing) {
lambdas[path.join(entryDirectory, pathname)] = await createLambdaFromPseudoLayers({
lambdas[
path.join(entryDirectory, pathname)
] = await createLambdaFromPseudoLayers({
files: {
...launcherFiles,
[requiresTracing ? pageFileName : 'page.js']: pages[page],
[requiresTracing ? pageFileName : 'page.js']: pages[page]
},
layers: pseudoLayers,
handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime,
runtime: nodeVersion.runtime
});
} else {
lambdas[path.join(entryDirectory, pathname)] = await createLambda({
@@ -585,16 +590,16 @@ export const build = async ({
...launcherFiles,
...assets,
...tracedFiles,
[requiresTracing ? pageFileName : 'page.js']: pages[page],
[requiresTracing ? pageFileName : 'page.js']: pages[page]
},
handler: 'now__launcher.launcher',
runtime: nodeVersion.runtime,
runtime: nodeVersion.runtime
});
}
console.timeEnd(label);
})
);
console.timeEnd(allLambdasLabel)
console.timeEnd(allLambdasLabel);
}
const nextStaticFiles = await glob(
@@ -604,9 +609,7 @@ export const build = async ({
const staticFiles = Object.keys(nextStaticFiles).reduce(
(mappedFiles, file) => ({
...mappedFiles,
[path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[
file
],
[path.join(entryDirectory, `_next/static/${file}`)]: nextStaticFiles[file]
}),
{}
);
@@ -623,14 +626,14 @@ export const build = async ({
const publicFiles = Object.keys(publicDirectoryFiles).reduce(
(mappedFiles, file) => ({
...mappedFiles,
[file.replace(/public[/\\]+/, '')]: publicDirectoryFiles[file],
[file.replace(/public[/\\]+/, '')]: publicDirectoryFiles[file]
}),
{}
);
let dynamicPrefix = path.join('/', entryDirectory);
dynamicPrefix = dynamicPrefix === '/' ? '' : dynamicPrefix;
let dynamicRoutes = getDynamicRoutes(
const dynamicRoutes = getDynamicRoutes(
entryPath,
entryDirectory,
dynamicPages
@@ -650,7 +653,7 @@ export const build = async ({
...lambdas,
...staticPages,
...staticFiles,
...staticDirectoryFiles,
...staticDirectoryFiles
},
routes: [
// Static exported pages (.html rewrites)
@@ -663,7 +666,7 @@ export const build = async ({
// Next.js assets contain a hash or entropy in their filenames, so they
// are guaranteed to be unique and cacheable indefinitely.
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
continue: true,
continue: true
},
// Next.js page lambdas, `static/` folder, reserved assets, and `public/`
// folder
@@ -676,18 +679,18 @@ export const build = async ({
{
src: path.join('/', entryDirectory, '.*'),
dest: path.join('/', entryDirectory, '_error'),
status: 404,
},
]),
status: 404
}
])
],
watch: [],
childProcesses: [],
childProcesses: []
};
};
export const prepareCache = async ({
workPath,
entrypoint,
entrypoint
}: PrepareCacheOptions) => {
debug('preparing cache ...');
const entryDirectory = path.dirname(entrypoint);
@@ -709,7 +712,7 @@ export const prepareCache = async ({
...(await glob(path.join(cacheEntrypoint, 'node_modules/**'), workPath)),
...(await glob(path.join(cacheEntrypoint, '.next/cache/**'), workPath)),
...(await glob(path.join(cacheEntrypoint, 'package-lock.json'), workPath)),
...(await glob(path.join(cacheEntrypoint, 'yarn.lock'), workPath)),
...(await glob(path.join(cacheEntrypoint, 'yarn.lock'), workPath))
};
debug('cache file manifest produced');
return cache;

View File

@@ -1,4 +1,3 @@
/* global it, expect */
const path = require('path');
const fs = require('fs-extra');
const runBuildLambda = require('../../../../test/lib/run-build-lambda');
@@ -9,70 +8,84 @@ it(
'Should build the standard example',
async () => {
const {
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'standard'));
expect(output['index.html']).toBeDefined();
expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/));
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/));
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/));
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
);
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
'Should build the monorepo example',
async () => {
const {
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'monorepo'));
expect(output['www/index']).toBeDefined();
expect(output['www/static/test.txt']).toBeDefined();
expect(output['www/data.txt']).toBeDefined();
const filePaths = Object.keys(output);
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/));
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/));
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
'Should build the legacy standard example',
async () => {
const {
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'legacy-standard'));
expect(output.index).toBeDefined();
const filePaths = Object.keys(output);
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/));
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/));
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
'Should build the legacy custom dependency test',
async () => {
const {
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'legacy-custom-dependency'));
expect(output.index).toBeDefined();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it('Should throw when package.json or next.config.js is not the "src"', async () => {
try {
await runBuildLambda(
path.join(__dirname, 'no-package-json-and-next-config'),
path.join(__dirname, 'no-package-json-and-next-config')
);
throw new Error('did not throw');
} catch (err) {
@@ -84,33 +97,33 @@ it(
'Should build the static-files test on legacy',
async () => {
const {
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'legacy-static-files'));
expect(output['static/test.txt']).toBeDefined();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
'Should build the static-files test',
async () => {
const {
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'static-files'));
expect(output['static/test.txt']).toBeDefined();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
'Should build the public-files test',
async () => {
const {
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'public-files'));
expect(output['robots.txt']).toBeDefined();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
@@ -118,15 +131,21 @@ it(
async () => {
const {
workPath,
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'serverless-config'));
expect(output.index).toBeDefined();
expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/));
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/));
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/));
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
);
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy();
@@ -135,10 +154,10 @@ it(
expect(contents.some(name => name === 'next.config.js')).toBeTruthy();
expect(
contents.some(name => name.includes('next.config.original.')),
contents.some(name => name.includes('next.config.original.'))
).toBeTruthy();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
@@ -154,7 +173,7 @@ it(
expect(error).not.toBe(null);
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
@@ -170,7 +189,7 @@ it(
expect(error).not.toBe(null);
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
@@ -178,15 +197,21 @@ it(
async () => {
const {
workPath,
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'serverless-config-object'));
expect(output['index.html']).toBeDefined();
expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/));
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/));
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/));
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
);
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy();
@@ -195,10 +220,10 @@ it(
expect(contents.some(name => name === 'next.config.js')).toBeTruthy();
expect(
contents.some(name => name.includes('next.config.original.')),
contents.some(name => name.includes('next.config.original.'))
).toBeTruthy();
},
FOUR_MINUTES,
FOUR_MINUTES
);
it(
@@ -206,15 +231,21 @@ it(
async () => {
const {
workPath,
buildResult: { output },
buildResult: { output }
} = await runBuildLambda(path.join(__dirname, 'serverless-no-config'));
expect(output['index.html']).toBeDefined();
expect(output.goodbye).toBeDefined();
const filePaths = Object.keys(output);
const serverlessError = filePaths.some(filePath => filePath.match(/_error/));
const hasUnderScoreAppStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_app\.js$/));
const hasUnderScoreErrorStaticFile = filePaths.some(filePath => filePath.match(/static.*\/pages\/_error\.js$/));
const serverlessError = filePaths.some(filePath =>
filePath.match(/_error/)
);
const hasUnderScoreAppStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_app\.js$/)
);
const hasUnderScoreErrorStaticFile = filePaths.some(filePath =>
filePath.match(/static.*\/pages\/_error\.js$/)
);
expect(hasUnderScoreAppStaticFile).toBeTruthy();
expect(hasUnderScoreErrorStaticFile).toBeTruthy();
expect(serverlessError).toBeTruthy();
@@ -223,8 +254,8 @@ it(
expect(contents.some(name => name === 'next.config.js')).toBeTruthy();
expect(
contents.some(name => name.includes('next.config.original.')),
contents.some(name => name.includes('next.config.original.'))
).toBeFalsy();
},
FOUR_MINUTES,
FOUR_MINUTES
);

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000);
@@ -26,8 +25,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}

View File

@@ -1,4 +1,3 @@
/* global expect, it, jest */
const path = require('path');
const os = require('os');
const { build } = require('@now/next');
@@ -14,40 +13,40 @@ describe('build meta dev', () => {
module.exports = {
target: 'serverless'
}
`,
`
}),
'pages/index.js': new FileBlob({
mode: 0o777,
data: `
export default () => 'Index page'
`,
`
}),
'pages/nested/[param].js': new FileBlob({
mode: 0o777,
data: `
export default () => 'Dynamic page'
`,
`
}),
'pages/nested/page.tsx': new FileBlob({
mode: 0o777,
data: `
export default () => 'Nested page'
`,
`
}),
'pages/api/test.js': new FileBlob({
mode: 0o777,
data: `
export default (req, res) => res.status(200).end('API Route')
`,
`
}),
// This file should be omitted because `pages/index.js` will use the same route
'public/index': new FileBlob({
mode: 0o777,
data: 'text',
data: 'text'
}),
'public/data.txt': new FileBlob({
mode: 0o777,
data: 'data',
data: 'data'
}),
'package.json': new FileBlob({
mode: 0o777,
@@ -67,15 +66,15 @@ describe('build meta dev', () => {
"typescript": "3"
}
}
`,
}),
`
})
};
const entrypoint = 'next.config.js';
const workPath = path.join(
os.tmpdir(),
Math.random()
.toString()
.slice(3),
.slice(3)
);
console.log('workPath directory: ', workPath);
@@ -85,15 +84,13 @@ describe('build meta dev', () => {
await download(files, workPath);
const meta = { isDev: true, requestPath: null };
const {
output, routes, watch, childProcesses,
} = await build({
const { output, routes, watch, childProcesses } = await build({
files,
workPath,
entrypoint,
meta,
meta
});
routes.forEach((route) => {
routes.forEach(route => {
// eslint-disable-next-line no-param-reassign
route.dest = route.dest.replace(':4000', ':5000');
});
@@ -107,9 +104,9 @@ describe('build meta dev', () => {
{ src: '/api/test', dest: 'http://localhost:5000/api/test' },
{
src: '^/(nested\\/([^\\/]+?)(?:\\/)?)$',
dest: 'http://localhost:5000/$1',
dest: 'http://localhost:5000/$1'
},
{ src: '/data.txt', dest: 'http://localhost:5000/data.txt' },
{ src: '/data.txt', dest: 'http://localhost:5000/data.txt' }
]);
expect(watch).toEqual([
'next.config.js',
@@ -119,7 +116,7 @@ describe('build meta dev', () => {
'pages/api/test.js',
'public/index',
'public/data.txt',
'package.json',
'package.json'
]);
childProcesses.forEach(cp => cp.kill());
});

View File

@@ -4,9 +4,9 @@ const {
validateEntrypoint,
includeOnlyEntryDirectory,
normalizePackageJson,
getNextConfig,
getNextConfig
} = require('@now/next/dist/utils');
const { FileRef } = require('@now/build-utils'); // eslint-disable-line import/no-extraneous-dependencies
const { FileRef } = require('@now/build-utils');
describe('getNextConfig', () => {
const workPath = path.join(__dirname, 'fixtures');
@@ -33,11 +33,11 @@ describe('excludeFiles', () => {
const files = {
'pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
'package-lock.json': new FileRef({ digest: 'package-lock' })
};
const result = excludeFiles(
files,
filePath => filePath === 'package-lock.json',
filePath => filePath === 'package-lock.json'
);
expect(result['pages/index.js']).toBeDefined();
expect(result['package.json']).toBeDefined();
@@ -69,7 +69,7 @@ describe('includeOnlyEntryDirectory', () => {
const files = {
'frontend/pages/index.js': new FileRef({ digest: 'index' }),
'package.json': new FileRef({ digest: 'package' }),
'package-lock.json': new FileRef({ digest: 'package-lock' }),
'package-lock.json': new FileRef({ digest: 'package-lock' })
};
const result = includeOnlyEntryDirectory(files, entryDirectory);
expect(result['frontend/pages/index.js']).toBeDefined();
@@ -85,15 +85,15 @@ describe('normalizePackageJson', () => {
dependencies: {
'next-server': 'v7.0.2-canary.49',
react: 'latest',
'react-dom': 'latest',
'react-dom': 'latest'
},
devDependencies: {
next: 'v7.0.2-canary.49',
next: 'v7.0.2-canary.49'
},
scripts: {
'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
},
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}
});
});
@@ -102,29 +102,29 @@ describe('normalizePackageJson', () => {
dependencies: {
'next-server': 'v7.0.2-canary.49',
react: 'latest',
'react-dom': 'latest',
'react-dom': 'latest'
},
devDependencies: {
next: 'v7.0.2-canary.49',
next: 'v7.0.2-canary.49'
},
scripts: {
'now-build': 'next build',
},
'now-build': 'next build'
}
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'v7.0.2-canary.49',
react: 'latest',
'react-dom': 'latest',
'react-dom': 'latest'
},
devDependencies: {
next: 'v7.0.2-canary.49',
next: 'v7.0.2-canary.49'
},
scripts: {
'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
},
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}
});
});
@@ -133,23 +133,23 @@ describe('normalizePackageJson', () => {
dependencies: {
react: 'latest',
'react-dom': 'latest',
next: 'latest',
},
next: 'latest'
}
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'v7.0.2-canary.49',
react: 'latest',
'react-dom': 'latest',
'react-dom': 'latest'
},
devDependencies: {
next: 'v7.0.2-canary.49',
next: 'v7.0.2-canary.49'
},
scripts: {
'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
},
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}
});
});
@@ -158,23 +158,23 @@ describe('normalizePackageJson', () => {
dependencies: {
react: 'latest',
'react-dom': 'latest',
next: 'latest',
},
next: 'latest'
}
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'v7.0.2-canary.49',
react: 'latest',
'react-dom': 'latest',
'react-dom': 'latest'
},
devDependencies: {
next: 'v7.0.2-canary.49',
next: 'v7.0.2-canary.49'
},
scripts: {
'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
},
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}
});
});
@@ -183,23 +183,23 @@ describe('normalizePackageJson', () => {
dependencies: {
react: 'latest',
'react-dom': 'latest',
next: 'latest',
},
next: 'latest'
}
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
dependencies: {
'next-server': 'v7.0.2-canary.49',
react: 'latest',
'react-dom': 'latest',
'react-dom': 'latest'
},
devDependencies: {
next: 'v7.0.2-canary.49',
next: 'v7.0.2-canary.49'
},
scripts: {
'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
},
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas'
}
});
});
@@ -211,7 +211,7 @@ describe('normalizePackageJson', () => {
dev: 'next',
build: 'next build',
start: 'next start',
test: "xo && stylelint './pages/**/*.js' && jest",
test: "xo && stylelint './pages/**/*.js' && jest"
},
main: 'pages/index.js',
license: 'MIT',
@@ -226,7 +226,7 @@ describe('normalizePackageJson', () => {
'stylelint-config-recommended': '^2.1.0',
'stylelint-config-styled-components': '^0.1.1',
'stylelint-processor-styled-components': '^1.5.1',
xo: '^0.23.0',
xo: '^0.23.0'
},
dependencies: {
consola: '^2.2.6',
@@ -234,7 +234,7 @@ describe('normalizePackageJson', () => {
next: '^7.0.2',
react: '^16.6.3',
'react-dom': '^16.6.3',
'styled-components': '^4.1.1',
'styled-components': '^4.1.1'
},
xo: {
extends: 'xo-react',
@@ -244,15 +244,15 @@ describe('normalizePackageJson', () => {
'test',
'pages/_document.js',
'pages/index.js',
'pages/home.js',
'pages/home.js'
],
rules: {
'react/no-unescaped-entities': null,
},
'react/no-unescaped-entities': null
}
},
jest: {
testEnvironment: 'node',
},
testEnvironment: 'node'
}
};
const result = normalizePackageJson(defaultPackage);
expect(result).toEqual({
@@ -263,7 +263,7 @@ describe('normalizePackageJson', () => {
'now-build':
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
start: 'next start',
test: "xo && stylelint './pages/**/*.js' && jest",
test: "xo && stylelint './pages/**/*.js' && jest"
},
main: 'pages/index.js',
license: 'MIT',
@@ -283,12 +283,12 @@ describe('normalizePackageJson', () => {
xo: '^0.23.0',
consola: '^2.2.6',
fontfaceobserver: '^2.0.13',
'styled-components': '^4.1.1',
'styled-components': '^4.1.1'
},
dependencies: {
'next-server': 'v7.0.2-canary.49',
react: '^16.6.3',
'react-dom': '^16.6.3',
'react-dom': '^16.6.3'
},
xo: {
extends: 'xo-react',
@@ -298,15 +298,15 @@ describe('normalizePackageJson', () => {
'test',
'pages/_document.js',
'pages/index.js',
'pages/home.js',
'pages/home.js'
],
rules: {
'react/no-unescaped-entities': null,
},
'react/no-unescaped-entities': null
}
},
jest: {
testEnvironment: 'node',
},
testEnvironment: 'node'
}
});
});
});

View File

@@ -1,24 +0,0 @@
{
"extends": ["prettier", "airbnb-base"],
"rules": {
"no-console": 0,
"import/no-unresolved": 0,
"import/no-dynamic-require": 0,
"global-require": 0
},
"overrides": [
{
"files": ["test/**"],
"rules": {
"import/no-extraneous-dependencies": 0
},
"globals": {
"describe": true,
"it": true,
"test": true,
"expect": true
}
}
]
}

View File

@@ -5,7 +5,7 @@ import {
Server,
IncomingHttpHeaders,
OutgoingHttpHeaders,
request,
request
} from 'http';
interface NowProxyEvent {
@@ -107,10 +107,10 @@ export class Bridge {
private listening: Promise<AddressInfo>;
private resolveListening: (info: AddressInfo) => void;
private events: { [key: string]: NowProxyRequest } = {};
private reqIdSeed: number = 1;
private shouldStoreEvents: boolean = false;
private reqIdSeed = 1;
private shouldStoreEvents = false;
constructor(server?: ServerLike, shouldStoreEvents: boolean = false) {
constructor(server?: ServerLike, shouldStoreEvents = false) {
this.server = null;
this.shouldStoreEvents = shouldStoreEvents;
if (server) {
@@ -141,7 +141,7 @@ export class Bridge {
return this.server.listen(
{
host: '127.0.0.1',
port: 0,
port: 0
},
function listeningCallback() {
if (!this || typeof this.address !== 'function') {
@@ -206,7 +206,7 @@ export class Bridge {
statusCode: response.statusCode || 200,
headers: response.headers,
body: bodyBuffer.toString('base64'),
encoding: 'base64',
encoding: 'base64'
});
});
});

View File

@@ -1,4 +1,6 @@
// We intentionally import these types here
// which will fail at compile time if exports
// are not found in the index file
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { NowRequest, NowResponse } from './index';

View File

@@ -17,7 +17,7 @@ import {
BuildOptions,
shouldServe,
Config,
debug,
debug
} from '@now/build-utils';
export { NowRequest, NowResponse } from './types';
import { makeLauncher } from './launcher';
@@ -57,7 +57,7 @@ async function downloadInstallAndBundle({
entrypoint,
workPath,
config,
meta,
meta
}: DownloadOptions) {
debug('downloading user files...');
const downloadTime = Date.now();
@@ -94,7 +94,7 @@ async function compile(
const sourceCache = new Map<string, string | Buffer | null>();
const fsCache = new Map<string, File>();
const tsCompiled = new Set<String>();
const tsCompiled = new Set<string>();
let shouldAddSourcemapSupport = false;
@@ -141,7 +141,7 @@ async function compile(
tsCompile = register({
basePath: workPath, // The base is the same as root now.json dir
project: path, // Resolve tsconfig.json from entrypoint dir
files: true, // Include all files such as global `.d.ts`
files: true // Include all files such as global `.d.ts`
});
}
const { code, map } = tsCompile(source, path);
@@ -149,7 +149,7 @@ async function compile(
preparedFiles[
relPath.slice(0, -3 - Number(path.endsWith('x'))) + '.js.map'
] = new FileBlob({
data: JSON.stringify(map),
data: JSON.stringify(map)
});
source = code;
shouldAddSourcemapSupport = true;
@@ -189,7 +189,7 @@ async function compile(
}
throw e;
}
},
}
});
debug('traced files:');
@@ -252,17 +252,17 @@ async function compile(
const filename = basename(path);
const { data: source } = await FileBlob.fromStream({
stream: preparedFiles[path].toStream(),
stream: preparedFiles[path].toStream()
});
const { code, map } = babelCompile(filename, source);
shouldAddSourcemapSupport = true;
preparedFiles[path] = new FileBlob({
data: `${code}\n//# sourceMappingURL=${filename}.map`,
data: `${code}\n//# sourceMappingURL=${filename}.map`
});
delete map.sourcesContent;
preparedFiles[path + '.map'] = new FileBlob({
data: JSON.stringify(map),
data: JSON.stringify(map)
});
}
}
@@ -270,7 +270,7 @@ async function compile(
return {
preparedFiles,
shouldAddSourcemapSupport,
watch: fileList,
watch: fileList
};
}
@@ -281,7 +281,7 @@ export async function build({
entrypoint,
workPath,
config = {},
meta = {},
meta = {}
}: BuildOptions) {
const shouldAddHelpers = config.helpers !== false;
@@ -289,13 +289,13 @@ export async function build({
entrypointPath,
entrypointFsDirname,
nodeVersion,
spawnOpts,
spawnOpts
} = await downloadInstallAndBundle({
files,
entrypoint,
workPath,
config,
meta,
meta
});
debug('running user script...');
@@ -321,23 +321,23 @@ export async function build({
helpersPath: `./${HELPERS_FILENAME}`,
sourcemapSupportPath: `./${SOURCEMAP_SUPPORT_FILENAME}`,
shouldAddHelpers,
shouldAddSourcemapSupport,
}),
shouldAddSourcemapSupport
})
}),
[`${BRIDGE_FILENAME}.js`]: new FileFsRef({
fsPath: join(__dirname, 'bridge.js'),
}),
fsPath: join(__dirname, 'bridge.js')
})
};
if (shouldAddSourcemapSupport) {
launcherFiles[`${SOURCEMAP_SUPPORT_FILENAME}.js`] = new FileFsRef({
fsPath: join(__dirname, 'source-map-support.js'),
fsPath: join(__dirname, 'source-map-support.js')
});
}
if (shouldAddHelpers) {
launcherFiles[`${HELPERS_FILENAME}.js`] = new FileFsRef({
fsPath: join(__dirname, 'helpers.js'),
fsPath: join(__dirname, 'helpers.js')
});
}
@@ -350,10 +350,10 @@ export async function build({
const lambda = await createLambda({
files: {
...preparedFiles,
...(awsLambdaHandler ? {} : launcherFiles),
...(awsLambdaHandler ? {} : launcherFiles)
},
handler: awsLambdaHandler || `${LAUNCHER_FILENAME}.launcher`,
runtime,
runtime
});
const output = { [entrypoint]: lambda };
@@ -365,7 +365,7 @@ export async function prepareCache({ workPath }: PrepareCacheOptions) {
return {
...(await glob('node_modules/**', workPath)),
...(await glob('package-lock.json', workPath)),
...(await glob('yarn.lock', workPath)),
...(await glob('yarn.lock', workPath))
};
}

View File

@@ -87,7 +87,7 @@ const DEFAULTS: Options = {
ignore: undefined,
project: undefined,
ignoreDiagnostics: undefined,
logError: null,
logError: null
};
/**
@@ -99,7 +99,7 @@ const TS_NODE_COMPILER_OPTIONS = {
inlineSources: true,
declaration: false,
noEmit: false,
outDir: '$$ts-node$$',
outDir: '$$ts-node$$'
};
/**
@@ -143,15 +143,16 @@ export function register(opts: Options = {}): Register {
6059, // "'rootDir' is expected to contain all source files."
18002, // "The 'files' list in config file is empty."
18003, // "No inputs were found in config file."
...(options.ignoreDiagnostics || []),
...(options.ignoreDiagnostics || [])
].map(Number);
// Require the TypeScript compiler and configuration.
const cwd = options.basePath || process.cwd();
const nowNodeBase = resolve(__dirname, '..', '..', '..');
try {
var compiler = require.resolve(options.compiler || 'typescript', {
paths: [cwd, nowNodeBase],
paths: [cwd, nowNodeBase]
});
} catch (e) {
compiler = require.resolve(eval('"./typescript"'));
@@ -174,7 +175,7 @@ export function register(opts: Options = {}): Register {
const diagnosticHost: _ts.FormatDiagnosticsHost = {
getNewLine: () => ts.sys.newLine,
getCurrentDirectory: () => cwd,
getCanonicalFileName: path => path,
getCanonicalFileName: path => path
};
function createTSError(diagnostics: ReadonlyArray<_ts.Diagnostic>) {
@@ -199,7 +200,7 @@ export function register(opts: Options = {}): Register {
// we create a custom build per tsconfig.json instance
const builds = new Map<string, Build>();
function getBuild(configFileName: string = ''): Build {
function getBuild(configFileName = ''): Build {
let build = builds.get(configFileName);
if (build) return build;
@@ -208,12 +209,12 @@ export function register(opts: Options = {}): Register {
/**
* Create the basic required function using transpile mode.
*/
let getOutput = function(code: string, fileName: string): SourceOutput {
const getOutput = function(code: string, fileName: string): SourceOutput {
const result = ts.transpileModule(code, {
fileName,
transformers,
compilerOptions: config.options,
reportDiagnostics: true,
reportDiagnostics: true
});
const diagnosticList = result.diagnostics
@@ -268,7 +269,7 @@ export function register(opts: Options = {}): Register {
getCurrentDirectory: () => cwd,
getCompilationSettings: () => config.options,
getDefaultLibFileName: () => ts.getDefaultLibFilePath(config.options),
getCustomTransformers: () => transformers,
getCustomTransformers: () => transformers
};
const registry = ts.createDocumentRegistry(
@@ -322,7 +323,7 @@ export function register(opts: Options = {}): Register {
return {
code: output.outputFiles[1].text,
map: output.outputFiles[0].text,
map: output.outputFiles[0].text
};
};
}
@@ -331,15 +332,14 @@ export function register(opts: Options = {}): Register {
configFileName,
(build = {
getOutput,
getOutputTypeCheck,
getOutputTypeCheck
})
);
return build;
}
// determine the tsconfig.json path for a given folder
function detectConfig(basePath: string): string | undefined {
basePath = normalizeSlashes(basePath);
function detectConfig(): string | undefined {
let configFileName: string | undefined = undefined;
// Read project configuration when available.
@@ -355,7 +355,7 @@ export function register(opts: Options = {}): Register {
*/
function readConfig(configFileName: string): _ts.ParsedCommandLine {
let config: any = { compilerOptions: {} };
let basePath = normalizeSlashes(dirname(configFileName));
const basePath = normalizeSlashes(dirname(configFileName));
// Read project configuration when available.
if (configFileName) {
@@ -366,7 +366,7 @@ export function register(opts: Options = {}): Register {
const errorResult = {
errors: [result.error],
fileNames: [],
options: {},
options: {}
};
const configDiagnosticList = filterDiagnostics(
errorResult.errors,
@@ -423,7 +423,7 @@ export function register(opts: Options = {}): Register {
fileName: string,
skipTypeCheck?: boolean
): SourceOutput {
const configFileName = detectConfig(fileName);
const configFileName = detectConfig();
const build = getBuild(configFileName);
const { code: value, map: sourceMap } = (skipTypeCheck
? build.getOutput
@@ -432,8 +432,8 @@ export function register(opts: Options = {}): Register {
code: value,
map: Object.assign(JSON.parse(sourceMap), {
file: basename(fileName),
sources: [fileName],
}),
sources: [fileName]
})
};
delete output.map.sourceRoot;
return output;

View File

@@ -1,4 +1,3 @@
/* global beforeEach, afterEach, expect, it, jest */
const fetch = require('node-fetch');
const listen = require('test-listen');
const qs = require('querystring');
@@ -22,7 +21,7 @@ async function fetchWithProxyReq(_url, opts = {}) {
return fetch(_url, {
...opts,
headers: { ...opts.headers, 'x-now-bridge-request-id': '2' },
headers: { ...opts.headers, 'x-now-bridge-request-id': '2' }
});
}
@@ -67,7 +66,7 @@ describe('all helpers', () => {
['body', 0],
['status', 1],
['send', 1],
['json', 1],
['json', 1]
];
test('should not recalculate req properties twice', async () => {
@@ -84,7 +83,7 @@ describe('all helpers', () => {
await fetchWithProxyReq(`${url}/?who=bill`, {
method: 'POST',
body: JSON.stringify({ who: 'mike' }),
headers: { 'content-type': 'application/json', cookie: 'who=jim' },
headers: { 'content-type': 'application/json', cookie: 'who=jim' }
});
// here we test that bodySpy is called twice with exactly the same arguments
@@ -138,7 +137,7 @@ describe('req.query', () => {
expect(mockListener.mock.calls[0][0].query).toMatchObject({
who: 'bill',
where: 'us',
where: 'us'
});
});
@@ -153,13 +152,13 @@ describe('req.cookies', () => {
test('req.cookies should reflect req.cookie header', async () => {
await fetchWithProxyReq(url, {
headers: {
cookie: 'who=bill; where=us',
},
cookie: 'who=bill; where=us'
}
});
expect(mockListener.mock.calls[0][0].cookies).toMatchObject({
who: 'bill',
where: 'us',
where: 'us'
});
});
});
@@ -173,7 +172,7 @@ describe('req.body', () => {
test('req.body should be undefined if content-type is not defined', async () => {
await fetchWithProxyReq(url, {
method: 'POST',
body: 'hello',
body: 'hello'
});
expect(mockListener.mock.calls[0][0].body).toBe(undefined);
});
@@ -182,7 +181,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, {
method: 'POST',
body: 'hello',
headers: { 'content-type': 'text/plain' },
headers: { 'content-type': 'text/plain' }
});
expect(mockListener.mock.calls[0][0].body).toBe('hello');
@@ -192,7 +191,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, {
method: 'POST',
body: 'hello',
headers: { 'content-type': 'application/octet-stream' },
headers: { 'content-type': 'application/octet-stream' }
});
const [{ body }] = mockListener.mock.calls[0];
@@ -209,7 +208,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, {
method: 'POST',
body: qs.encode(obj),
headers: { 'content-type': 'application/x-www-form-urlencoded' },
headers: { 'content-type': 'application/x-www-form-urlencoded' }
});
expect(mockListener.mock.calls[0][0].body).toMatchObject(obj);
@@ -218,13 +217,13 @@ describe('req.body', () => {
test('req.body should be an object when content-type is `application/json`', async () => {
const json = {
who: 'bill',
where: 'us',
where: 'us'
};
await fetchWithProxyReq(url, {
method: 'POST',
body: JSON.stringify(json),
headers: { 'content-type': 'application/json' },
headers: { 'content-type': 'application/json' }
});
expect(mockListener.mock.calls[0][0].body).toMatchObject(json);
@@ -239,7 +238,7 @@ describe('req.body', () => {
const res = await fetchWithProxyReq(url, {
method: 'POST',
body: '',
headers: { 'content-type': 'application/json' },
headers: { 'content-type': 'application/json' }
});
expect(res.status).toBe(400);
@@ -261,7 +260,7 @@ describe('req.body', () => {
await fetchWithProxyReq(url, {
method: 'POST',
body: '{"wrong":"json"',
headers: { 'content-type': 'application/json' },
headers: { 'content-type': 'application/json' }
});
expect(bodySpy).toHaveBeenCalled();

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000);
@@ -29,7 +28,7 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
try {
await testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
path.join(fixturesPath, fixture)
);
} catch (err) {
expect(err.message).toMatch(/is ERROR/);
@@ -43,8 +42,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000);
@@ -26,8 +25,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}

View File

@@ -25,7 +25,7 @@ export type Handler = {
export type Route = Source | Handler;
export function isHandler(route: Route): route is Handler {
return typeof (<Handler>route).handle !== 'undefined';
return typeof (route as Handler).handle !== 'undefined';
}
export function normalizeRoutes(
@@ -47,24 +47,20 @@ export function normalizeRoutes(
// typeof { handle: string }
if (Object.keys(route).length !== 1) {
errors.push({
message: `Cannot have any other keys when handle is used (handle: ${
route.handle
})`,
handle: route.handle,
message: `Cannot have any other keys when handle is used (handle: ${route.handle})`,
handle: route.handle
});
}
if (!['filesystem'].includes(route.handle)) {
errors.push({
message: `This is not a valid handler (handle: ${route.handle})`,
handle: route.handle,
handle: route.handle
});
}
if (handling.includes(route.handle)) {
errors.push({
message: `You can only handle something once (handle: ${
route.handle
})`,
handle: route.handle,
message: `You can only handle something once (handle: ${route.handle})`,
handle: route.handle
});
} else {
handling.push(route.handle);
@@ -86,12 +82,12 @@ export function normalizeRoutes(
} catch (err) {
errors.push({
message: `Invalid regular expression: "${route.src}"`,
src: route.src,
src: route.src
});
}
} else {
errors.push({
message: 'A route must set either handle or src',
message: 'A route must set either handle or src'
});
}
}
@@ -105,7 +101,7 @@ export function normalizeRoutes(
null,
2
)}`,
errors,
errors
}
: null;
@@ -124,19 +120,19 @@ export const schema = {
properties: {
src: {
type: 'string',
maxLength: 4096,
maxLength: 4096
},
dest: {
type: 'string',
maxLength: 4096,
maxLength: 4096
},
methods: {
type: 'array',
maxItems: 10,
items: {
type: 'string',
maxLength: 32,
},
maxLength: 32
}
},
headers: {
type: 'object',
@@ -146,22 +142,22 @@ export const schema = {
patternProperties: {
'^.{1,256}$': {
type: 'string',
maxLength: 4096,
},
},
maxLength: 4096
}
}
},
handle: {
type: 'string',
maxLength: 32,
maxLength: 32
},
continue: {
type: 'boolean',
type: 'boolean'
},
status: {
type: 'integer',
minimum: 100,
maximum: 999,
},
},
},
maximum: 999
}
}
}
};

View File

@@ -6,7 +6,7 @@ import {
remove,
pathExists,
readFile,
writeFile,
writeFile
} from 'fs-extra';
import {
download,
@@ -14,7 +14,7 @@ import {
glob,
createLambda,
BuildOptions,
debug,
debug
} from '@now/build-utils';
import { installBundler } from './install-ruby';
@@ -58,15 +58,15 @@ async function bundleInstall(
'--gemfile',
gemfilePath,
'--path',
bundleDir,
bundleDir
],
{
stdio: 'pipe',
env: {
BUNDLE_SILENCE_ROOT_WARNING: '1',
BUNDLE_APP_CONFIG: bundleAppConfig,
BUNDLE_JOBS: '4',
},
BUNDLE_JOBS: '4'
}
}
);
} catch (err) {
@@ -79,12 +79,11 @@ export const build = async ({
workPath,
files,
entrypoint,
config,
config
}: BuildOptions) => {
debug('downloading files...');
// eslint-disable-next-line no-param-reassign
files = await download(files, workPath);
await download(files, workPath);
const { gemHome, bundlerPath } = await installBundler();
process.env.GEM_HOME = gemHome;
@@ -102,9 +101,9 @@ export const build = async ({
const bundleDir = join(workPath, 'vendor/bundle');
const relativeVendorDir = join(fsEntryDirectory, REQUIRED_VENDOR_DIR);
let hasRootVendorDir = await pathExists(vendorDir);
let hasRelativeVendorDir = await pathExists(relativeVendorDir);
let hasVendorDir = hasRootVendorDir || hasRelativeVendorDir;
const hasRootVendorDir = await pathExists(vendorDir);
const hasRelativeVendorDir = await pathExists(relativeVendorDir);
const hasVendorDir = hasRootVendorDir || hasRelativeVendorDir;
if (hasRelativeVendorDir) {
if (hasRootVendorDir) {
@@ -151,7 +150,9 @@ export const build = async ({
// try to remove gem cache to slim bundle size
try {
await remove(join(vendorDir, 'cache'));
} catch (e) {}
} catch (e) {
// don't do anything here
}
const originalRbPath = join(__dirname, '..', 'now_init.rb');
const originalNowHandlerRbContents = await readFile(originalRbPath, 'utf8');
@@ -209,10 +210,10 @@ export const build = async ({
files: outputFiles,
handler: `${nowHandlerRbFilename}.now__handler`,
runtime: 'ruby2.5',
environment: {},
environment: {}
});
return {
[entrypoint]: lambda,
[entrypoint]: lambda
};
};

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(5 * 60 * 1000);
@@ -26,8 +25,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}

View File

@@ -1,10 +1,9 @@
/* global beforeAll, expect, it, jest */
const fs = require('fs');
const path = require('path');
const {
packAndDeploy,
testDeployment,
testDeployment
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(12 * 60 * 1000);
@@ -22,7 +21,7 @@ const testsThatFailToBuild = new Set([
'04-wrong-dist-dir',
'05-empty-dist-dir',
'06-missing-script',
'07-nonzero-sh',
'07-nonzero-sh'
]);
// eslint-disable-next-line no-restricted-syntax
@@ -33,7 +32,7 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
try {
await testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
path.join(fixturesPath, fixture)
);
} catch (err) {
expect(err.message).toMatch(/is ERROR/);
@@ -47,8 +46,8 @@ for (const fixture of fs.readdirSync(fixturesPath)) {
await expect(
testDeployment(
{ builderUrl, buildUtilsUrl },
path.join(fixturesPath, fixture),
),
path.join(fixturesPath, fixture)
)
).resolves.toBeDefined();
});
}

2
run.js
View File

@@ -55,7 +55,7 @@ async function main() {
console.log(matches.join('\n') + '\n');
for (let pkgName of matches) {
for (const pkgName of matches) {
await runScript(pkgName, script);
}
}

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const airtable = require('airtable');
module.exports = (req, res) => {

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const aws = require('aws-sdk');
module.exports = (req, res) => {

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const axios = require('axios');
module.exports = (req, res) => {

View File

@@ -1,4 +1,3 @@
/* global it, expect */
const path = require('path');
const runBuildLambda = require('../../lib/run-build-lambda');
@@ -14,7 +13,7 @@ it(
const { buildResult } = await runBuildForFolder('airtable');
expect(buildResult.output['index.js']).toBeDefined();
},
TWO_MINUTES,
TWO_MINUTES
);
it(
@@ -23,7 +22,7 @@ it(
const { buildResult } = await runBuildForFolder('aws-sdk');
expect(buildResult.output['index.js']).toBeDefined();
},
TWO_MINUTES,
TWO_MINUTES
);
it(
@@ -32,7 +31,7 @@ it(
const { buildResult } = await runBuildForFolder('axios');
expect(buildResult.output['index.js']).toBeDefined();
},
TWO_MINUTES,
TWO_MINUTES
);
it(
@@ -41,5 +40,5 @@ it(
const { buildResult } = await runBuildForFolder('mongoose');
expect(buildResult.output['index.js']).toBeDefined();
},
TWO_MINUTES,
TWO_MINUTES
);

View File

@@ -1,4 +1,4 @@
// eslint-disable-next-line no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const mongoose = require('mongoose');
module.exports = (req, res) => {

View File

@@ -1,4 +1,3 @@
/* global expect */
const getWritableDirectory = require('../../packages/now-build-utils/fs/get-writable-directory.js');
const glob = require('../../packages/now-build-utils/fs/glob.js');
@@ -20,13 +19,14 @@ async function runBuildLambda(inputPath) {
expect(build.src.includes('*')).toBeFalsy();
const entrypoint = build.src.replace(/^\//, ''); // strip leftmost slash
expect(inputFiles[entrypoint]).toBeDefined();
inputFiles[entrypoint].digest = 'this-is-a-fake-digest-for-non-default-analyze';
inputFiles[entrypoint].digest =
'this-is-a-fake-digest-for-non-default-analyze';
const wrapper = require(build.use);
const analyzeResult = runAnalyze(wrapper, {
files: inputFiles,
entrypoint,
config: build.config,
config: build.config
});
const workPath = await getWritableDirectory();
@@ -34,7 +34,7 @@ async function runBuildLambda(inputPath) {
files: inputFiles,
entrypoint,
config: build.config,
workPath,
workPath
});
const { output } = buildResult;
@@ -43,16 +43,16 @@ async function runBuildLambda(inputPath) {
buildResult.output = Object.keys(output).reduce(
(result, path) => ({
...result,
[path.replace(/\\/g, '/')]: output[path],
[path.replace(/\\/g, '/')]: output[path]
}),
{},
{}
);
}
return {
analyzeResult,
buildResult,
workPath,
workPath
};
}

808
yarn.lock

File diff suppressed because it is too large Load Diff