netlify-cli 8.0.10 → 8.1.0-rc

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 (183) hide show
  1. package/bin/run +81 -3
  2. package/npm-shrinkwrap.json +471 -2182
  3. package/package.json +12 -35
  4. package/src/commands/addons/addons-auth.js +50 -0
  5. package/src/commands/addons/addons-config.js +180 -0
  6. package/src/commands/addons/addons-create.js +129 -0
  7. package/src/commands/addons/addons-delete.js +59 -0
  8. package/src/commands/addons/addons-list.js +62 -0
  9. package/src/commands/addons/addons.js +49 -0
  10. package/src/commands/addons/index.js +3 -24
  11. package/src/commands/api/api.js +83 -0
  12. package/src/commands/api/index.js +5 -0
  13. package/src/commands/base-command.js +322 -0
  14. package/src/commands/build/build.js +58 -0
  15. package/src/commands/build/index.js +3 -61
  16. package/src/commands/completion/completion.js +18 -0
  17. package/src/commands/completion/index.js +5 -0
  18. package/src/commands/{deploy.js → deploy/deploy.js} +306 -278
  19. package/src/commands/deploy/index.js +5 -0
  20. package/src/commands/dev/dev-exec.js +39 -0
  21. package/src/commands/dev/dev-trace.js +50 -0
  22. package/src/commands/dev/dev.js +349 -0
  23. package/src/commands/dev/index.js +3 -335
  24. package/src/commands/env/env-get.js +51 -0
  25. package/src/commands/env/env-import.js +93 -0
  26. package/src/commands/env/env-list.js +63 -0
  27. package/src/commands/env/env-set.js +67 -0
  28. package/src/commands/env/env-unset.js +66 -0
  29. package/src/commands/env/env.js +47 -0
  30. package/src/commands/env/index.js +3 -23
  31. package/src/commands/functions/functions-build.js +59 -0
  32. package/src/commands/functions/{create.js → functions-create.js} +133 -94
  33. package/src/commands/functions/functions-invoke.js +276 -0
  34. package/src/commands/functions/functions-list.js +107 -0
  35. package/src/commands/functions/functions-serve.js +63 -0
  36. package/src/commands/functions/functions.js +53 -0
  37. package/src/commands/functions/index.js +3 -45
  38. package/src/commands/index.js +5 -0
  39. package/src/commands/init/index.js +6 -0
  40. package/src/commands/{init.js → init/init.js} +79 -68
  41. package/src/commands/link/index.js +6 -0
  42. package/src/{utils/link/link-by-prompt.js → commands/link/link.js} +153 -14
  43. package/src/commands/lm/index.js +3 -19
  44. package/src/commands/lm/lm-info.js +42 -0
  45. package/src/commands/lm/lm-install.js +36 -0
  46. package/src/commands/lm/lm-setup.js +106 -0
  47. package/src/commands/lm/lm-uninstall.js +25 -0
  48. package/src/commands/lm/lm.js +39 -0
  49. package/src/commands/login/index.js +6 -0
  50. package/src/commands/login/login.js +52 -0
  51. package/src/commands/logout/index.js +5 -0
  52. package/src/commands/logout/logout.js +43 -0
  53. package/src/commands/main.js +117 -0
  54. package/src/commands/open/index.js +3 -39
  55. package/src/commands/open/open-admin.js +56 -0
  56. package/src/commands/open/open-site.js +49 -0
  57. package/src/commands/open/open.js +42 -0
  58. package/src/commands/sites/index.js +5 -20
  59. package/src/commands/sites/sites-create.js +184 -0
  60. package/src/commands/sites/sites-delete.js +108 -0
  61. package/src/commands/sites/sites-list.js +89 -0
  62. package/src/commands/sites/sites.js +36 -0
  63. package/src/commands/status/index.js +3 -118
  64. package/src/commands/status/status-hooks.js +73 -0
  65. package/src/commands/status/status.js +125 -0
  66. package/src/commands/switch/index.js +5 -0
  67. package/src/commands/switch/switch.js +50 -0
  68. package/src/commands/unlink/index.js +5 -0
  69. package/src/commands/unlink/unlink.js +48 -0
  70. package/src/commands/watch/index.js +5 -0
  71. package/src/commands/watch/watch.js +121 -0
  72. package/src/lib/build.js +21 -7
  73. package/src/lib/exec-fetcher.js +5 -3
  74. package/src/lib/fs.js +54 -36
  75. package/src/lib/functions/background.js +1 -1
  76. package/src/lib/functions/form-submissions-handler.js +2 -1
  77. package/src/lib/functions/local-proxy.js +2 -1
  78. package/src/lib/functions/netlify-function.js +4 -1
  79. package/src/lib/functions/registry.js +4 -6
  80. package/src/lib/functions/runtimes/go/index.js +2 -1
  81. package/src/lib/functions/runtimes/js/builders/netlify-lambda.js +6 -4
  82. package/src/lib/functions/runtimes/js/builders/zisi.js +3 -3
  83. package/src/lib/functions/runtimes/rust/index.js +4 -3
  84. package/src/lib/functions/server.js +2 -3
  85. package/src/lib/functions/synchronous.js +2 -1
  86. package/src/lib/functions/utils.js +2 -3
  87. package/src/lib/functions/watcher.js +1 -0
  88. package/src/lib/http-agent.js +5 -5
  89. package/src/lib/log.js +2 -1
  90. package/src/lib/spinner.js +22 -0
  91. package/src/utils/addons/diffs/index.js +1 -0
  92. package/src/utils/addons/diffs/options.js +3 -1
  93. package/src/utils/addons/prepare.js +13 -6
  94. package/src/utils/addons/prompts.js +2 -1
  95. package/src/utils/addons/render.js +3 -1
  96. package/src/utils/command-helpers.js +156 -43
  97. package/src/utils/create-stream-promise.js +5 -5
  98. package/src/utils/deferred.js +1 -0
  99. package/src/utils/deploy/deploy-site.js +1 -1
  100. package/src/utils/deploy/index.js +4 -0
  101. package/src/utils/detect-server-settings.js +10 -12
  102. package/src/utils/dev.js +18 -10
  103. package/src/utils/dot-env.js +4 -2
  104. package/src/utils/{edge-handlers.js → functions/edge-handlers.js} +8 -7
  105. package/src/utils/functions/functions.js +36 -0
  106. package/src/utils/{get-functions.js → functions/get-functions.js} +2 -1
  107. package/src/utils/functions/index.js +8 -26
  108. package/src/utils/get-global-config.js +3 -2
  109. package/src/utils/get-repo-data.js +1 -0
  110. package/src/utils/gh-auth.js +1 -0
  111. package/src/utils/gitignore.js +7 -5
  112. package/src/utils/header.js +2 -2
  113. package/src/utils/headers.js +1 -2
  114. package/src/utils/index.js +42 -0
  115. package/src/utils/init/config-github.js +12 -5
  116. package/src/utils/init/config-manual.js +9 -2
  117. package/src/utils/init/config.js +13 -7
  118. package/src/utils/init/frameworks.js +1 -0
  119. package/src/utils/init/node-version.js +4 -2
  120. package/src/utils/init/plugins.js +1 -0
  121. package/src/utils/init/utils.js +10 -6
  122. package/src/utils/live-tunnel.js +3 -4
  123. package/src/utils/lm/install.js +10 -15
  124. package/src/utils/lm/requirements.js +3 -1
  125. package/src/utils/lm/steps.js +1 -1
  126. package/src/utils/lm/ui.js +7 -3
  127. package/src/utils/open-browser.js +8 -2
  128. package/src/utils/parse-raw-flags.js +4 -4
  129. package/src/utils/proxy.js +7 -5
  130. package/src/utils/read-repo-url.js +1 -0
  131. package/src/utils/redirects.js +2 -2
  132. package/src/utils/rules-proxy.js +4 -2
  133. package/src/utils/state-config.js +1 -1
  134. package/src/utils/telemetry/index.js +2 -113
  135. package/src/utils/telemetry/request.js +3 -1
  136. package/src/utils/telemetry/telemetry.js +117 -0
  137. package/src/utils/telemetry/validation.js +13 -12
  138. package/src/utils/traffic-mesh.js +3 -3
  139. package/oclif.manifest.json +0 -1
  140. package/src/commands/addons/auth.js +0 -42
  141. package/src/commands/addons/config.js +0 -177
  142. package/src/commands/addons/create.js +0 -127
  143. package/src/commands/addons/delete.js +0 -69
  144. package/src/commands/addons/list.js +0 -54
  145. package/src/commands/api.js +0 -84
  146. package/src/commands/dev/exec.js +0 -32
  147. package/src/commands/dev/trace.js +0 -61
  148. package/src/commands/env/get.js +0 -44
  149. package/src/commands/env/import.js +0 -90
  150. package/src/commands/env/list.js +0 -49
  151. package/src/commands/env/set.js +0 -64
  152. package/src/commands/env/unset.js +0 -58
  153. package/src/commands/functions/build.js +0 -60
  154. package/src/commands/functions/invoke.js +0 -277
  155. package/src/commands/functions/list.js +0 -102
  156. package/src/commands/functions/serve.js +0 -70
  157. package/src/commands/link.js +0 -133
  158. package/src/commands/lm/info.js +0 -36
  159. package/src/commands/lm/install.js +0 -30
  160. package/src/commands/lm/setup.js +0 -107
  161. package/src/commands/lm/uninstall.js +0 -17
  162. package/src/commands/login.js +0 -54
  163. package/src/commands/logout.js +0 -37
  164. package/src/commands/open/admin.js +0 -51
  165. package/src/commands/open/site.js +0 -43
  166. package/src/commands/sites/create.js +0 -191
  167. package/src/commands/sites/delete.js +0 -116
  168. package/src/commands/sites/list.js +0 -84
  169. package/src/commands/status/hooks.js +0 -60
  170. package/src/commands/switch.js +0 -44
  171. package/src/commands/unlink.js +0 -38
  172. package/src/commands/watch.js +0 -115
  173. package/src/hooks/init.js +0 -46
  174. package/src/index.js +0 -25
  175. package/src/lib/help.js +0 -26
  176. package/src/utils/chalk.js +0 -16
  177. package/src/utils/check-command-inputs.js +0 -21
  178. package/src/utils/command.js +0 -261
  179. package/src/utils/detect-functions-builder.js +0 -25
  180. package/src/utils/difference.js +0 -4
  181. package/src/utils/logo.js +0 -11
  182. package/src/utils/show-help.js +0 -5
  183. package/src/utils/telemetry/tracked-command.js +0 -51
