netlify-cli 15.10.0 → 16.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/bin/run.mjs +6 -5
  2. package/npm-shrinkwrap.json +628 -42
  3. package/package.json +4 -5
  4. package/src/commands/base-command.mjs +295 -118
  5. package/src/commands/build/build.mjs +9 -1
  6. package/src/commands/deploy/deploy.mjs +42 -18
  7. package/src/commands/dev/dev.mjs +22 -17
  8. package/src/commands/functions/functions-create.mjs +118 -89
  9. package/src/commands/functions/functions-invoke.mjs +10 -7
  10. package/src/commands/functions/functions-list.mjs +3 -3
  11. package/src/commands/functions/functions-serve.mjs +1 -0
  12. package/src/commands/init/init.mjs +1 -1
  13. package/src/commands/link/link.mjs +5 -5
  14. package/src/commands/serve/serve.mjs +10 -6
  15. package/src/commands/sites/sites-create-template.mjs +1 -1
  16. package/src/commands/sites/sites-create.mjs +1 -1
  17. package/src/functions-templates/javascript/google-analytics/package.json +1 -1
  18. package/src/functions-templates/typescript/scheduled-function/package.json +1 -1
  19. package/src/lib/edge-functions/deploy.mjs +11 -4
  20. package/src/lib/edge-functions/internal.mjs +5 -3
  21. package/src/lib/edge-functions/proxy.mjs +29 -5
  22. package/src/lib/functions/netlify-function.mjs +26 -1
  23. package/src/lib/functions/registry.mjs +14 -26
  24. package/src/lib/functions/runtimes/js/builders/zisi.mjs +20 -3
  25. package/src/lib/functions/runtimes/js/worker.mjs +1 -1
  26. package/src/lib/functions/server.mjs +3 -2
  27. package/src/lib/spinner.mjs +1 -1
  28. package/src/recipes/vscode/index.mjs +24 -6
  29. package/src/utils/build-info.mjs +100 -0
  30. package/src/utils/command-helpers.mjs +16 -7
  31. package/src/utils/deploy/deploy-site.mjs +4 -4
  32. package/src/utils/deploy/hash-fns.mjs +2 -2
  33. package/src/utils/detect-server-settings.mjs +133 -245
  34. package/src/utils/framework-server.mjs +6 -5
  35. package/src/utils/functions/functions.mjs +8 -5
  36. package/src/utils/get-repo-data.mjs +5 -6
  37. package/src/utils/init/config-github.mjs +2 -2
  38. package/src/utils/init/config-manual.mjs +24 -7
  39. package/src/utils/init/utils.mjs +68 -68
  40. package/src/utils/proxy-server.mjs +7 -4
  41. package/src/utils/proxy.mjs +4 -3
  42. package/src/utils/read-repo-url.mjs +4 -0
  43. package/src/utils/run-build.mjs +58 -32
  44. package/src/utils/shell.mjs +24 -7
  45. package/src/utils/state-config.mjs +5 -1
  46. package/src/utils/static-server.mjs +4 -0
  47. package/src/utils/init/frameworks.mjs +0 -23
