Compare commits

..

30 Commits

Author SHA1 Message Date
luc
53eb71f26d Publish Stable
- now@17.0.2
 - @now/routing-utils@1.5.3
2020-02-06 19:18:35 +01:00
luc
92ffd654b5 Publish Canary
- now@17.0.2-canary.1
2020-02-06 18:53:36 +01:00
Luc
36b83f1606 [now-cli] Use npx or yarn to execute dev command (#3760)
1. Use bundled yarn to run `yarn bin`
2. Skip `yarn bin` if `npx` is used
2020-02-06 17:47:39 +00:00
Steven
7a79f620c0 [tests] Fix changelog script (#3751)
Previously, the changelog script was looking for the last "Publish Stable" commit, but it should really be looking for the last Stable release of Now CLI.

This PR updates the changelog script so that it fetches the latest GH Release (which should be Now CLI) and then compares that to the HEAD.
2020-02-06 14:35:15 +00:00
Steven
f3b286ecf3 Publish Canary
- now@17.0.2-canary.0
 - @now/routing-utils@1.5.3-canary.0
2020-02-06 09:12:19 -05:00
Steven
adf31c3fcc [now-routing-utils] Change behavior of trailingSlash: true redirects (#3745)
This PR changes the behavior of `trailingSlash: true` after we received feedback that files should not be redirected with a trailing slash. This matches the behavior of `serve` and `serve-handler`.

### Examples 
* `/index.html` => serve
* `/assets/style.css` => serve
* `/assets` => redirect to `/assets/`
* `/assets/style` => redirect to `/assets/style/` 

### Additional

In order to avoid duplicate content, this PR also adds redirects to files without a trailing slash.

* `/about.html/` => redirect to `/about.html`
* `/assets/style.css/` => redirect to `/assets/style.css`


Fixes #3731
2020-02-06 09:07:46 -05:00
luc
deacdfc47c Publish Stable
- now@17.0.1
2020-02-06 01:07:15 +01:00
Luc
ac9badbe9e [now-cli] Always output deployment url in stdout (#3753) 2020-02-06 00:58:24 +01:00
luc
62beb0f78d Publish Stable
- @now/frameworks@0.0.9
 - @now/build-utils@1.3.9
 - @now/cgi@1.0.3
 - now@17.0.0
 - now-client@7.0.0
 - @now/go@1.0.3
 - @now/next@2.3.13
 - @now/node@1.4.1
 - @now/python@1.1.3
 - @now/routing-utils@1.5.2
 - @now/ruby@1.0.2
 - @now/static-build@0.14.12
2020-02-05 23:03:23 +01:00
luc
5f9777f4af Publish Canary
- now@17.0.0-canary.35
2020-02-05 22:38:39 +01:00
Luc
e00db4437a [now-cli] Use npx when available to run dev command (#3749)
* use npx when available

* add --no-install

* replace $PORT and %PORT% in devCommand

* remove PORT from env variables

* replace more than one $PORT or %PORT%

* fix regex
2020-02-05 22:37:06 +01:00
Steven
b0e4f2590d Publish Stable
- @now/cgi@1.0.2
 - @now/go@1.0.2
 - @now/python@1.1.2
2020-02-05 15:09:14 -05:00
Leo Lamprecht
f0d58eac8c Remove now dev suggestion (#3748) 2020-02-05 20:50:21 +01:00
Steven
dae830d2b6 [examples] Fix hugo theme (#3746)
The Hugo theme was lost when transferring from `zeit/now-examples` to `zeit/now`.

This PR fixes the `.gitignore` file to include the `dist` directory and override our root `.gitignore`.
2020-02-05 19:30:08 +00:00
dependabot[bot]
e3071e4e29 Bump mixin-deep from 1.3.1 to 1.3.2 in /packages/now-cgi (#3736)
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-02-05 09:52:08 -05:00
Steven
073d7ece23 Publish Canary
- @now/build-utils@1.3.9-canary.0
 - now@17.0.0-canary.34
2020-02-05 08:29:10 -05:00
Andy Bitz
071258ba33 Publish Stable
- @now/build-utils@1.3.8
2020-02-05 03:27:31 +01:00
Andy
c0e00dc69a [now-build-utils] Fix build script check (#3743) 2020-02-05 03:27:17 +01:00
luc
6e5c136337 Publish Canary
- now@17.0.0-canary.33
2020-02-05 02:26:53 +01:00
Steven
60428cd4cf [now-cli] Bump @zeit/fun to 0.11.2 (#3741)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-05 02:20:54 +01:00
Luc
c6b9d80eec Fix now cli breaking tests (#3742) 2020-02-05 02:17:43 +01:00
Luc
953bdc10e5 [now-cli] Fix prompts and fetch team on windows (#3740)
* fix fetch on windows

* update inquirer

Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-02-05 01:58:49 +01:00
Andy Bitz
becdbd2136 Publish Stable
- @now/build-utils@1.3.7
2020-02-05 01:52:02 +01:00
Luc
da9bb31259 [now-cli] Handle no framework detected case (#3738)
* handle no framework detected case

* remove related test

* simplify

Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-02-05 01:49:13 +01:00
Luc
8cbf036921 [now-cli] Do not prompt for root directory when project is linked (#3737)
* do not prompt for root directory when linked

* run tests

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-02-05 01:48:52 +01:00
Andy
8f66e4a308 [now-build-utils] Handle empty buildCommand and outputDirectory (#3739)
* [now-build-utils] Handle empty buildCommand and outputDirectory

* Update comment
2020-02-05 01:47:54 +01:00
Luc
9627b612f2 [now-cli] Do not show spinners with --debug (#3732)
* create output.wait and use it

* fix printing "ended" multiple times

* update more `wait` -> `output.spinner`

* timeout -> delay
2020-02-04 23:23:37 +01:00
Luc
8a9ded6d61 [now-cli] Slugify suggested project name (#3733)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-04 22:29:07 +01:00
Steven
d89c772bd5 [now-build-utils] Exclude _test.go files (#3735)
Typically, Go tests are side-by-side with their source files in a `_test.go`.

The Go documentation says the following:

> To write a new test suite, create a file whose name ends _test.go that contains the TestXxx functions as described here. Put the file in the same package as the one being tested. The file will be excluded from regular package builds but will be included when the “go test” command is run. [View Docs](https://golang.org/pkg/testing/)

This PR excludes the test files from being turned into Serverless Functions.
2020-02-04 21:11:26 +00:00
Steven
32137586b9 Publish Stable
- @now/static-build@0.14.11
2020-02-04 15:10:33 -05:00
58 changed files with 521 additions and 349 deletions

View File

@@ -16,7 +16,6 @@ To quickly start a new project, run the following commands:
```
now init # Pick an example project to clone
cd <PROJECT> # Change directory to the newly created project
now dev # Run locally during development
now # Deploy to the cloud
```

View File

@@ -28,3 +28,5 @@ npm-debug.log
/junit.xml
partials/structure/stylesheet.html
!dist

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
!function(n){function t(e){if(r[e])return r[e].exports;var o=r[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};t.m=n,t.c=r,t.i=function(n){return n},t.d=function(n,r,e){t.o(n,r)||Object.defineProperty(n,r,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(r,"a",r),r},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=1)}([function(n,t){},function(n,t,r){"use strict";var e=r(0);!function(n){n&&n.__esModule}(e)}]);

View File

@@ -1,6 +1,6 @@
{
"name": "@now/frameworks",
"version": "0.0.8",
"version": "0.0.9",
"main": "frameworks.json",
"license": "UNLICENSED"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/build-utils",
"version": "1.3.7-canary.2",
"version": "1.3.9",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

View File

@@ -28,7 +28,7 @@ function getApiBuilders({ tag }: Pick<Options, 'tag'> = {}): Builder[] {
return [
{ src: 'api/**/*.js', use: `@now/node${withTag}`, config },
{ src: 'api/**/*.ts', use: `@now/node${withTag}`, config },
{ src: 'api/**/*.go', use: `@now/go${withTag}`, config },
{ src: 'api/**/!(*_test).go', use: `@now/go${withTag}`, config },
{ src: 'api/**/*.py', use: `@now/python${withTag}`, config },
{ src: 'api/**/*.rb', use: `@now/ruby${withTag}`, config },
];
@@ -423,10 +423,18 @@ export async function detectBuilders(
let frontendBuilder: Builder | null = null;
if (hasBuildScript(pkg) || buildCommand || framework) {
// Everything will be static if either is an empty string
const ignoreBuild = buildCommand === '' || outputDirectory === '';
if (!ignoreBuild && (hasBuildScript(pkg) || buildCommand || framework)) {
frontendBuilder = detectFrontBuilder(pkg, builders, files, options);
} else {
if (!options.ignoreBuildScript && pkg && builders.length === 0) {
if (
!ignoreBuild &&
!options.ignoreBuildScript &&
pkg &&
builders.length === 0
) {
// We only show this error when there are no api builders
// since the dependencies of the pkg could be used for those
errors.push({
@@ -442,7 +450,9 @@ export async function detectBuilders(
// when there are no build steps
const outDir = outputDirectory || 'public';
if (hasDirectory(outDir, files)) {
// If `outputDirectory` is an empty string,
// we'll default to the root directory.
if (hasDirectory(outDir, files) && outputDirectory !== '') {
frontendBuilder = {
use: '@now/static',
src: `${outDir}/**/*`,

View File

@@ -151,6 +151,27 @@ describe('Test `detectBuilders`', () => {
expect(builders!.length).toBe(2);
});
it('api go with test files', async () => {
const files = [
'api/index.go',
'api/index_test.go',
'api/test.go',
'api/testing_another.go',
'api/readme.md',
'api/config/staging.go',
'api/config/staging_test.go',
'api/config/production.go',
'api/config/production_test.go',
'api/src/controllers/health.go',
'api/src/controllers/user.module.go',
'api/src/controllers/user.module_test.go',
];
const { builders } = await detectBuilders(files);
expect(builders!.length).toBe(7);
expect(builders!.some(b => b.src.endsWith('_test.go'))).toBe(false);
});
it('just public', async () => {
const files = ['public/index.html', 'public/favicon.ico', 'README.md'];
@@ -745,6 +766,53 @@ describe('Test `detectBuilders`', () => {
},
]);
});
it('All static if `buildCommand` is an empty string', async () => {
const files = ['index.html'];
const projectSettings = { buildCommand: '' };
const { builders, errors } = await detectBuilders(files, null, {
projectSettings,
});
expect(errors).toBe(null);
expect(builders).toBe(null);
});
it('All static if `outputDirectory` is an empty string', async () => {
const files = ['index.html'];
const projectSettings = { outputDirectory: '' };
const { builders, errors } = await detectBuilders(files, null, {
projectSettings,
});
expect(errors).toBe(null);
expect(builders).toBe(null);
});
it('All static if `buildCommand` is an empty string with an `outputDirectory`', async () => {
const files = ['out/index.html'];
const projectSettings = { buildCommand: '', outputDirectory: 'out' };
const { builders, errors } = await detectBuilders(files, null, {
projectSettings,
});
expect(errors).toBe(null);
expect(builders![0]!.use).toBe('@now/static');
expect(builders![0]!.src).toBe('out/**/*');
});
it('do not require build script when `buildCommand` is an empty string', async () => {
const files = ['index.html', 'about.html', 'package.json'];
const projectSettings = { buildCommand: '', outputDirectory: '' };
const pkg = {
scripts: {
build: 'false',
},
};
const { builders, errors } = await detectBuilders(files, pkg, {
projectSettings,
});
expect(builders).toBe(null);
expect(errors).toBe(null);
});
});
it('Test `detectRoutes`', async () => {

View File

@@ -1,6 +1,6 @@
{
"name": "@now/cgi",
"version": "1.0.1",
"version": "1.0.3",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -15,7 +15,7 @@
"@zeit/best@0.4.3":
version "0.4.3"
resolved "http://registry.npmjs.org/@zeit/best/-/best-0.4.3.tgz#eaebdfa8b24121a97b1753501ea8c9330d549b30"
resolved "https://registry.npmjs.org/@zeit/best/-/best-0.4.3.tgz#eaebdfa8b24121a97b1753501ea8c9330d549b30"
dependencies:
arg "1.0.0"
chalk "2.3.1"
@@ -144,7 +144,7 @@ call-me-maybe@^1.0.1:
chalk@2.3.1:
version "2.3.1"
resolved "http://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
resolved "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
dependencies:
ansi-styles "^3.2.0"
escape-string-regexp "^1.0.5"
@@ -585,8 +585,8 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
mixin-deep@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
dependencies:
for-in "^1.0.2"
is-extendable "^1.0.1"
@@ -704,7 +704,7 @@ rmfr@2.0.0:
safe-regex@^1.1.0:
version "1.1.0"
resolved "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
dependencies:
ret "~0.1.10"

View File

@@ -1,6 +1,6 @@
{
"name": "now",
"version": "17.0.0-canary.32",
"version": "17.0.2",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Now",
@@ -63,6 +63,7 @@
},
"devDependencies": {
"@sentry/node": "5.5.0",
"@sindresorhus/slugify": "0.10.0",
"@types/ansi-escapes": "3.0.0",
"@types/ansi-regex": "4.0.0",
"@types/async-retry": "1.2.1",
@@ -89,10 +90,10 @@
"@types/tar-fs": "1.16.1",
"@types/text-table": "0.2.0",
"@types/universal-analytics": "0.4.2",
"@types/which": "1.3.1",
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@zeit/dockerignore": "0.0.5",
"@zeit/fun": "0.11.0",
"@zeit/fun": "0.11.2",
"@zeit/ncc": "0.18.5",
"@zeit/source-map-support": "0.6.2",
"ajv": "6.10.2",
@@ -131,7 +132,7 @@
"http-proxy": "1.17.0",
"ignore": "4.0.6",
"ini": "1.3.4",
"inquirer": "3.3.0",
"inquirer": "7.0.4",
"is-port-reachable": "3.0.0",
"is-url": "1.2.2",
"jaro-winkler": "0.2.8",
@@ -174,7 +175,7 @@
"universal-analytics": "0.4.20",
"update-check": "1.5.3",
"utility-types": "2.1.0",
"which": "1.3.1",
"which": "2.0.2",
"which-promise": "1.0.0",
"write-json-file": "2.2.0",
"xdg-app-paths": "5.1.0",

View File

@@ -8,12 +8,11 @@ import getAliases from '../../util/alias/get-aliases';
import getScope from '../../util/get-scope.ts';
import stamp from '../../util/output/stamp.ts';
import strlen from '../../util/strlen.ts';
import wait from '../../util/output/wait';
export default async function ls(ctx, opts, args, output) {
const {
authConfig: { token },
config
config,
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
@@ -22,7 +21,7 @@ export default async function ls(ctx, opts, args, output) {
apiUrl,
token,
currentTeam,
debug: debugEnabled
debug: debugEnabled,
});
let contextName = null;
@@ -51,7 +50,7 @@ export default async function ls(ctx, opts, args, output) {
return 1;
}
cancelWait = wait(
cancelWait = output.spinner(
args[0]
? `Fetching alias details for "${args[0]}" under ${chalk.bold(
contextName
@@ -112,13 +111,13 @@ function printAliasTable(aliases) {
? a.deployment.url
: chalk.gray(''),
a.alias,
ms(Date.now() - new Date(a.created))
])
ms(Date.now() - new Date(a.created)),
]),
],
{
align: ['l', 'l', 'r'],
hsep: ' '.repeat(4),
stringLength: strlen
stringLength: strlen,
}
).replace(/^/gm, ' ')}\n\n`;
}
@@ -130,13 +129,13 @@ function printPathAliasTable(rules) {
rules.map(rule => [
rule.pathname ? rule.pathname : chalk.cyan('[fallthrough]'),
rule.method ? rule.method : '*',
rule.dest
rule.dest,
])
),
{
align: ['l', 'l', 'l', 'l'],
hsep: ' '.repeat(6),
stringLength: strlen
stringLength: strlen,
}
).replace(/^(.*)/gm, ' $1')}\n`;
}

View File

@@ -21,7 +21,7 @@ export default async function({ creditCards, clear = false, contextName }) {
name: {
label: rightPad('Full Name', 12),
placeholder: 'John Appleseed',
validateValue: data => data.trim().length > 0
validateValue: data => data.trim().length > 0,
},
cardNumber: {
@@ -36,7 +36,7 @@ export default async function({ creditCards, clear = false, contextName }) {
return false;
}
return ccValidator.isValidCardNumber(data, type);
}
},
},
ccv: {
@@ -46,7 +46,7 @@ export default async function({ creditCards, clear = false, contextName }) {
validateValue: data => {
const brand = state.cardNumber.brand.toLowerCase();
return ccValidator.doesCvvMatchType(data, brand);
}
},
},
expDate: {
@@ -54,8 +54,8 @@ export default async function({ creditCards, clear = false, contextName }) {
mask: 'expDate',
placeholder: 'mm / yyyy',
middleware: expDateMiddleware,
validateValue: data => !ccValidator.isExpired(...data.split(' / '))
}
validateValue: data => !ccValidator.isExpired(...data.split(' / ')),
},
};
async function render() {
@@ -80,7 +80,7 @@ export default async function({ creditCards, clear = false, contextName }) {
mask: piece.mask,
validateKeypress: piece.validateKeypress,
validateValue: piece.validateValue,
autoComplete: piece.autoComplete
autoComplete: piece.autoComplete,
});
piece.value = result;
@@ -135,7 +135,7 @@ export default async function({ creditCards, clear = false, contextName }) {
name: state.name.value,
cardNumber: state.cardNumber.value,
ccv: state.ccv.value,
expDate: state.expDate.value
expDate: state.expDate.value,
});
stopSpinner();
@@ -156,9 +156,9 @@ export default async function({ creditCards, clear = false, contextName }) {
stopSpinner();
const linesToClear = state.error ? 15 : 14;
process.stdout.write(ansiEscapes.eraseLines(linesToClear));
state.error = `${chalk.red(
'> Error!'
)} ${err.message} Please make sure the info is correct`;
state.error = `${chalk.red('> Error!')} ${
err.message
} Please make sure the info is correct`;
await render();
}
}

View File

@@ -5,7 +5,6 @@ import Now from '../../util';
import Client from '../../util/client';
import getScope from '../../util/get-scope';
import stamp from '../../util/output/stamp';
import wait from '../../util/output/wait';
import createCertFromFile from '../../util/certs/create-cert-from-file';
import createCertForCns from '../../util/certs/create-cert-for-cns';
import { NowContext } from '../../types';
@@ -110,7 +109,7 @@ async function add(
(res, item) => res.concat(item.split(',')),
[]
);
const cancelWait = wait(
const cancelWait = output.spinner(
`Generating a certificate for ${chalk.bold(cns.join(', '))}`
);

View File

@@ -94,7 +94,6 @@ const printDeploymentStatus = async (
},
deployStamp,
isClipboardEnabled,
quiet,
isFile
) => {
const isProdDeployment = target === 'production';
@@ -144,11 +143,6 @@ const printDeploymentStatus = async (
.catch(error => output.debug(`Error copying to clipboard: ${error}`));
}
// write to stdout
if (quiet) {
process.stdout.write(`https://${deploymentUrl}`);
}
output.print(
prependEmoji(
`${isProdDeployment ? 'Production' : 'Preview'}: ${chalk.bold(
@@ -404,6 +398,7 @@ export default async function main(
}
org = await selectOrg(
output,
'Which scope do you want to deploy to?',
client,
ctx.config.currentTeam,
@@ -427,8 +422,10 @@ export default async function main(
if (typeof projectOrNewProjectName === 'string') {
newProjectName = projectOrNewProjectName;
rootDirectory = await inputRootDirectory(path, output, autoConfirm);
} else {
project = projectOrNewProjectName;
rootDirectory = project.rootDirectory;
// we can already link the project
await linkFolderToProject(
@@ -443,8 +440,6 @@ export default async function main(
);
status = 'linked';
}
rootDirectory = await inputRootDirectory(path, output, autoConfirm);
}
const sourcePath = rootDirectory ? join(path, rootDirectory) : path;
@@ -455,7 +450,9 @@ export default async function main(
output,
path,
sourcePath,
project ? `To change your project settings, go to https://zeit.co/${org.slug}/${project.name}/settings` : ''
project
? `To change your project settings, go to https://zeit.co/${org.slug}/${project.name}/settings`
: ''
)) === false
) {
return 1;
@@ -656,7 +653,6 @@ export default async function main(
deployment,
deployStamp,
!argv['--no-clipboard'],
quiet,
isFile
);
}

View File

@@ -13,7 +13,6 @@ import param from '../../util/output/param';
import promptBool from '../../util/input/prompt-bool';
import purchaseDomain from '../../util/domains/purchase-domain';
import stamp from '../../util/output/stamp';
import wait from '../../util/output/wait';
type Options = {
'--debug': boolean;
@@ -27,7 +26,7 @@ export default async function buy(
) {
const {
authConfig: { token },
config
config,
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
@@ -100,7 +99,7 @@ export default async function buy(
let buyResult;
const purchaseStamp = stamp();
const stopPurchaseSpinner = wait('Purchasing');
const stopPurchaseSpinner = output.spinner('Purchasing');
try {
buyResult = await purchaseDomain(client, domainName, price);

View File

@@ -9,7 +9,6 @@ import listInput from '../../util/input/list';
import listItem from '../../util/output/list-item';
import promptBool from '../../util/input/prompt-bool';
import toHumanPath from '../../util/humanize-path';
import wait from '../../util/output/wait';
import { Output } from '../../util/output';
import { NowContext } from '../../types';
import success from '../../util/output/success';
@@ -24,10 +23,10 @@ type Options = {
};
type Example = {
name: string,
visible: boolean,
suggestions: string[]
}
name: string;
visible: boolean;
suggestions: string[];
};
const EXAMPLE_API = 'https://now-example-files.zeit.sh';
@@ -40,7 +39,7 @@ export default async function init(
const [name, dir] = args;
const force = opts['-f'] || opts['--force'];
const examples = await fetchExampleList();
const examples = await fetchExampleList(output);
if (!examples) {
throw new Error(`Could not fetch example list.`);
@@ -56,22 +55,22 @@ export default async function init(
return 0;
}
return extractExample(chosen, dir, force);
return extractExample(output, chosen, dir, force);
}
if (exampleList.includes(name)) {
return extractExample(name, dir, force);
return extractExample(output, name, dir, force);
}
const oldExample = examples.find(x => !x.visible && x.name === name);
if (oldExample) {
return extractExample(name, dir, force, 'v1');
return extractExample(output, name, dir, force, 'v1');
}
const found = await guess(exampleList, name);
if (typeof found === 'string') {
return extractExample(found, dir, force);
return extractExample(output, found, dir, force);
}
console.log(info('No changes made.'));
@@ -81,8 +80,8 @@ export default async function init(
/**
* Fetch example list json
*/
async function fetchExampleList() {
const stopSpinner = wait('Fetching examples');
async function fetchExampleList(output: Output) {
const stopSpinner = output.spinner('Fetching examples');
const url = `${EXAMPLE_API}/v2/list.json`;
try {
@@ -93,7 +92,7 @@ async function fetchExampleList() {
throw new Error(`Failed fetching list.json (${resp.statusText}).`);
}
return await resp.json() as Example[];
return (await resp.json()) as Example[];
} catch (e) {
stopSpinner();
}
@@ -106,22 +105,28 @@ async function chooseFromDropdown(message: string, exampleList: string[]) {
const choices = exampleList.map(name => ({
name,
value: name,
short: name
short: name,
}));
return listInput({
message,
separator: false,
choices
choices,
});
}
/**
* Extract example to directory
*/
async function extractExample(name: string, dir: string, force?: boolean, ver: string = 'v2') {
async function extractExample(
output: Output,
name: string,
dir: string,
force?: boolean,
ver: string = 'v2'
) {
const folder = prepareFolder(process.cwd(), dir || name, force);
const stopSpinner = wait(`Fetching ${name}`);
const stopSpinner = output.spinner(`Fetching ${name}`);
const url = `${EXAMPLE_API}/${ver}/download/${name}.tar.gz`;

View File

@@ -9,7 +9,6 @@ import createOutput from '../util/output';
import Now from '../util';
import logo from '../util/output/logo';
import elapsed from '../util/output/elapsed.ts';
import wait from '../util/output/wait';
import { handleError } from '../util/error';
import strlen from '../util/strlen.ts';
import Client from '../util/client.ts';
@@ -79,13 +78,16 @@ export default async function main(ctx) {
return 1;
}
const { authConfig: { token }, config } = ctx;
const {
authConfig: { token },
config,
} = ctx;
const { currentTeam } = config;
const client = new Client({
apiUrl,
token,
currentTeam,
debug: debugEnabled
debug: debugEnabled,
});
let contextName = null;
@@ -104,7 +106,7 @@ export default async function main(ctx) {
// resolve the deployment, since we might have been given an alias
const depFetchStart = Date.now();
const cancelWait = wait(
const cancelWait = output.spinner(
`Fetching deployment "${id}" in ${chalk.bold(contextName)}`
);
@@ -140,7 +142,7 @@ export default async function main(ctx) {
limits,
version,
routes,
readyState
readyState,
} = deployment;
const isBuilds = version === 2;
@@ -159,7 +161,7 @@ export default async function main(ctx) {
)}/events?types=event`
)
),
isBuilds ? now.fetch(buildsUrl) : { builds: [] }
isBuilds ? now.fetch(buildsUrl) : { builds: [] },
]);
cancelWait();
@@ -174,7 +176,9 @@ export default async function main(ctx) {
print(` ${chalk.cyan('version')}\t${version}\n`);
print(` ${chalk.cyan('id')}\t\t${finalId}\n`);
print(` ${chalk.cyan('name')}\t${name}\n`);
print(` ${chalk.cyan('readyState')}\t${stateString(state || readyState)}\n`);
print(
` ${chalk.cyan('readyState')}\t${stateString(state || readyState)}\n`
);
if (!isBuilds) {
print(` ${chalk.cyan('type')}\t${type}\n`);
}
@@ -255,7 +259,7 @@ export default async function main(ctx) {
`${table(t, {
align: ['l', 'c', 'c', 'c'],
hsep: ' '.repeat(8),
stringLength: strlen
stringLength: strlen,
}).replace(/^(.*)/gm, ' $1')}\n`
);
print('\n');
@@ -269,9 +273,9 @@ export default async function main(ctx) {
events.forEach(data => {
if (!data.event) return; // keepalive
print(
` ${chalk.gray(
new Date(data.created).toISOString()
)} ${data.event} ${getEventMetadata(data)}\n`
` ${chalk.gray(new Date(data.created).toISOString())} ${
data.event
} ${getEventMetadata(data)}\n`
);
});
print('\n');

View File

@@ -8,7 +8,6 @@ import chalk from 'chalk';
import ua from '../util/ua.ts';
import getArgs from '../util/get-args';
import error from '../util/output/error';
import wait from '../util/output/wait';
import highlight from '../util/output/highlight';
import ok from '../util/output/ok';
import cmd from '../util/output/cmd.ts';
@@ -191,7 +190,7 @@ const login = async ctx => {
let verificationToken;
let securityCode;
stopSpinner = wait('Sending you an email');
stopSpinner = output.spinner('Sending you an email');
try {
const data = await executeLogin(apiUrl, email);
@@ -216,7 +215,7 @@ const login = async ctx => {
)}.\n`
);
stopSpinner = wait('Waiting for your confirmation');
stopSpinner = output.spinner('Waiting for your confirmation');
let token;

View File

@@ -6,7 +6,6 @@ import logo from '../util/output/logo';
import elapsed from '../util/output/elapsed.ts';
import { maybeURL, normalizeURL, parseInstanceURL } from '../util/url';
import printEvents from '../util/events';
import wait from '../util/output/wait';
import Client from '../util/client.ts';
import getScope from '../util/get-scope.ts';
@@ -165,7 +164,7 @@ export default async function main(ctx) {
const id = deploymentIdOrURL;
const depFetchStart = Date.now();
const cancelWait = wait(
const cancelWait = output.spinner(
`Fetching deployment "${id}" in ${chalk.bold(contextName)}`
);
@@ -287,12 +286,12 @@ function printLogShort(log) {
data = JSON.stringify(obj, null, 2);
} else {
data = (log.text || '')
.replace(/\n$/, '')
.replace(/^\n/, '')
// eslint-disable-next-line no-control-regex
.replace(/\x1b\[1000D/g, '')
.replace(/\x1b\[0K/g, '')
.replace(/\x1b\[1A/g, '');
.replace(/\n$/, '')
.replace(/^\n/, '')
// eslint-disable-next-line no-control-regex
.replace(/\x1b\[1000D/g, '')
.replace(/\x1b\[0K/g, '')
.replace(/\x1b\[1A/g, '');
if (/warning/i.test(data)) {
data = chalk.yellow(data);
} else if (log.type === 'stderr') {

View File

@@ -6,7 +6,6 @@ import table from 'text-table';
import Now from '../util';
import getAliases from '../util/alias/get-aliases';
import createOutput from '../util/output';
import wait from '../util/output/wait';
import logo from '../util/output/logo';
import cmd from '../util/output/cmd.ts';
import elapsed from '../util/output/elapsed.ts';
@@ -132,7 +131,7 @@ export default async function main(ctx) {
throw err;
}
const cancelWait = wait(
const cancelWait = output.spinner(
`Fetching deployment(s) ${ids
.map(id => `"${id}"`)
.join(' ')} in ${chalk.bold(contextName)}`

View File

@@ -57,7 +57,7 @@ export default async function({ apiUrl, token, teams, config }) {
validateKeypress: validateSlugKeypress,
initialValue: slug,
valid: team,
forceLowerCase: true
forceLowerCase: true,
});
} catch (err) {
if (err.message === 'USER_ABORT') {
@@ -95,7 +95,7 @@ export default async function({ apiUrl, token, teams, config }) {
try {
name = await textInput({
label: `- ${teamNamePrefix}`,
validateKeypress: validateNameKeypress
validateKeypress: validateNameKeypress,
});
} catch (err) {
if (err.message === 'USER_ABORT') {
@@ -153,7 +153,7 @@ export default async function({ apiUrl, token, teams, config }) {
introMsg: 'Invite your teammates! When done, press enter on an empty field',
noopMsg: `You can invite teammates later by running ${cmd(
'now teams invite'
)}`
)}`,
});
gracefulExit();

View File

@@ -30,7 +30,7 @@ const domains = Array.from(
'inbox.com',
'mail.com',
'gmx.com',
'icloud.com'
'icloud.com',
])
);
@@ -56,17 +56,15 @@ const emailAutoComplete = (value, teamSlug) => {
return false;
};
export default async function(
{
teams,
args,
config,
introMsg,
noopMsg = 'No changes made',
apiUrl,
token
} = {}
) {
export default async function({
teams,
args,
config,
introMsg,
noopMsg = 'No changes made',
apiUrl,
token,
} = {}) {
const { currentTeam: currentTeamId } = config;
const stopSpinner = wait('Fetching teams');
@@ -86,7 +84,11 @@ export default async function(
if (!currentTeam) {
// We specifically need a team scope here
let err = `You can't run this command under ${param(user.username || user.email)}.\nPlease select a team scope using ${cmd('now switch')} or use ${cmd('--scope')}`;
let err = `You can't run this command under ${param(
user.username || user.email
)}.\nPlease select a team scope using ${cmd('now switch')} or use ${cmd(
'--scope'
)}`;
return fatalError(err);
}
@@ -107,7 +109,9 @@ export default async function(
userInfo = res.name || res.username;
} catch (err) {
if (err.code === 'user_not_found') {
console.error(error(`No user exists with the email address "${email}".`));
console.error(
error(`No user exists with the email address "${email}".`)
);
return 1;
}
@@ -115,7 +119,11 @@ export default async function(
}
stopSpinner();
console.log(`${chalk.cyan(chars.tick)} ${email}${userInfo ? ` (${userInfo})` : ''} ${elapsed()}`);
console.log(
`${chalk.cyan(chars.tick)} ${email}${
userInfo ? ` (${userInfo})` : ''
} ${elapsed()}`
);
} else {
console.log(`${chalk.red(`${email}`)} ${chalk.gray('[invalid]')}`);
}
@@ -135,7 +143,7 @@ export default async function(
email = await textInput({
label: `- ${inviteUserPrefix}`,
validateValue: validateEmail,
autoComplete: value => emailAutoComplete(value, currentTeam.slug)
autoComplete: value => emailAutoComplete(value, currentTeam.slug),
});
} catch (err) {
if (err.message !== 'USER_ABORT') {
@@ -149,7 +157,10 @@ export default async function(
stopSpinner = wait(inviteUserPrefix + email);
try {
// eslint-disable-next-line no-await-in-loop
const { name, username } = await teams.inviteUser({ teamId: currentTeam.id, email });
const { name, username } = await teams.inviteUser({
teamId: currentTeam.id,
email,
});
stopSpinner();
const userInfo = name || username;
email = `${email}${userInfo ? ` (${userInfo})` : ''} ${elapsed()}`;

View File

@@ -27,20 +27,20 @@ export default async function({ teams, config, apiUrl, token }) {
if (accountIsCurrent) {
currentTeam = {
slug: user.username || user.email
slug: user.username || user.email,
};
}
const teamList = list.map(({ slug, name }) => ({
name,
value: slug,
current: slug === currentTeam.slug ? chars.tick : ''
current: slug === currentTeam.slug ? chars.tick : '',
}));
teamList.unshift({
name: user.email,
value: user.username || user.email,
current: (accountIsCurrent && chars.tick) || ''
current: (accountIsCurrent && chars.tick) || '',
});
// Let's bring the current team to the beginning of the list

View File

@@ -3,7 +3,6 @@ import { Output } from '../output';
import * as ERRORS from '../errors-ts';
import Client from '../client';
import createCertForAlias from '../certs/create-cert-for-alias';
import wait from '../output/wait';
export type AliasRecord = {
uid: string;
@@ -20,7 +19,7 @@ export default async function createAlias(
alias: string,
externalDomain: boolean
) {
let cancelMessage = wait(`Creating alias`);
let cancelMessage = output.spinner(`Creating alias`);
const result = await performCreateAlias(
client,
contextName,
@@ -41,7 +40,7 @@ export default async function createAlias(
return cert;
}
let cancelMessage = wait(`Creating alias`);
let cancelMessage = output.spinner(`Creating alias`);
const secondTry = await performCreateAlias(
client,
contextName,
@@ -66,7 +65,7 @@ async function performCreateAlias(
`/now/deployments/${deployment.uid}/aliases`,
{
method: 'POST',
body: { alias }
body: { alias },
}
);
} catch (error) {
@@ -77,7 +76,10 @@ async function performCreateAlias(
return { uid: error.uid, alias: error.alias } as AliasRecord;
}
if (error.code === 'deployment_not_found') {
return new ERRORS.DeploymentNotFound({ context: contextName, id: deployment.uid });
return new ERRORS.DeploymentNotFound({
context: contextName,
id: deployment.uid,
});
}
if (error.code === 'gone') {
return new ERRORS.DeploymentFailedAliasImpossible();
@@ -94,7 +96,7 @@ async function performCreateAlias(
}
}
if (error.status === 400) {
return new ERRORS.DeploymentNotReady({url: deployment.url })
return new ERRORS.DeploymentNotReady({ url: deployment.url });
}
throw error;

View File

@@ -3,7 +3,6 @@ import chalk from 'chalk';
import getAppLastDeployment from '../deploy/get-app-last-deployment';
import getAppName from '../deploy/get-app-name';
import fetchDeploymentByIdOrHost from '../deploy/get-deployment-by-id-or-host';
import wait from '../output/wait';
import Client from '../client';
import { Output } from '../output';
import { User, Config } from '../../types';
@@ -17,7 +16,7 @@ export default async function getDeploymentForAlias(
contextName: string,
localConfig: Config
) {
const cancelWait = wait(
const cancelWait = output.spinner(
`Fetching deployment to alias in ${chalk.bold(contextName)}`
);

View File

@@ -4,7 +4,6 @@ import * as ERRORS from '../errors-ts';
import Client from '../client';
import createCertForAlias from '../certs/create-cert-for-alias';
import setupDomain from '../domains/setup-domain';
import wait from '../output/wait';
const NOW_SH_REGEX = /\.now\.sh$/;
@@ -34,6 +33,7 @@ export default async function upsertPathAlias(
}
const result = await performUpsertPathAlias(
output,
client,
alias,
rules,
@@ -51,23 +51,26 @@ export default async function upsertPathAlias(
return cert;
}
return performUpsertPathAlias(client, alias, rules, contextName);
return performUpsertPathAlias(output, client, alias, rules, contextName);
}
return result;
}
async function performUpsertPathAlias(
output: Output,
client: Client,
alias: string,
rules: PathRule[],
contextName: string
) {
const cancelMessage = wait(`Updating path alias rules for ${alias}`);
const cancelMessage = output.spinner(
`Updating path alias rules for ${alias}`
);
try {
const record = await client.fetch<AliasRecord>(`/now/aliases`, {
body: { alias, rules },
method: 'POST'
method: 'POST',
});
cancelMessage();
return record;

View File

@@ -5,7 +5,6 @@ import createCertForCns from './create-cert-for-cns';
import getWildcardCnsForAlias from './get-wildcard-cns-for-alias';
import joinWords from '../output/join-words';
import stamp from '../output/stamp';
import wait from '../output/wait';
export default async function createCertificateForAlias(
output: Output,
@@ -15,7 +14,7 @@ export default async function createCertificateForAlias(
shouldBeWildcard: boolean
) {
const cns = shouldBeWildcard ? getWildcardCnsForAlias(alias) : [alias];
const cancelMessage = wait(`Generating a certificate...`);
const cancelMessage = output.spinner(`Generating a certificate...`);
const certStamp = stamp();
const cert = await createCertForCns(client, cns, context);
if (cert instanceof NowError) {
@@ -25,9 +24,9 @@ export default async function createCertificateForAlias(
cancelMessage();
output.log(
`Certificate for ${joinWords(
cert.cns
)} (${cert.uid}) created ${certStamp()}`
`Certificate for ${joinWords(cert.cns)} (${
cert.uid
}) created ${certStamp()}`
);
return cert;
}

View File

@@ -4,7 +4,6 @@ import { Output } from '../output';
import Client from '../client';
import createCertForCns from '../certs/create-cert-for-cns';
import setupDomain from '../domains/setup-domain';
import wait from '../output/wait';
import { InvalidDomain } from '../errors-ts';
export default async function generateCertForDeploy(
@@ -23,7 +22,9 @@ export default async function generateCertForDeploy(
return new InvalidDomain(deployURL);
}
const cancelSetupWait = wait(`Setting custom suffix domain ${domain}`);
const cancelSetupWait = output.spinner(
`Setting custom suffix domain ${domain}`
);
const result = await setupDomain(output, client, domain, contextName);
cancelSetupWait();
if (result instanceof NowError) {
@@ -31,7 +32,7 @@ export default async function generateCertForDeploy(
}
// Generate the certificate with the given parameters
const cancelCertWait = wait(
const cancelCertWait = output.spinner(
`Generating a wildcard certificate for ${domain}`
);
const cert = await createCertForCns(

View File

@@ -6,7 +6,6 @@ import {
DeploymentOptions,
NowClientOptions,
} from 'now-client';
import wait from '../output/wait';
import { Output } from '../output';
// @ts-ignore
import Now from '../../util';
@@ -84,6 +83,7 @@ export default async function processDeployment({
deployStamp,
force,
nowConfig,
quiet,
} = args;
const { debug } = output;
@@ -106,7 +106,7 @@ export default async function processDeployment({
let buildSpinner = null;
let deploySpinner = null;
let deployingSpinner = wait(
let deployingSpinner = output.spinner(
isSettingUpProject
? `Setting up project`
: `Deploying ${chalk.bold(`${org.slug}/${projectName}`)}`,
@@ -180,11 +180,15 @@ export default async function processDeployment({
printInspectUrl(output, event.payload.url, deployStamp, org.slug);
if (quiet) {
process.stdout.write(`https://${event.payload.url}`);
}
if (queuedSpinner === null) {
queuedSpinner =
event.payload.readyState === 'QUEUED'
? wait('Queued', 0)
: wait('Building', 0);
? output.spinner('Queued', 0)
: output.spinner('Building', 0);
}
}
@@ -194,7 +198,7 @@ export default async function processDeployment({
}
if (buildSpinner === null) {
buildSpinner = wait('Building', 0);
buildSpinner = output.spinner('Building', 0);
}
}
@@ -206,7 +210,7 @@ export default async function processDeployment({
buildSpinner();
}
deploySpinner = wait('Completing', 0);
deploySpinner = output.spinner('Completing', 0);
}
// Handle error events

View File

@@ -20,7 +20,6 @@ import {
import pkg from '../../../package.json';
import { NoBuilderCacheError } from '../errors-ts';
import wait from '../output/wait';
import { Output } from '../output';
import { getDistTag } from '../get-dist-tag';
@@ -246,7 +245,7 @@ export async function installBuilders(
return;
}
const stopSpinner = wait(
const stopSpinner = output.spinner(
`Installing ${pluralize(
'Runtime',
packagesToInstall.length

View File

@@ -11,12 +11,13 @@ import { randomBytes } from 'crypto';
import serveHandler from 'serve-handler';
import { watch, FSWatcher } from 'chokidar';
import { parse as parseDotenv } from 'dotenv';
import { basename, dirname, extname, join, delimiter } from 'path';
import { basename, dirname, extname, join } from 'path';
import { getTransformedRoutes, HandleValue } from '@now/routing-utils';
import directoryTemplate from 'serve-handler/src/directory';
import getPort from 'get-port';
import { ChildProcess } from 'child_process';
import isPortReachable from 'is-port-reachable';
import which from 'which';
import {
Builder,
@@ -26,7 +27,6 @@ import {
detectRoutes,
detectApiDirectory,
detectApiExtensions,
execAsync,
spawnCommand,
} from '@now/build-utils';
@@ -1636,12 +1636,6 @@ export default class DevServer {
const cwd = this.cwd;
const { stdout: yarnBinStdout } = await execAsync('yarn', ['bin'], {
cwd,
});
const yarnBinPath = yarnBinStdout.trim();
this.output.log(
`Running Dev Command ${chalk.cyan.bold(`${this.devCommand}`)}`
);
@@ -1651,24 +1645,42 @@ export default class DevServer {
const env: EnvConfig = {
...process.env,
...this.buildEnv,
PATH: `${yarnBinPath}${delimiter}${process.env.PATH}`,
NOW_REGION: 'dev1',
PORT: `${port}`,
};
const devCommand = this.devCommand
.replace(/\$PORT/g, `${port}`)
.replace(/%PORT%/g, `${port}`);
this.output.debug(
`Starting dev command with parameters : ${JSON.stringify({
cwd: this.cwd,
devCommand: this.devCommand,
devCommand,
port,
})}`
);
const p = spawnCommand(this.devCommand, {
stdio: 'inherit',
cwd,
env,
});
let command = devCommand;
const isNpxAvailable = await which('npx')
.then(() => true)
.catch(() => false);
if (isNpxAvailable) {
command = `npx --no-install ${devCommand}`;
} else {
const isYarnAvailable = await which('yarn')
.then(() => true)
.catch(() => false);
if (isYarnAvailable) {
command = `yarn run --silent ${devCommand}`;
}
}
this.output.debug(`Spawning dev command: ${command}`);
const p = spawnCommand(command, { stdio: 'inherit', cwd, env });
p.on('exit', () => {
this.devProcessPort = undefined;

View File

@@ -9,7 +9,6 @@ import getDomainStatus from './get-domain-status';
import promptBool from '../input/prompt-bool';
import purchaseDomain from './purchase-domain';
import stamp from '../output/stamp';
import wait from '../output/wait';
import * as ERRORS from '../errors-ts';
const isTTY = process.stdout.isTTY;
@@ -20,7 +19,7 @@ export default async function purchaseDomainIfAvailable(
domain: string,
contextName: string
) {
const cancelWait = wait(`Checking status of ${chalk.bold(domain)}`);
const cancelWait = output.spinner(`Checking status of ${chalk.bold(domain)}`);
const buyDomainStamp = stamp();
const { available } = await getDomainStatus(client, domain);

View File

@@ -1,6 +1,8 @@
import Client from './client';
import { APIError, InvalidToken } from './errors-ts';
import { Team } from '../types';
// @ts-ignore
import NowTeams from './teams.js';
let teams: Team[] | undefined;
@@ -8,10 +10,15 @@ export default async function getTeams(client: Client) {
if (teams) return teams;
try {
const res = await client.fetch<{ teams: Team[] }>('/teams');
// we're using NowTeams because `client.fetch` hangs on windows
const teamClient = new NowTeams({
apiUrl: client._apiUrl,
token: client._token,
debug: client._debug,
});
teams = res.teams;
return teams;
const teams = (await teamClient.ls()).teams;
return teams as Team[];
} catch (error) {
if (error instanceof APIError && error.status === 403) {
throw new InvalidToken();

View File

@@ -43,7 +43,9 @@ export default async function editProjectSettings(
}
output.print(
`Auto-detected project settings (${chalk.bold(framework.name)}):\n`
!framework.slug
? `No framework detected. Default project settings:\n`
: `Auto-detected project settings (${chalk.bold(framework.name)}):\n`
);
settings.framework = framework.slug;

View File

@@ -6,7 +6,7 @@ import chalk from 'chalk';
import { ProjectNotFound } from '../../util/errors-ts';
import { Output } from '../output';
import { Project, Org } from '../../types';
import wait from '../output/wait';
import slugify from '@sindresorhus/slugify';
export default async function inputProject(
output: Output,
@@ -19,16 +19,26 @@ export default async function inputProject(
return detectedProjectName;
}
const slugifiedName = slugify(detectedProjectName);
// attempt to auto-detect a project to link
let detectedProject = null;
const existingProjectSpinner = wait('Searching for existing projects…', 1000);
const existingProjectSpinner = output.spinner(
'Searching for existing projects…',
1000
);
try {
const project = await getProjectByIdOrName(
client,
detectedProjectName,
org.id
);
detectedProject = project instanceof ProjectNotFound ? null : project;
const [project, slugifiedProject] = await Promise.all([
getProjectByIdOrName(client, detectedProjectName, org.id),
slugifiedName !== detectedProjectName
? getProjectByIdOrName(client, slugifiedName, org.id)
: null,
]);
detectedProject = !(project instanceof ProjectNotFound)
? project
: !(slugifiedProject instanceof ProjectNotFound)
? slugifiedProject
: null;
} catch (error) {}
existingProjectSpinner();
@@ -42,7 +52,7 @@ export default async function inputProject(
if (
await confirm(
`Found project ${chalk.cyan(
`${org.slug}/${detectedProjectName}`
`${org.slug}/${detectedProject.name}`
)}. Link to it?`,
true
)
@@ -74,7 +84,7 @@ export default async function inputProject(
continue;
}
const spinner = wait('Verifying project name…', 1000);
const spinner = output.spinner('Verifying project name…', 1000);
try {
project = await getProjectByIdOrName(client, projectName, org.id);
} finally {
@@ -97,7 +107,7 @@ export default async function inputProject(
type: 'input',
name: 'newProjectName',
message: `Whats your projects name?`,
default: !detectedProject ? detectedProjectName : undefined,
default: !detectedProject ? slugifiedName : undefined,
});
newProjectName = answers.newProjectName as string;
@@ -106,7 +116,7 @@ export default async function inputProject(
continue;
}
const spinner = wait('Verifying project name…', 1000);
const spinner = output.spinner('Verifying project name…', 1000);
let existingProject: Project | ProjectNotFound;
try {
existingProject = await getProjectByIdOrName(

View File

@@ -3,11 +3,12 @@ import inquirer from 'inquirer';
import getUser from '../get-user';
import getTeams from '../get-teams';
import { User, Team, Org } from '../../types';
import wait from '../output/wait';
import { Output } from '../output';
type Choice = { name: string; value: Org };
export default async function selectProject(
export default async function selectOrg(
output: Output,
question: string,
client: Client,
currentTeam?: string,
@@ -15,7 +16,7 @@ export default async function selectProject(
): Promise<Org> {
require('./patch-inquirer');
const spinner = wait('Loading scopes…', 1000);
const spinner = output.spinner('Loading scopes…', 1000);
let user: User;
let teams: Team[];
try {

View File

@@ -2,6 +2,7 @@ import chalk from 'chalk';
import boxen from 'boxen';
import { format } from 'util';
import { Console } from 'console';
import wait from './wait';
export type Output = ReturnType<typeof createOutput>;
@@ -76,6 +77,20 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
}
}
function spinner(message: string, delay: number = 300) {
if (debugEnabled) {
debug(`Spinner invoked (${message}) with a ${delay}ms delay`);
let isEnded = false;
return () => {
if (isEnded) return;
isEnded = true;
debug(`Spinner ended (${message})`);
};
}
return wait(message, delay);
}
// This is pretty hacky, but since we control the version of Node.js
// being used because of `pkg` it's safe to do in this case.
const c = {
@@ -109,5 +124,6 @@ export default function createOutput({ debug: debugEnabled = false } = {}) {
dim,
time,
note,
spinner,
};
}

View File

@@ -2,7 +2,7 @@ import ora from 'ora';
import chalk from 'chalk';
import eraseLines from './erase-lines';
export default function wait(msg: string, timeout: number = 300, _ora = ora) {
export default function wait(msg: string, delay: number = 300, _ora = ora) {
let spinner: ReturnType<typeof _ora>;
let running = false;
@@ -11,7 +11,7 @@ export default function wait(msg: string, timeout: number = 300, _ora = ora) {
spinner.color = 'gray';
spinner.start();
running = true;
}, timeout);
}, delay);
const cancel = () => {
clearTimeout(planned);

View File

@@ -12,7 +12,6 @@ import { Project } from '../../types';
import { Org, ProjectLink } from '../../types';
import chalk from 'chalk';
import { prependEmoji, emoji } from '../emoji';
import wait from '../output/wait';
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
@@ -86,7 +85,7 @@ export async function getLinkedOrg(
return { status: 'not_linked', org: null };
}
const spinner = wait('Retrieving scope…', 1000);
const spinner = output.spinner('Retrieving scope…', 1000);
try {
const org = await getOrgById(client, orgId);
@@ -141,7 +140,7 @@ export async function getLinkedProject(
return { status: 'not_linked', org: null, project: null };
}
const spinner = wait('Retrieving project…', 1000);
const spinner = output.spinner('Retrieving project…', 1000);
let org: Org | null;
let project: Project | ProjectNotFound | null;
try {

View File

@@ -1,5 +1,4 @@
import chalk from 'chalk';
import wait from '../output/wait';
import joinWords from '../output/join-words';
import * as Errors from '../errors-ts';
import { Output } from '../output';
@@ -17,7 +16,7 @@ export default async function patchDeploymentScale(
scaleArgs: ScaleArgs,
url: string
) {
const cancelWait = wait(
const cancelWait = output.spinner(
`Setting scale rules for ${joinWords(
Object.keys(scaleArgs).map(dc => `${chalk.bold(dc)}`)
)}`
@@ -28,7 +27,7 @@ export default async function patchDeploymentScale(
`/v3/now/deployments/${encodeURIComponent(deploymentId)}/instances`,
{
method: 'PATCH',
body: scaleArgs
body: scaleArgs,
}
);
cancelWait();

View File

@@ -4,7 +4,6 @@ import { Output } from '../output';
import * as ERRORS from '../errors-ts';
import Client from '../client';
import joinWords from '../output/join-words';
import wait from '../output/wait';
type ScaleArgs = {
min: number;
@@ -18,7 +17,7 @@ export default async function setScale(
scaleArgs: ScaleArgs | DeploymentScale,
url: string
) {
const cancelWait = wait(
const cancelWait = output.spinner(
`Setting scale rules for ${joinWords(
Object.keys(scaleArgs).map(dc => `${chalk.bold(dc)}`)
)}`
@@ -29,7 +28,7 @@ export default async function setScale(
`/v3/now/deployments/${encodeURIComponent(deploymentId)}/instances`,
{
method: 'PUT',
body: scaleArgs
body: scaleArgs,
}
);
cancelWait();

View File

@@ -9,7 +9,6 @@ import Client from '../client';
import joinWords from '../output/join-words';
import stamp from '../output/stamp';
import verifyDeploymentScale from './verify-deployment-scale';
import wait from '../output/wait';
export default async function waitForScale(
output: Output,
@@ -19,7 +18,7 @@ export default async function waitForScale(
) {
const remainingDCs = new Set(Object.keys(scale));
const scaleStamp = stamp();
let cancelWait = renderWaitDcs(Array.from(remainingDCs.keys()));
let cancelWait = renderWaitDcs(output, Array.from(remainingDCs.keys()));
for await (const dcReady of verifyDeploymentScale(
output,
@@ -43,13 +42,13 @@ export default async function waitForScale(
}
if (remainingDCs.size > 0) {
cancelWait = renderWaitDcs(Array.from(remainingDCs.keys()));
cancelWait = renderWaitDcs(output, Array.from(remainingDCs.keys()));
}
}
}
function renderWaitDcs(dcs: string[]) {
return wait(
function renderWaitDcs(output: Output, dcs: string[]) {
return output.spinner(
`Waiting for instances in ${joinWords(
dcs.map(dc => chalk.bold(dc))
)} to be ready`

View File

@@ -638,7 +638,7 @@ test(
await testPath(200, '/about/', 'About Page');
await testPath(200, '/sub/', 'Sub Index Page');
await testPath(200, '/sub/another/', 'Sub Another Page');
await testPath(200, '/style.css/', 'body { color: green }');
await testPath(200, '/style.css', 'body { color: green }');
await testPath(308, '/index.html', '', { Location: '/' });
await testPath(308, '/about.html', '', { Location: '/about/' });
await testPath(308, '/sub/index.html', '', { Location: '/sub/' });
@@ -653,17 +653,15 @@ test(
'[now dev] test trailingSlash true serve correct content',
testFixtureStdio('test-trailing-slash', async (t, port, testPath) => {
await testPath(200, '/', 'Index Page');
await testPath(200, '/index.html/', 'Index Page');
await testPath(200, '/about.html/', 'About Page');
await testPath(200, '/index.html', 'Index Page');
await testPath(200, '/about.html', 'About Page');
await testPath(200, '/sub/', 'Sub Index Page');
await testPath(200, '/sub/index.html/', 'Sub Index Page');
await testPath(200, '/sub/another.html/', 'Sub Another Page');
await testPath(200, '/style.css/', 'body { color: green }');
await testPath(308, '/about.html', '', { Location: '/about.html/' });
await testPath(200, '/sub/index.html', 'Sub Index Page');
await testPath(200, '/sub/another.html', 'Sub Another Page');
await testPath(200, '/style.css', 'body { color: green }');
await testPath(308, '/about.html/', '', { Location: '/about.html' });
await testPath(308, '/style.css/', '', { Location: '/style.css' });
await testPath(308, '/sub', '', { Location: '/sub/' });
await testPath(308, '/sub/another.html', '', {
Location: '/sub/another.html/',
});
})
);

View File

@@ -2149,54 +2149,6 @@ test('should show prompts to set up project', async t => {
t.is(text.includes('<h1>custom hello</h1>'), true, text);
});
test('should not prompt "project settings overwrite" for undetected projects', async t => {
const directory = fixture('static-deployment');
const projectName = `static-deployment-${
Math.random()
.toString(36)
.split('.')[1]
}`;
// remove previously linked project if it exists
await remove(path.join(directory, '.now'));
const now = execa(binaryPath, [directory, ...defaultArgs]);
await waitForPrompt(now, chunk => /Set up and deploy [^?]+\?/.test(chunk));
now.stdin.write('yes\n');
await waitForPrompt(now, chunk =>
chunk.includes('Which scope do you want to deploy to?')
);
now.stdin.write('\n');
await waitForPrompt(now, chunk =>
chunk.includes('Link to existing project?')
);
now.stdin.write('no\n');
await waitForPrompt(now, chunk =>
chunk.includes('Whats your projects name?')
);
now.stdin.write(`${projectName}\n`);
await waitForPrompt(now, chunk =>
chunk.includes('In which directory is your code located?')
);
now.stdin.write('\n');
await waitForPrompt(now, chunk => {
t.false(
chunk.includes('Want to override the settings?'),
'Should not ask to override'
);
return chunk.includes('Linked to');
});
const output = await now;
t.is(output.exitCode, 0, formatOutput(output));
});
test('should prefill "project name" prompt with folder name', async t => {
const projectName = `static-deployment-${
Math.random()
@@ -2237,6 +2189,11 @@ test('should prefill "project name" prompt with folder name', async t => {
);
now.stdin.write('\n');
await waitForPrompt(now, chunk =>
chunk.includes('Want to override the settings?')
);
now.stdin.write('no\n');
const output = await now;
t.is(output.exitCode, 0, formatOutput(output));
});
@@ -2292,6 +2249,11 @@ test('should prefill "project name" prompt with --name', async t => {
);
now.stdin.write('\n');
await waitForPrompt(now, chunk =>
chunk.includes('Want to override the settings?')
);
now.stdin.write('no\n');
const output = await now;
t.is(output.exitCode, 0, formatOutput(output));
});
@@ -2348,6 +2310,11 @@ test('should prefill "project name" prompt with now.json `name`', async t => {
);
now.stdin.write('\n');
await waitForPrompt(now, chunk =>
chunk.includes('Want to override the settings?')
);
now.stdin.write('no\n');
const output = await now;
t.is(output.exitCode, 0, formatOutput(output));

View File

@@ -1,6 +1,6 @@
{
"name": "now-client",
"version": "7.0.0-canary.3",
"version": "7.0.0",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://zeit.co",

View File

@@ -1,6 +1,6 @@
{
"name": "@now/go",
"version": "1.0.2-canary.0",
"version": "1.0.3",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/go",

View File

@@ -3,14 +3,24 @@ const path = require('path');
const {
packAndDeploy,
testDeployment
testDeployment,
} = require('../../../test/lib/deployment/test-deployment.js');
jest.setTimeout(4 * 60 * 1000);
const buildUtilsUrl = '@canary';
let buildUtilsUrl;
let builderUrl;
beforeAll(async () => {
if (!buildUtilsUrl) {
const buildUtilsPath = path.resolve(
__dirname,
'..',
'..',
'now-build-utils'
);
buildUtilsUrl = await packAndDeploy(buildUtilsPath);
console.log('buildUtilsUrl', buildUtilsUrl);
}
const builderPath = path.resolve(__dirname, '..');
builderUrl = await packAndDeploy(builderPath);
console.log('builderUrl', builderUrl);

View File

@@ -1,6 +1,6 @@
{
"name": "@now/next",
"version": "2.3.12",
"version": "2.3.13",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/next-js",

View File

@@ -1,6 +1,6 @@
{
"name": "@now/node",
"version": "1.4.0",
"version": "1.4.1",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/node-js",

View File

@@ -1,6 +1,6 @@
{
"name": "@now/python",
"version": "1.1.2-canary.0",
"version": "1.1.3",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/python",

View File

@@ -1,6 +1,6 @@
{
"name": "@now/routing-utils",
"version": "1.5.2-canary.4",
"version": "1.5.3",
"description": "ZEIT Now routing utilities",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",

View File

@@ -105,10 +105,15 @@ export function convertTrailingSlash(enable: boolean, status = 308): Route[] {
const routes: Route[] = [];
if (enable) {
routes.push({
src: '^/(.*[^\\/])$',
src: '^/((?:[^/]+/)*[^/\\.]+)$',
headers: { Location: '/$1/' },
status,
});
routes.push({
src: '^/((?:[^/]+/)*[^/]+\\.\\w+)/$',
headers: { Location: '/$1' },
status,
});
} else {
routes.push({
src: '^/(.*)\\/$',

View File

@@ -503,16 +503,41 @@ test('convertTrailingSlash enabled', () => {
const actual = convertTrailingSlash(true);
const expected = [
{
src: '^/(.*[^\\/])$',
src: '^/((?:[^/]+/)*[^/\\.]+)$',
headers: { Location: '/$1/' },
status: 308,
},
{
src: '^/((?:[^/]+/)*[^/]+\\.\\w+)/$',
headers: { Location: '/$1' },
status: 308,
},
];
deepEqual(actual, expected);
const mustMatch = [['/index.html', '/dir', '/dir/index.html', '/foo/bar']];
const mustMatch = [
['/dir', '/dir/foo', '/dir/foo/bar'],
['/foo.html/', '/dir/foo.html/', '/dir/foo/bar.css/', '/dir/about.map.js/'],
];
const mustNotMatch = [['/', '/dir/', '/dir/foo/', '/next.php?page=/']];
const mustNotMatch = [
[
'/',
'/index.html',
'/asset/style.css',
'/asset/about.map.js',
'/dir/',
'/dir/foo/',
'/next.php?page=/',
],
[
'/',
'/foo.html',
'/dir/foo.html',
'/dir/foo/bar.css',
'/dir/about.map.js',
],
];
assertRegexMatches(actual, mustMatch, mustNotMatch);
});

View File

@@ -1,7 +1,7 @@
{
"name": "@now/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.0.2-canary.0",
"version": "1.0.2",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/ruby",

View File

@@ -1,6 +1,6 @@
{
"name": "@now/static-build",
"version": "0.14.11-canary.2",
"version": "0.14.12",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://zeit.co/docs/runtimes#official-runtimes/static-builds",

View File

@@ -1,45 +1,56 @@
const { join } = require('path');
const { execSync } = require('child_process');
const fetch = require('node-fetch');
process.chdir(join(__dirname, '..'));
const commit = execSync('git log --pretty=format:"%s %H"')
.toString()
.trim()
.split('\n')
.find(line => line.startsWith('Publish Stable '))
.split(' ')
.pop();
async function main() {
const res = await fetch(
'https://api.github.com/repos/zeit/now/releases/latest'
);
const { tag_name } = await res.json();
if (!commit) {
throw new Error('Unable to find last publish commit');
// git log --pretty=format:"- %s [%an]" `git show-ref -s 'now@16.7.3'`...HEAD | grep -v '\- Publish '
if (!tag_name) {
throw new Error('Unable to find last GitHub Release tag.');
}
const log =
execSync(`git log --pretty=format:"- %s [%an]" ${tag_name}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => !line.startsWith('- Publish '))
.join('\n') || 'NO CHANGES DETECTED';
console.log(`Changes since the last stable release (${tag_name}):`);
console.log(`\n${log}\n`);
const pkgs =
Array.from(
new Set(
execSync(`git diff --name-only ${tag_name}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => line.startsWith('packages/'))
.map(line => line.split('/')[1])
.map(pkgName => {
try {
return require(`../packages/${pkgName}/package.json`).name;
} catch {
// Failed to read package.json (perhaps the pkg was deleted)
}
})
.filter(s => Boolean(s))
)
).join(',') || 'now';
console.log('To publish a stable release, execute the following:');
console.log(
`\nnpx lerna version --message 'Publish Stable' --exact --force-publish=${pkgs}\n`
);
}
const log =
execSync(`git log --pretty=format:"- %s [%an]" ${commit}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => !line.startsWith('- Publish Canary '))
.join('\n') || 'NO CHANGES DETECTED';
console.log(`Changes since the last Stable release (${commit.slice(0, 7)}):`);
console.log(`\n${log}\n`);
const pkgs =
Array.from(
new Set(
execSync(`git diff --name-only ${commit}...HEAD`)
.toString()
.trim()
.split('\n')
.filter(line => line.startsWith('packages/'))
.map(line => line.split('/')[1])
.map(pkgName => require(`../packages/${pkgName}/package.json`).name)
)
).join(',') || 'now';
console.log('To publish a stable release, execute the following:');
console.log(
`\ngit pull && lerna version --message 'Publish Stable' --exact --force-publish=${pkgs}\n`
);
main().catch(console.error);

View File

@@ -1363,6 +1363,14 @@
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
"@sindresorhus/slugify@0.10.0":
version "0.10.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/slugify/-/slugify-0.10.0.tgz#8878609a6a468a110690abbfb65171769cd9a8d4"
integrity sha512-R/3PVAS0rIbrH/qJRb4ma/5pG3oyQKW1Ws4bsc/Fscfb6HWeB0CNWD3bnPAiWi5PYLnl33TcsXCKXNOPwBpyaw==
dependencies:
escape-string-regexp "^2.0.0"
lodash.deburr "^4.1.0"
"@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.6.0.tgz#ec7670432ae9c8eb710400d112c201a362d83393"
@@ -1922,10 +1930,10 @@
"@types/webpack-sources" "*"
source-map "^0.6.0"
"@types/which@1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.1.tgz#7802c380887986ca909008afea4e08025b130f8d"
integrity sha512-ZrJDWpvg75LTGX4XwuneY9s6bF3OeZcGTpoGh3zDV9ytzcHMFsRrMIaLBRJZQMBoGyKs6unBQfVdrLZiYfb1zQ==
"@types/which@1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==
"@types/write-json-file@2.2.1":
version "2.2.1"
@@ -2042,10 +2050,10 @@
agentkeepalive "3.4.1"
debug "3.1.0"
"@zeit/fun@0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@zeit/fun/-/fun-0.11.0.tgz#e226af0a2b63020a0e233dd37a2ceb2ac2e68fe3"
integrity sha512-w9IqoMV6SIKVmQbocKKvllgL27im7YQfTFV/0hjIgASfi8yQgPIj7mo76VFosRS0HQA5MEIzYz+oigdelOTIOQ==
"@zeit/fun@0.11.2":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@zeit/fun/-/fun-0.11.2.tgz#a9ac34c8db09f8de40f7e727bdfde808c1be6505"
integrity sha512-1LoKTF2jq7YT3eATD/iTRuaTmvVtX3pWi3SVZPAgDTb70OLklpDkvVA/Z7dqP/WMB3gVGBdQNIhWfPTlBwrHEA==
dependencies:
async-listen "1.0.0"
debug "4.1.1"
@@ -3205,11 +3213,6 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chardet@^0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=
chardet@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
@@ -4735,15 +4738,6 @@ extend@~3.0.2:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
external-editor@^2.0.4:
version "2.2.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==
dependencies:
chardet "^0.4.0"
iconv-lite "^0.4.17"
tmp "^0.0.33"
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@@ -5756,7 +5750,7 @@ iconv-lite@0.4.19:
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==
iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@@ -5918,24 +5912,23 @@ init-package-json@^1.10.3:
validate-npm-package-license "^3.0.1"
validate-npm-package-name "^3.0.0"
inquirer@3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==
inquirer@7.0.4:
version "7.0.4"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703"
integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==
dependencies:
ansi-escapes "^3.0.0"
chalk "^2.0.0"
cli-cursor "^2.1.0"
ansi-escapes "^4.2.1"
chalk "^2.4.2"
cli-cursor "^3.1.0"
cli-width "^2.0.0"
external-editor "^2.0.4"
figures "^2.0.0"
lodash "^4.3.0"
mute-stream "0.0.7"
external-editor "^3.0.3"
figures "^3.0.0"
lodash "^4.17.15"
mute-stream "0.0.8"
run-async "^2.2.0"
rx-lite "^4.0.8"
rx-lite-aggregates "^4.0.8"
string-width "^2.1.0"
strip-ansi "^4.0.0"
rxjs "^6.5.3"
string-width "^4.1.0"
strip-ansi "^5.1.0"
through "^2.3.6"
inquirer@^6.2.0:
@@ -7217,6 +7210,11 @@ lodash.clonedeep@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.deburr@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-4.1.0.tgz#ddb1bbb3ef07458c0177ba07de14422cb033ff9b"
integrity sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=
lodash.flattendeep@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
@@ -7287,7 +7285,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.2.1, lodash@^4.3.0:
lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.2.1:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -9542,14 +9540,14 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rx-lite-aggregates@4.0.8, rx-lite-aggregates@^4.0.8:
rx-lite-aggregates@4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=
dependencies:
rx-lite "*"
rx-lite@*, rx-lite@^4.0.8:
rx-lite@*:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=
@@ -9561,6 +9559,13 @@ rxjs@^6.3.3, rxjs@^6.4.0:
dependencies:
tslib "^1.9.0"
rxjs@^6.5.3:
version "6.5.4"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
dependencies:
tslib "^1.9.0"
safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
@@ -9725,7 +9730,7 @@ shellwords@^0.1.1:
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
signal-exit@3.0.2, signal-exit@^3.0.0, signal-exit@^3.0.2:
signal-exit@3.0.2, signal-exit@TooTallNate/signal-exit#update/sighub-to-sigint-on-windows, signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2"
resolved "https://codeload.github.com/TooTallNate/signal-exit/tar.gz/58088fa7f715149f8411e089a4a6e3fe6ed265ec"
@@ -11116,13 +11121,20 @@ which-promise@1.0.0:
pinkie-promise "^1.0.0"
which "^1.1.2"
which@1, which@1.3.1, which@^1.1.2, which@^1.2.9, which@^1.3.0, which@^1.3.1:
which@1, which@^1.1.2, which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
which@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
which@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.1.tgz#f1cf94d07a8e571b6ff006aeb91d0300c47ef0a4"