@@ -0,0 +1,47 @@
1
+ const { generateCommandsHelp, generateExamplesHelp } = require('../../utils')
2
+
3
+ const { createEnvGetCommand } = require('./env-get')
4
+ const { createEnvImportCommand } = require('./env-import')
5
+ const { createEnvListCommand } = require('./env-list')
6
+ const { createEnvSetCommand } = require('./env-set')
7
+ const { createEnvUnsetCommand } = require('./env-unset')
8
+
9
+ /**
10
+ * The env command
11
+ * @param {import('commander').OptionValues} options
12
+ * @param {import('../base-command').BaseCommand} command
13
+ */
14
+ const env = (options, command) => {
15
+ command.help()
16
+ }
17
+
18
+ /**
19
+ * Creates the `netlify env` command
20
+ * @param {import('../base-command').BaseCommand} program
21
+ * @returns
22
+ */
23
+ const createEnvCommand = (program) => {
24
+ createEnvGetCommand(program)
25
+ createEnvImportCommand(program)
26
+ createEnvListCommand(program)
27
+ createEnvSetCommand(program)
28
+ createEnvUnsetCommand(program)
29
+
30
+ return program
31
+ .command('env')
32
+ .description('(Beta) Control environment variables for the current site')
33
+ .addHelpText(
34
+ 'after',
35
+ generateExamplesHelp([
36
+ 'netlify env:list',
37
+ 'netlify env:get VAR_NAME',
38
+ 'netlify env:set VAR_NAME value',
39
+ 'netlify env:unset VAR_NAME',
40
+ 'netlify env:import fileName',
41
+ ]),
42
+ )
43
+ .addHelpText('after', generateCommandsHelp('env', program))
44
+ .action(env)
45
+ }
46
+
47
+ module.exports = { createEnvCommand }
@@ -1,25 +1,5 @@
1
- const { isEmptyCommand } = require('../../utils/check-command-inputs')
2
- const Command = require('../../utils/command')
3
- const showHelp = require('../../utils/show-help')
1
+ const { createEnvCommand } = require('./env')
4
2
 