@@ -0,0 +1,100 @@
1
+ // @ts-check
2
+
3
+ import fuzzy from 'fuzzy'
4
+ import inquirer from 'inquirer'
5
+
6
+ import { chalk, log } from './command-helpers.mjs'
7
+
8
+ /**
9
+ * Filters the inquirer settings based on the input
10
+ * @param {ReturnType<typeof formatSettingsArrForInquirer>} scriptInquirerOptions
11
+ * @param {string} input
12
+ */
13
+ const filterSettings = function (scriptInquirerOptions, input) {
14
+ const filterOptions = scriptInquirerOptions.map((scriptInquirerOption) => scriptInquirerOption.name)
15
+ // TODO: remove once https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1394 is fixed
16
+ // eslint-disable-next-line unicorn/no-array-method-this-argument
17
+ const filteredSettings = fuzzy.filter(input, filterOptions)
18
+ const filteredSettingNames = new Set(
19
+ filteredSettings.map((filteredSetting) => (input ? filteredSetting.string : filteredSetting)),
20
+ )
21
+ return scriptInquirerOptions.filter((t) => filteredSettingNames.has(t.name))
22
+ }
23
+
24
+ /** @typedef {import('@netlify/build-info').Settings} Settings */
25
+
26
+ /**
27
+ * @param {Settings[]} settings
28
+ * @param {'dev' | 'build'} type The type of command (dev or build)
29
+ */
30
+ const formatSettingsArrForInquirer = function (settings, type = 'dev') {
31
+ return settings.map((setting) => {
32
+ const cmd = type === 'dev' ? setting.devCommand : setting.buildCommand
33
+ return {
34
+ name: `[${chalk.yellow(setting.framework.name)}] '${cmd}'`,
35
+ value: { ...setting, commands: [cmd] },
36
+ short: `${setting.name}-${cmd}`,
37
+ }
38
+ })
39
+ }
40
+
41
+ /**
42
+ * Uses @netlify/build-info to detect the dev settings and port based on the framework
43
+ * and the build system that is used.
44
+ * @param {import('../commands/base-command.mjs').default} command
45
+ * @param {'dev' | 'build'} type The type of command (dev or build)
46
+ * @returns {Promise<Settings | undefined>}
47
+ */
48
+ export const detectFrameworkSettings = async (command, type = 'dev') => {
49
+ const { relConfigFilePath } = command.netlify
50
+ const settings = await detectBuildSettings(command)
51
+ if (settings.length === 1) {
52
+ return settings[0]
53
+ }
54
+
55
+ if (settings.length > 1) {
56
+ /** multiple matching detectors, make the user choose */
57
+ const scriptInquirerOptions = formatSettingsArrForInquirer(settings, type)
58
+ /** @type {{chosenSettings: Settings}} */
59
+ const { chosenSettings } = await inquirer.prompt({
60
+ name: 'chosenSettings',
61
+ message: `Multiple possible ${type} commands found`,
62
+ type: 'autocomplete',
63
+ source(/** @type {string} */ _, input = '') {
64
+ if (!input) return scriptInquirerOptions
65
+ // only show filtered results
66
+ return filterSettings(scriptInquirerOptions, input)
67
+ },
68
+ })
69
+
70
+ log(`
71
+ Update your ${relConfigFilePath} to avoid this selection prompt next time:
72
+
73
+ [build]
74
+ command = "${chosenSettings.buildCommand}"
75
+ publish = "${chosenSettings.dist}"
76
+
77
+ [dev]
78
+ command = "${chosenSettings.devCommand}"
79
+ `)
80
+ return chosenSettings
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Detects and filters the build setting for a project and a command
86
+ * @param {import('../commands/base-command.mjs').default} command
87
+ */
88
+ export const detectBuildSettings = async (command) => {
89
+ const { project, workspacePackage } = command
90
+ const buildSettings = await project.getBuildSettings(project.workspace ? workspacePackage : '')
91
+ return buildSettings
92
+ .filter((setting) => {
93
+ if (project.workspace && project.relativeBaseDirectory && setting.packagePath) {
94
+ return project.relativeBaseDirectory.startsWith(setting.packagePath)
95
+ }
96
+
97
+ return true
98
+ })
99
+ .filter((setting) => setting.devCommand)
100
+ }
@@ -24,7 +24,7 @@ const argv = process.argv.slice(2)
24
24
  * Chalk instance for CLI that can be initialized with no colors mode
25
25
  * needed for json outputs where we don't want to have colors
26
26
  * @param {boolean} noColors - disable chalk colors
27
- * @return {object} - default or custom chalk instance
27
+ * @return {import('chalk').ChalkInstance} - default or custom chalk instance
28
28
  */
29
29
  const safeChalk = function (noColors) {
30
30
  if (noColors) {
@@ -174,12 +174,18 @@ export const warn = (message = '') => {
174
174
 
175
175
  /**
176
176
  * throws an error or log it
177
- * @param {string|Error} message
177
+ * @param {unknown} message
178
178
  * @param {object} [options]
179
179
  * @param {boolean} [options.exit]
180
180
  */
181
181
  export const error = (message = '', options = {}) => {
182
- const err = message instanceof Error ? message : new Error(message)
182
+ const err =
183
+ message instanceof Error
184
+ ? message
185
+ : // eslint-disable-next-line unicorn/no-nested-ternary
186
+ typeof message === 'string'
187
+ ? new Error(message)
188
+ : /** @type {Error} */ ({ message, stack: undefined, name: 'Error' })
183
189
 
184
190
  if (options.exit === false) {
185
191
  const bang = chalk.red(BANG)
@@ -198,10 +204,13 @@ export const exit = (code = 0) => {
198
204
  process.exit(code)
199
205
  }
200
206
 
201
- // When `build.publish` is not set by the user, the CLI behavior differs in
202
- // several ways. It detects it by checking if `build.publish` is `undefined`.
203
- // However, `@netlify/config` adds a default value to `build.publish`.
204
- // This removes 'publish' and 'publishOrigin' in this case.
207
+ /**
208
+ * When `build.publish` is not set by the user, the CLI behavior differs in
209
+ * several ways. It detects it by checking if `build.publish` is `undefined`.
210
+ * However, `@netlify/config` adds a default value to `build.publish`.
211
+ * This removes 'publish' and 'publishOrigin' in this case.
212
+ * @param {*} config
213
+ */
205
214
  export const normalizeConfig = (config) => {
206
215
  // Unused var here is in order to omit 'publish' from build config
207
216
  // eslint-disable-next-line no-unused-vars
@@ -39,7 +39,6 @@ export const deploySite = async (
39
39
  maxRetry = DEFAULT_MAX_RETRY,
40
40
  // API calls this the 'title'
41
41
  message: title,
42
- rootDir,
43
42
  siteEnv,
44
43
  skipFunctionsCache,
45
44
  statusCb = () => {
@@ -47,6 +46,7 @@ export const deploySite = async (
47
46
  },
48
47
  syncFileLimit = DEFAULT_SYNC_LIMIT,
49
48
  tmpDir = temporaryDirectory(),
49
+ workingDir,
50
50
  } = {},
51
51
  ) => {
52
52
  statusCb({
@@ -55,7 +55,7 @@ export const deploySite = async (
55
55
  phase: 'start',
56
56
  })
57
57
 
58
- const edgeFunctionsDistPath = await getDistPathIfExists({ rootDir })
58
+ const edgeFunctionsDistPath = await getDistPathIfExists(workingDir)
59
59
  const [{ files, filesShaMap }, { fnConfig, fnShaMap, functionSchedules, functions, functionsWithNativeModules }] =
60
60
  await Promise.all([
61
61
  hashFiles({
@@ -64,7 +64,7 @@ export const deploySite = async (
64
64
  directories: [configPath, dir, edgeFunctionsDistPath].filter(Boolean),
65
65
  filter,
66
66
  hashAlgorithm,
67
- normalizer: deployFileNormalizer.bind(null, rootDir),
67
+ normalizer: deployFileNormalizer.bind(null, workingDir),
68
68
  statusCb,
69
69
  }),
70
70
  hashFns(fnDir, {
@@ -74,7 +74,7 @@ export const deploySite = async (
74
74
  hashAlgorithm,
75
75
  statusCb,
76
76
  assetType,
77
- rootDir,
77
+ workingDir,
78
78
  manifestPath,
79
79
  skipFunctionsCache,
80
80
  siteEnv,
@@ -20,10 +20,10 @@ const getFunctionZips = async ({
20
20
  directories,
21
21
  functionsConfig,
22
22
  manifestPath,
23
- rootDir,
24
23
  skipFunctionsCache,
25
24
  statusCb,
26
25
  tmpDir,
26
+ workingDir,
27
27
  }) => {
28
28
  statusCb({
29
29
  type: 'functions-manifest',
@@ -68,7 +68,7 @@ const getFunctionZips = async ({
68
68
  }
69
69
 
70
70
  return await zipFunctions(directories, tmpDir, {
71
- basePath: rootDir,
71
+ basePath: workingDir,
72
72
  configFileDirectories: [getPathInProject([INTERNAL_FUNCTIONS_FOLDER])],
73
73
  config: functionsConfig,
74
74
  })