5
- class EnvCommand extends Command {
6
- run() {
7
- const { args, flags } = this.parse(EnvCommand)
8
-
9
- // Show help on empty sub command
10
- if (isEmptyCommand(flags, args)) {
11
- showHelp(this.id)
12
- }
13
- }
3
+ module.exports = {
4
+ createEnvCommand,
14
5
  }
15
-
16
- EnvCommand.description = `(Beta) Control environment variables for the current site`
17
- EnvCommand.examples = [
18
- 'netlify env:list',
19
- 'netlify env:get VAR_NAME',
20
- 'netlify env:set VAR_NAME value',
21
- 'netlify env:unset VAR_NAME',
22
- 'netlify env:import fileName',
23
- ]
24
-
25
- module.exports = EnvCommand
@@ -0,0 +1,59 @@
1
+ // @ts-check
2
+
3
+ const { mkdir } = require('fs').promises
4
+
5
+ const { zipFunctions } = require('@netlify/zip-it-and-ship-it')
6
+
7
+ const { NETLIFYDEVERR, NETLIFYDEVLOG, exit, getFunctionsDir, log } = require('../../utils')
8
+
9
+ /**
10
+ * The functions:build command
11
+ * @param {import('commander').OptionValues} options
12
+ * @param {import('../base-command').BaseCommand} command
13
+ */
14
+ const functionsBuild = async (options, command) => {
15
+ const { config } = command.netlify
16
+
17
+ const src = options.src || config.build.functionsSource
18
+ const dst = getFunctionsDir({ options, config })
19
+
20
+ if (src === dst) {
21
+ log(`${NETLIFYDEVERR} Source and destination for function build can't be the same`)
22
+ exit(1)
23
+ }
24
+
25
+ if (!src || !dst) {
26
+ if (!src)
27
+ log(
28
+ `${NETLIFYDEVERR} Error: You must specify a source folder with a --src flag or a functionsSource field in your config`,
29
+ )
30
+ if (!dst)
31
+ log(
32
+ `${NETLIFYDEVERR} Error: You must specify a destination functions folder with a --functions flag or a functions field in your config`,
33
+ )
34
+ exit(1)
35
+ }
36
+
37
+ await mkdir(dst, { recursive: true })
38
+
39
+ log(`${NETLIFYDEVLOG} Building functions`)
40
+ // @ts-ignore Seems that the typings of zip it and ship it are not correct
41
+ zipFunctions(src, dst, { skipGo: true })
42
+ log(`${NETLIFYDEVLOG} Functions built to `, dst)
43
+ }
44
+
45
+ /**
46
+ * Creates the `netlify functions:build` command
47
+ * @param {import('../base-command').BaseCommand} program
48
+ * @returns
49
+ */
50
+ const createFunctionsBuildCommand = (program) =>
51
+ program
52
+ .command('functions:build')
53
+ .alias('function:build')
54
+ .description('Build functions locally')
55
+ .option('-f, --function <directory>', 'Specify a functions directory to build to')
56
+ .option('-s, --src <directory>', 'Specify the source directory for the functions')
57
+ .action(functionsBuild)
58
+
59
+ module.exports = { createFunctionsBuildCommand }
@@ -1,13 +1,12 @@
1
+ // @ts-check
1
2
  const cp = require('child_process')
2
3
  const fs = require('fs')
4
+ const { mkdir } = require('fs').promises
3
5
  const path = require('path')
4
6
  const process = require('process')
5
7
  const { promisify } = require('util')
6
8
 
7
- const { flags: flagsLib } = require('@oclif/command')
8
- const chalk = require('chalk')
9
9
  const copy = promisify(require('copy-template-dir'))
10
- const execa = require('execa')
11
10
  const findUp = require('find-up')
12
11
  const fuzzy = require('fuzzy')
13
12
  const inquirer = require('inquirer')
@@ -15,13 +14,20 @@ const inquirerAutocompletePrompt = require('inquirer-autocomplete-prompt')
15
14
  const fetch = require('node-fetch')
16
15
  const ora = require('ora')
17
16
 
18
- const { mkdirRecursiveSync } = require('../../lib/fs')
17
+ const {
18
+ NETLIFYDEVERR,
19
+ NETLIFYDEVLOG,
20
+ NETLIFYDEVWARN,
21
+ chalk,
22
+ error,
23
+ execa,
24
+ generateExamplesHelp,
25
+ injectEnvVariables,
26
+ log,
27
+ readRepoURL,
28
+ validateRepoURL,
29
+ } = require('../../utils')
19
30
  const { getAddons, getCurrentAddon, getSiteData } = require('../../utils/addons/prepare')
20
- const Command = require('../../utils/command')
21
- const { error, log } = require('../../utils/command-helpers')
22
- const { injectEnvVariables } = require('../../utils/dev')
23
- const { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN } = require('../../utils/logo')
24
- const { readRepoURL, validateRepoURL } = require('../../utils/read-repo-url')
25
31
 
26
32
  const templatesDir = path.resolve(__dirname, '../../functions-templates')
27
33
 
@@ -37,58 +43,22 @@ const languages = [
37
43
  ]
38
44
 
39
45
  /**
40
- * Be very clear what is the SOURCE (templates dir) vs the DEST (functions dir)
46
+ * prompt for a name if name not supplied
47
+ * @param {string} argumentName
48
+ * @param {import('commander').OptionValues} options
49
+ * @param {string} [defaultName]
50
+ * @returns
41
51
  */
42
- class FunctionsCreateCommand extends Command {
43
- async run() {
44
- const { args, flags } = this.parse(FunctionsCreateCommand)
45
-
46
- const functionsDir = await ensureFunctionDirExists(this)
47
-
48
- /* either download from URL or scaffold from template */
49
- const mainFunc = flags.url ? downloadFromURL : scaffoldFromTemplate
50
- await mainFunc(this, flags, args, functionsDir)
51
- }
52
- }
53
-
54
- FunctionsCreateCommand.args = [
55
- {
56
- name: 'name',
57
- description: 'name of your new function file inside your functions directory',
58
- },
59
- ]
60
-
61
- FunctionsCreateCommand.description = `Create a new function locally`
62
-
63
- FunctionsCreateCommand.examples = [
64
- 'netlify functions:create',
65
- 'netlify functions:create hello-world',
66
- 'netlify functions:create --name hello-world',
67
- ]
68
- FunctionsCreateCommand.aliases = ['function:create']
69
- FunctionsCreateCommand.flags = {
70
- name: flagsLib.string({ char: 'n', description: 'function name' }),
71
- url: flagsLib.string({ char: 'u', description: 'pull template from URL' }),
72
- language: flagsLib.string({ char: 'l', description: 'function language' }),
73
- ...FunctionsCreateCommand.flags,
74
- }
75
- module.exports = FunctionsCreateCommand
76
-
77
- /**
78
- * all subsections of code called from the main logic flow above
79
- */
80
-
81
- // prompt for a name if name not supplied
82
- const getNameFromArgs = async function (args, flags, defaultName) {
83
- if (flags.name) {
84
- if (args.name) {
52
+ const getNameFromArgs = async function (argumentName, options, defaultName) {
53
+ if (options.name) {
54
+ if (argumentName) {
85
55
  throw new Error('function name specified in both flag and arg format, pick one')
86
56
  }
87
- return flags.name
57
+ return options.name
88
58
  }
89
59
 
90
- if (args.name) {
91
- return args.name
60
+ if (argumentName) {
61
+ return argumentName
92
62
  }
93
63
 
94
64
  const { name } = await inquirer.prompt([
@@ -155,7 +125,10 @@ const formatRegistryArrayForInquirer = function (lang) {
155
125
  return registry
156
126
  }
157
127
 
158
- // pick template from our existing templates
128
+ /**
129
+ * pick template from our existing templates
130
+ * @param {import('commander').OptionValues} config
131
+ */
159
132
  const pickTemplate = async function ({ language: languageFromFlag }) {
160
133
  const specialCommands = [
161
134
  new inquirer.Separator(),
@@ -218,11 +191,11 @@ const DEFAULT_PRIORITY = 999
218
191
 
219
192
  /**
220
193
  * Get functions directory (and make it if necessary)
221
- * @param {FunctionsCreateCommand} context
222
- * @returns {string | never} - functions directory or throws an error
194
+ * @param {import('../base-command').BaseCommand} command
195
+ * @returns {Promise<string|never>} - functions directory or throws an error
223
196
  */
224
- const ensureFunctionDirExists = async function (context) {
225
- const { api, config, site } = context.netlify
197
+ const ensureFunctionDirExists = async function (command) {
198
+ const { api, config, site } = command.netlify
226
199
  const siteId = site.id
227
200
  let functionsDirHolder = config.functionsDirectory
228
201
 
@@ -248,6 +221,7 @@ const ensureFunctionDirExists = async function (context) {
248
221
  try {
249
222
  log(`${NETLIFYDEVLOG} updating site settings with ${chalk.magenta.inverse(functionsDirHolder)}`)
250
223
 
224
+ // @ts-ignore Typings of API are not correct
251
225
  await api.updateSite({
252
226
  siteId: site.id,
253
227
  body: {
@@ -278,11 +252,17 @@ const ensureFunctionDirExists = async function (context) {
278
252
  return functionsDirHolder
279
253
  }
280
254
 
281
- // Download files from a given github URL
282
- const downloadFromURL = async function (context, flags, args, functionsDir) {
283
- const folderContents = await readRepoURL(flags.url)
284
- const [functionName] = flags.url.split('/').slice(-1)
285
- const nameToUse = await getNameFromArgs(args, flags, functionName)
255
+ /**
256
+ * Download files from a given github URL
257
+ * @param {import('../base-command').BaseCommand} command
258
+ * @param {import('commander').OptionValues} options
259
+ * @param {string} argumentName
260
+ * @param {string} functionsDir
261
+ */
262
+ const downloadFromURL = async function (command, options, argumentName, functionsDir) {
263
+ const folderContents = await readRepoURL(options.url)
264
+ const [functionName] = options.url.split('/').slice(-1)
265
+ const nameToUse = await getNameFromArgs(argumentName, options, functionName)
286
266
 
287
267
  const fnFolder = path.join(functionsDir, nameToUse)
288
268
  if (fs.existsSync(`${fnFolder}.js`) && fs.lstatSync(`${fnFolder}.js`).isFile()) {
@@ -293,7 +273,7 @@ const downloadFromURL = async function (context, flags, args, functionsDir) {
293
273
  }
294
274
 
295
275
  try {
296
- mkdirRecursiveSync(fnFolder)
276
+ await mkdir(fnFolder, { recursive: true })
297
277
  } catch {
298
278
  // Ignore
299
279
  }
@@ -321,8 +301,8 @@ const downloadFromURL = async function (context, flags, args, functionsDir) {
321
301
  // eslint-disable-next-line node/global-require, import/no-dynamic-require
322
302
  const { onComplete, addons = [] } = require(fnTemplateFile)
323
303
 
324
- await installAddons(context, addons, path.resolve(fnFolder))
325
- await handleOnComplete({ context, onComplete })
304
+ await installAddons(command, addons, path.resolve(fnFolder))
305
+ await handleOnComplete({ command, onComplete })
326
306
  // delete
327
307
  fs.unlinkSync(fnTemplateFile)
328
308
  }
@@ -385,10 +365,16 @@ const installDeps = async ({ functionPackageJson, functionPath, functionsDir })
385
365
  }
386
366
  }
387
367
 
388
- // no --url flag specified, pick from a provided template
389
- const scaffoldFromTemplate = async function (context, flags, args, functionsDir) {
368
+ /**
369
+ * no --url flag specified, pick from a provided template
370
+ * @param {import('../base-command').BaseCommand} command
371
+ * @param {import('commander').OptionValues} options
372
+ * @param {string} argumentName
373
+ * @param {string} functionsDir
374
+ */
375
+ const scaffoldFromTemplate = async function (command, options, argumentName, functionsDir) {
390
376
  // pull the rest of the metadata from the template
391
- const chosenTemplate = await pickTemplate(flags)
377
+ const chosenTemplate = await pickTemplate(options)
392
378
  if (chosenTemplate === 'url') {
393
379
  const { chosenUrl } = await inquirer.prompt([
394
380
  {
@@ -400,11 +386,11 @@ const scaffoldFromTemplate = async function (context, flags, args, functionsDir)
400
386
  // this has some nuance i have ignored, eg crossenv and i18n concerns
401
387
  },
402
388
  ])
403
- flags.url = chosenUrl.trim()
389
+ options.url = chosenUrl.trim()
404
390
  try {
405
- await downloadFromURL(context, flags, args, functionsDir)
391
+ await downloadFromURL(command, options, argumentName, functionsDir)
406
392
  } catch (error_) {
407
- error(`$${NETLIFYDEVERR} Error downloading from URL: ${flags.url}`)
393
+ error(`$${NETLIFYDEVERR} Error downloading from URL: ${options.url}`)
408
394
  error(error_)
409
395
  process.exit(1)
410
396
  }
@@ -420,7 +406,7 @@ const scaffoldFromTemplate = async function (context, flags, args, functionsDir)
420
406
  )
421
407
  }
422
408
 
423
- const name = await getNameFromArgs(args, flags, templateName)
409
+ const name = await getNameFromArgs(argumentName, options, templateName)
424
410
 
425
411
  log(`${NETLIFYDEVLOG} Creating function ${chalk.cyan.inverse(name)}`)
426
412
  const functionPath = ensureFunctionPathIsOk(functionsDir, name)
@@ -436,7 +422,7 @@ const scaffoldFromTemplate = async function (context, flags, args, functionsDir)
436
422
  const filename = path.basename(filePath)
437
423
 
438
424
  if (!omittedFromOutput.has(filename)) {
439
- context.log(`${NETLIFYDEVLOG} ${chalk.greenBright('Created')} ${filePath}`)
425
+ log(`${NETLIFYDEVLOG} ${chalk.greenBright('Created')} ${filePath}`)
440
426
  }
441
427
 
442
428
  fs.chmodSync(path.resolve(filePath), TEMPLATE_PERMISSIONS)
@@ -458,8 +444,8 @@ const scaffoldFromTemplate = async function (context, flags, args, functionsDir)
458
444
  spinner.succeed(`Installed dependencies for ${name}`)
459
445
  }
460
446
 
461
- await installAddons(context, addons, path.resolve(functionPath))
462
- await handleOnComplete({ context, onComplete })
447
+ await installAddons(command, addons, path.resolve(functionPath))
448
+ await handleOnComplete({ command, onComplete })
463
449
  }
464
450
  }
465
451
 
@@ -484,20 +470,27 @@ const createFunctionAddon = async function ({ addonName, addons, api, siteData,
484
470
  }
485
471
  }
486
472
 
487
- const injectEnvVariablesFromContext = async ({ context }) => {
488
- const { netlify, warn } = context
489
- const { cachedConfig, site } = netlify
490
- await injectEnvVariables({ env: cachedConfig.env, site, warn })
491
- }
492
-
493
- const handleOnComplete = async ({ context, onComplete }) => {
473
+ /**
474
+ *
475
+ * @param {object} config
476
+ * @param {import('../base-command').BaseCommand} config.command
477
+ * @param {(command: import('../base-command').BaseCommand) => any} config.onComplete
478
+ */
479
+ const handleOnComplete = async ({ command, onComplete }) => {
494
480
  if (onComplete) {
495
- await injectEnvVariablesFromContext({ context })
496
- await onComplete.call(context)
481
+ await injectEnvVariables({ env: command.netlify.cachedConfig.env, site: command.netlify.site })
482
+ await onComplete.call(command)
497
483
  }
498
484
  }
499
-
500
- const handleAddonDidInstall = async ({ addonCreated, addonDidInstall, context, fnPath }) => {
485
+ /**
486
+ *
487
+ * @param {object} config
488
+ * @param {*} config.addonCreated
489
+ * @param {*} config.addonDidInstall
490
+ * @param {import('../base-command').BaseCommand} config.command
491
+ * @param {string} config.fnPath
492
+ */
493
+ const handleAddonDidInstall = async ({ addonCreated, addonDidInstall, command, fnPath }) => {
501
494
  if (!addonCreated || !addonDidInstall) {
502
495
  return
503
496
  }
@@ -515,16 +508,23 @@ const handleAddonDidInstall = async ({ addonCreated, addonDidInstall, context, f
515
508
  return
516
509
  }
517
510
 
518
- await injectEnvVariablesFromContext({ context })
511
+ await injectEnvVariables({ env: command.netlify.cachedConfig.env, site: command.netlify.site })
519
512
  addonDidInstall(fnPath)
520
513
  }
521
514
 
522
- const installAddons = async function (context, functionAddons, fnPath) {
515
+ /**
516
+ *
517
+ * @param {import('../base-command').BaseCommand} command
518
+ * @param {*} functionAddons
519
+ * @param {*} fnPath
520
+ * @returns
521
+ */
522
+ const installAddons = async function (command, functionAddons, fnPath) {
523
523
  if (functionAddons.length === 0) {
524
524
  return
525
525
  }
526
526
 
527
- const { api, site } = context.netlify
527
+ const { api, site } = command.netlify
528
528
  const siteId = site.id
529
529
  if (!siteId) {
530
530
  log('No site id found, please run inside a site directory or `netlify link`')
@@ -545,7 +545,7 @@ const installAddons = async function (context, functionAddons, fnPath) {
545
545
  siteData,
546
546
  })
547
547
 
548
- await handleAddonDidInstall({ addonCreated, addonDidInstall, context, fnPath })
548
+ await handleAddonDidInstall({ addonCreated, addonDidInstall, command, fnPath })
549
549
  } catch (error_) {
550
550
  error(`${NETLIFYDEVERR} Error installing addon: `, error_)
551
551
  }
@@ -563,3 +563,42 @@ const ensureFunctionPathIsOk = function (functionsDir, name) {
563
563
  }
564
564
  return functionPath
565
565
  }
566
+
567
+ /**
568
+ * The functions:create command
569
+ * @param {import('commander').OptionValues} options
570
+ * @param {import('../base-command').BaseCommand} command
571
+ */
572
+ const functionsCreate = async (name, options, command) => {
573
+ const functionsDir = await ensureFunctionDirExists(command)
574
+
575
+ /* either download from URL or scaffold from template */
576
+ const mainFunc = options.url ? downloadFromURL : scaffoldFromTemplate
577
+ await mainFunc(command, options, name, functionsDir)
578
+ }
579
+
580
+ /**
581
+ * Creates the `netlify functions:create` command
582
+ * @param {import('../base-command').BaseCommand} program
583
+ * @returns
584
+ */
585
+ const createFunctionsCreateCommand = (program) =>
586
+ program
587
+ .command('functions:create')
588
+ .alias('function:create')
589
+ .argument('[name]', 'name of your new function file inside your functions directory')
590
+ .description('Create a new function locally')
591
+ .option('-n, --name <name>', 'function name')
592
+ .option('-u, --url <url>', 'pull template from URL')
593
+ .option('-l, --language <lang>', 'function language')
594
+ .addHelpText(
595
+ 'after',
596
+ generateExamplesHelp([
597
+ 'netlify functions:create',
598
+ 'netlify functions:create hello-world',
599
+ 'netlify functions:create --name hello-world',
600
+ ]),
601
+ )
602
+ .action(functionsCreate)
603
+
604
+ module.exports = { createFunctionsCreateCommand }