netlify-cli 15.10.0-rc.1 → 15.11.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 (39) hide show
  1. package/bin/run.mjs +5 -6
  2. package/npm-shrinkwrap.json +3 -6
  3. package/package.json +2 -1
  4. package/src/commands/base-command.mjs +116 -295
  5. package/src/commands/build/build.mjs +1 -9
  6. package/src/commands/deploy/deploy.mjs +9 -23
  7. package/src/commands/dev/dev.mjs +17 -22
  8. package/src/commands/functions/functions-create.mjs +89 -118
  9. package/src/commands/functions/functions-invoke.mjs +7 -10
  10. package/src/commands/functions/functions-list.mjs +2 -2
  11. package/src/commands/init/init.mjs +1 -1
  12. package/src/commands/link/link.mjs +5 -5
  13. package/src/commands/serve/serve.mjs +6 -10
  14. package/src/commands/sites/sites-create-template.mjs +1 -1
  15. package/src/commands/sites/sites-create.mjs +1 -1
  16. package/src/lib/edge-functions/internal.mjs +3 -5
  17. package/src/lib/edge-functions/proxy.mjs +3 -27
  18. package/src/lib/functions/netlify-function.mjs +26 -1
  19. package/src/lib/functions/registry.mjs +14 -26
  20. package/src/lib/functions/runtimes/js/worker.mjs +1 -1
  21. package/src/lib/spinner.mjs +1 -1
  22. package/src/recipes/vscode/index.mjs +6 -24
  23. package/src/utils/command-helpers.mjs +7 -16
  24. package/src/utils/detect-server-settings.mjs +245 -133
  25. package/src/utils/framework-server.mjs +5 -6
  26. package/src/utils/functions/functions.mjs +5 -8
  27. package/src/utils/get-repo-data.mjs +6 -5
  28. package/src/utils/init/config-github.mjs +2 -2
  29. package/src/utils/init/config-manual.mjs +7 -24
  30. package/src/utils/init/frameworks.mjs +23 -0
  31. package/src/utils/init/utils.mjs +63 -62
  32. package/src/utils/proxy-server.mjs +4 -7
  33. package/src/utils/proxy.mjs +3 -4
  34. package/src/utils/read-repo-url.mjs +0 -4
  35. package/src/utils/run-build.mjs +32 -58
  36. package/src/utils/shell.mjs +7 -24
  37. package/src/utils/state-config.mjs +1 -5
  38. package/src/utils/static-server.mjs +0 -4
  39. package/src/utils/build-info.mjs +0 -100
@@ -2,7 +2,6 @@
2
2
  import process from 'process'
3
3
 
4
4
  import { getBuildOptions, runBuild } from '../../lib/build.mjs'
5
- import { detectFrameworkSettings } from '../../utils/build-info.mjs'
6
5
  import { error, exit, getToken } from '../../utils/command-helpers.mjs'
7
6
  import { getEnvelopeEnv, normalizeContext } from '../../utils/env/index.mjs'
8
7
 
@@ -34,18 +33,11 @@ const injectEnv = async function (command, { api, buildOptions, context, siteInf
34
33
  * @param {import('../base-command.mjs').default} command
35
34
  */
36
35
  const build = async (options, command) => {
37
- const { cachedConfig, siteInfo } = command.netlify
38
36
  command.setAnalyticsPayload({ dry: options.dry })
39
37
  // Retrieve Netlify Build options
40
38
  const [token] = await getToken()
41
- const settings = await detectFrameworkSettings(command, 'build')
42
-
43
- // override the build command with the detection result if no command is specified through the config
44
- if (!cachedConfig.config.build.command) {
45
- cachedConfig.config.build.command = settings?.buildCommand
46
- cachedConfig.config.build.commandOrigin = 'heuristics'
47
- }
48
39
 
40
+ const { cachedConfig, siteInfo } = command.netlify
49
41
  const buildOptions = await getBuildOptions({
50
42
  cachedConfig,
51
43
  token,
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  import { stat } from 'fs/promises'
3
3
  import { basename, resolve } from 'path'
4
- import { env } from 'process'
4
+ import { cwd, env } from 'process'
5
5
 
6
6
  import { runCoreSteps } from '@netlify/build'
7
7
  import { restoreConfig, updateConfig } from '@netlify/config'
@@ -64,18 +64,16 @@ const triggerDeploy = async ({ api, options, siteData, siteId }) => {
64
64
  /**
65
65
  * g
66
66
  * @param {object} config
67
- * @param {string} config.workingDir The process working directory
68
67
  * @param {object} config.config
69
68
  * @param {import('commander').OptionValues} config.options
70
69
  * @param {object} config.site
71
70
  * @param {object} config.siteData
72
71
  * @returns {Promise<string>}
73
72
  */
74
- const getDeployFolder = async ({ config, options, site, siteData, workingDir }) => {
75
- console.log()
73
+ const getDeployFolder = async ({ config, options, site, siteData }) => {
76
74
  let deployFolder
77
75
  if (options.dir) {
78
- deployFolder = resolve(site.root, options.dir)
76
+ deployFolder = resolve(cwd(), options.dir)
79
77
  } else if (config?.build?.publish) {
80
78
  deployFolder = resolve(site.root, config.build.publish)
81
79
  } else if (siteData?.build_settings?.dir) {
@@ -84,13 +82,14 @@ const getDeployFolder = async ({ config, options, site, siteData, workingDir })
84
82
 
85
83
  if (!deployFolder) {
86
84
  log('Please provide a publish directory (e.g. "public" or "dist" or "."):')
85
+ log(cwd())
87
86
  const { promptPath } = await inquirer.prompt([
88
87
  {
89
88
  type: 'input',
90
89
  name: 'promptPath',
91
90
  message: 'Publish directory',
92
91
  default: '.',
93
- filter: (input) => resolve(workingDir, input),
92
+ filter: (input) => resolve(cwd(), input),
94
93
  },
95
94
  ])
96
95
  deployFolder = promptPath
@@ -129,15 +128,14 @@ const validateDeployFolder = async ({ deployFolder }) => {
129
128
  * @param {import('commander').OptionValues} config.options
130
129
  * @param {object} config.site
131
130
  * @param {object} config.siteData
132
- * @param {string} config.workingDir // The process working directory
133
131
  * @returns {string}
134
132
  */
135
- const getFunctionsFolder = ({ config, options, site, siteData, workingDir }) => {
133
+ const getFunctionsFolder = ({ config, options, site, siteData }) => {
136
134
  let functionsFolder
137
135
  // Support "functions" and "Functions"
138
136
  const funcConfig = config.functionsDirectory
139
137
  if (options.functions) {
140
- functionsFolder = resolve(workingDir, options.functions)
138
+ functionsFolder = resolve(cwd(), options.functions)
141
139
  } else if (funcConfig) {
142
140
  functionsFolder = resolve(site.root, funcConfig)
143
141
  } else if (siteData?.build_settings?.functions_dir) {
@@ -180,21 +178,12 @@ const validateFolders = async ({ deployFolder, functionsFolder }) => {
180
178
  return { deployFolderStat, functionsFolderStat }
181
179
  }
182
180
 
183
- /**
184
- * @param {object} config
185
- * @param {string} config.deployFolder
186
- * @param {*} config.site
187
- * @returns
188
- */
189
181
  const getDeployFilesFilter = ({ deployFolder, site }) => {
190
182
  // site.root === deployFolder can happen when users run `netlify deploy --dir .`
191
183
  // in that specific case we don't want to publish the repo node_modules
192
184
  // when site.root !== deployFolder the behaviour matches our buildbot
193
185
  const skipNodeModules = site.root === deployFolder
194
186
 
195
- /**
196
- * @param {string} filename
197
- */
198
187
  return (filename) => {
199
188
  if (filename == null) {
200
189
  return false
@@ -507,7 +496,6 @@ const printResults = ({ deployToProduction, json, results, runBuildCommand }) =>
507
496
  * @param {import('../base-command.mjs').default} command
508
497
  */
509
498
  const deploy = async (options, command) => {
510
- const { workingDir } = command
511
499
  const { api, site, siteInfo } = command.netlify
512
500
  const alias = options.alias || options.branch
513
501
 
@@ -572,18 +560,16 @@ const deploy = async (options, command) => {
572
560
  siteInfo: siteData,
573
561
  })
574
562
  }
575
-
576
563
  const { configMutations = [], newConfig } = await handleBuild({
577
564
  cachedConfig: command.netlify.cachedConfig,
578
565
  options,
579
566
  })
580
567
  const config = newConfig || command.netlify.config
581
568
 
582
- const deployFolder = await getDeployFolder({ workingDir, options, config, site, siteData })
583
- const functionsFolder = getFunctionsFolder({ workingDir, options, config, site, siteData })
569
+ const deployFolder = await getDeployFolder({ options, config, site, siteData })
570
+ const functionsFolder = getFunctionsFolder({ options, config, site, siteData })
584
571
  const { configPath } = site
585
572
  const edgeFunctionsConfig = command.netlify.config.edge_functions
586
- console.log({ functionsFolder, edgeFunctionsConfig })
587
573
 
588
574
  // build flag wasn't used and edge functions exist
589
575
  if (!options.build && edgeFunctionsConfig && edgeFunctionsConfig.length !== 0) {
@@ -9,6 +9,7 @@ import { printBanner } from '../../utils/banner.mjs'
9
9
  import {
10
10
  BANG,
11
11
  chalk,
12
+ exit,
12
13
  log,
13
14
  NETLIFYDEV,
14
15
  NETLIFYDEVERR,
@@ -34,7 +35,7 @@ import { createDevExecCommand } from './dev-exec.mjs'
34
35
  * @param {object} config
35
36
  * @param {*} config.api
36
37
  * @param {import('commander').OptionValues} config.options
37
- * @param {import('../../utils/types.js').ServerSettings} config.settings
38
+ * @param {*} config.settings
38
39
  * @param {*} config.site
39
40
  * @param {*} config.state
40
41
  * @returns
@@ -67,9 +68,6 @@ const handleLiveTunnel = async ({ api, options, settings, site, state }) => {
67
68
  }
68
69
  }
69
70
 
70
- /**
71
- * @param {string} args
72
- */
73
71
  const validateShortFlagArgs = (args) => {
74
72
  if (args.startsWith('=')) {
75
73
  throw new Error(
@@ -96,13 +94,11 @@ const dev = async (options, command) => {
96
94
  const { api, cachedConfig, config, repositoryRoot, site, siteInfo, state } = command.netlify
97
95
  config.dev = { ...config.dev }
98
96
  config.build = { ...config.build }
99
- /** @type {import('./types.js').DevConfig} */
97
+ /** @type {import('./types').DevConfig} */
100
98
  const devConfig = {
101
99
  framework: '#auto',
102
- autoLaunch: Boolean(options.open),
103
100
  ...(config.functionsDirectory && { functions: config.functionsDirectory }),
104
101
  ...(config.build.publish && { publish: config.build.publish }),
105
- ...(config.build.base && { base: config.build.base }),
106
102
  ...config.dev,
107
103
  ...options,
108
104
  }
@@ -128,17 +124,20 @@ const dev = async (options, command) => {
128
124
  siteInfo,
129
125
  })
130
126
 
131
- /** @type {import('../../utils/types.js').ServerSettings} */
132
- let settings
127
+ /** @type {Partial<import('../../utils/types').ServerSettings>} */
128
+ let settings = {}
133
129
  try {
134
- settings = await detectServerSettings(devConfig, options, command)
130
+ settings = await detectServerSettings(devConfig, options, site.root, {
131
+ site: {
132
+ id: site.id,
133
+ url: siteUrl,
134
+ },
135
+ })
135
136
 
136
137
  cachedConfig.config = getConfigWithPlugins(cachedConfig.config, settings)
137
138
  } catch (error_) {
138
- if (error_ && typeof error_ === 'object' && 'message' in error_) {
139
- log(NETLIFYDEVERR, error_.message)
140
- }
141
- process.exit(1)
139
+ log(NETLIFYDEVERR, error_.message)
140
+ exit(1)
142
141
  }
143
142
 
144
143
  command.setAnalyticsPayload({ live: options.live })
@@ -152,9 +151,10 @@ const dev = async (options, command) => {
152
151
  log(`${NETLIFYDEVWARN} Setting up local development server`)
153
152
 
154
153
  const { configPath: configPathOverride } = await runDevTimeline({
155
- command,
154
+ cachedConfig,
156
155
  options,
157
156
  settings,
157
+ site,
158
158
  env: {
159
159
  URL: url,
160
160
  DEPLOY_URL: url,
@@ -188,11 +188,8 @@ const dev = async (options, command) => {
188
188
 
189
189
  // TODO: We should consolidate this with the existing config watcher.
190
190
  const getUpdatedConfig = async () => {
191
- const { config: newConfig } = await command.getConfig({
192
- cwd: command.workingDir,
193
- offline: true,
194
- state,
195
- })
191
+ const cwd = options.cwd || process.cwd()
192
+ const { config: newConfig } = await command.getConfig({ cwd, offline: true, state })
196
193
  const normalizedNewConfig = normalizeConfig(newConfig)
197
194
 
198
195
  return normalizedNewConfig
@@ -205,7 +202,6 @@ const dev = async (options, command) => {
205
202
  config,
206
203
  configPath: configPathOverride,
207
204
  debug: options.debug,
208
- projectDir: command.workingDir,
209
205
  env,
210
206
  getUpdatedConfig,
211
207
  inspectSettings,
@@ -252,7 +248,6 @@ export const createDevCommand = (program) => {
252
248
  .argParser((value) => Number.parseInt(value))
253
249
  .hideHelp(true),
254
250
  )
255
- .addOption(new Option('--no-open', 'disables the automatic opening of a browser window'))
256
251
  .option('--target-port <port>', 'port of target app server', (value) => Number.parseInt(value))
257
252
  .option('--framework <name>', 'framework to use. Defaults to #auto which automatically detects a framework')
258
253
  .option('-d ,--dir <path>', 'dir with static files')
@@ -3,7 +3,7 @@ import cp from 'child_process'
3
3
  import fs from 'fs'
4
4
  import { mkdir, readdir, unlink } from 'fs/promises'
5
5
  import { createRequire } from 'module'
6
- import path, { dirname, join, relative } from 'path'
6
+ import path, { dirname } from 'path'
7
7
  import process from 'process'
8
8
  import { fileURLToPath, pathToFileURL } from 'url'
9
9
  import { promisify } from 'util'
@@ -12,6 +12,7 @@ import copyTemplateDirOriginal from 'copy-template-dir'
12
12
  import { findUp } from 'find-up'
13
13
  import fuzzy from 'fuzzy'
14
14
  import inquirer from 'inquirer'
15
+ import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'
15
16
  import fetch from 'node-fetch'
16
17
  import ora from 'ora'
17
18
 
@@ -30,10 +31,8 @@ const templatesDir = path.resolve(dirname(fileURLToPath(import.meta.url)), '../.
30
31
 
31
32
  const showRustTemplates = process.env.NETLIFY_EXPERIMENTAL_BUILD_RUST_SOURCE === 'true'
32
33
 
33
- /**
34
- * Ensure that there's a sub-directory in `src/functions-templates` named after
35
- * each `value` property in this list.
36
- */
34
+ // Ensure that there's a sub-directory in `src/functions-templates` named after
35
+ // each `value` property in this list.
37
36
  const languages = [
38
37
  { name: 'JavaScript', value: 'javascript' },
39
38
  { name: 'TypeScript', value: 'typescript' },
@@ -92,28 +91,23 @@ const filterRegistry = function (registry, input) {
92
91
  })
93
92
  }
94
93
 
95
- /**
96
- * @param {string} lang
97
- * @param {'edge' | 'serverless'} funcType
98
- */
99
94
  const formatRegistryArrayForInquirer = async function (lang, funcType) {
100
- const folders = await readdir(path.join(templatesDir, lang), { withFileTypes: true })
95
+ const folderNames = await readdir(path.join(templatesDir, lang))
101
96
 
102
97
  const imports = await Promise.all(
103
- folders
104
- .filter((folder) => Boolean(folder?.isDirectory()))
105
- .map(async ({ name }) => {
106
- try {
107
- const templatePath = path.join(templatesDir, lang, name, '.netlify-function-template.mjs')
108
- const template = await import(pathToFileURL(templatePath))
109
- return template.default
110
- } catch {
111
- // noop if import fails we don't break the whole inquirer
112
- }
98
+ folderNames
99
+ // filter out markdown files
100
+ .filter((folderName) => !folderName.endsWith('.md'))
101
+ .map(async (folderName) => {
102
+ const templatePath = path.join(templatesDir, lang, folderName, '.netlify-function-template.mjs')
103
+ const template = await import(pathToFileURL(templatePath))
104
+
105
+ return template.default
113
106
  }),
114
107
  )
108
+
115
109
  const registry = imports
116
- .filter((template) => template?.functionType === funcType)
110
+ .filter((template) => template.functionType === funcType)
117
111
  .sort((templateA, templateB) => {
118
112
  const priorityDiff = (templateA.priority || DEFAULT_PRIORITY) - (templateB.priority || DEFAULT_PRIORITY)
119
113
 
@@ -142,7 +136,7 @@ const formatRegistryArrayForInquirer = async function (lang, funcType) {
142
136
  /**
143
137
  * pick template from our existing templates
144
138
  * @param {import('commander').OptionValues} config
145
- * @param {'edge' | 'serverless'} funcType
139
+ *
146
140
  */
147
141
  const pickTemplate = async function ({ language: languageFromFlag }, funcType) {
148
142
  const specialCommands = [
@@ -178,6 +172,8 @@ const pickTemplate = async function ({ language: languageFromFlag }, funcType) {
178
172
  language = languageFromPrompt
179
173
  }
180
174
 
175
+ inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
176
+
181
177
  let templatesForLanguage
182
178
 
183
179
  try {
@@ -211,7 +207,6 @@ const pickTemplate = async function ({ language: languageFromFlag }, funcType) {
211
207
 
212
208
  const DEFAULT_PRIORITY = 999
213
209
 
214
- /** @returns {Promise<'edge' | 'serverless'>} */
215
210
  const selectTypeOfFunc = async () => {
216
211
  const functionTypes = [
217
212
  { name: 'Edge function (Deno)', value: 'edge' },
@@ -229,100 +224,92 @@ const selectTypeOfFunc = async () => {
229
224
  return functionType
230
225
  }
231
226
 
232
- /**
233
- * @param {import('../base-command.mjs').default} command
234
- */
235
227
  const ensureEdgeFuncDirExists = function (command) {
236
228
  const { config, site } = command.netlify
237
229
  const siteId = site.id
230
+ let functionsDirHolder = config.build.edge_functions
238
231
 
239
232
  if (!siteId) {
240
233
  error(`${NETLIFYDEVERR} No site id found, please run inside a site directory or \`netlify link\``)
241
234
  }
242
235
 
243
- const functionsDir = config.build?.edge_functions ?? join(command.workingDir, 'netlify/edge-functions')
244
- const relFunctionsDir = relative(command.workingDir, functionsDir)
236
+ if (!functionsDirHolder) {
237
+ functionsDirHolder = 'netlify/edge-functions'
238
+ }
245
239
 
246
- if (!fs.existsSync(functionsDir)) {
240
+ if (!fs.existsSync(functionsDirHolder)) {
247
241
  log(
248
242
  `${NETLIFYDEVLOG} Edge Functions directory ${chalk.magenta.inverse(
249
- relFunctionsDir,
243
+ functionsDirHolder,
250
244
  )} does not exist yet, creating it...`,
251
245
  )
252
246
 
253
- fs.mkdirSync(functionsDir, { recursive: true })
247
+ fs.mkdirSync(functionsDirHolder, { recursive: true })
254
248
 
255
- log(`${NETLIFYDEVLOG} Edge Functions directory ${chalk.magenta.inverse(relFunctionsDir)} created.`)
249
+ log(`${NETLIFYDEVLOG} Edge Functions directory ${chalk.magenta.inverse(functionsDirHolder)} created.`)
256
250
  }
257
-
258
- return functionsDir
251
+ return functionsDirHolder
259
252
  }
260
253
 
261
254
  /**
262
- * Prompts the user to choose a functions directory
255
+ * Get functions directory (and make it if necessary)
263
256
  * @param {import('../base-command.mjs').default} command
264
- * @returns {Promise<string>} - functions directory or throws an error
257
+ * @returns {Promise<string|never>} - functions directory or throws an error
265
258
  */
266
- const promptFunctionsDirectory = async (command) => {
267
- const { api, relConfigFilePath, site } = command.netlify
268
- log(`\n${NETLIFYDEVLOG} functions directory not specified in ${relConfigFilePath} or UI settings`)
259
+ const ensureFunctionDirExists = async function (command) {
260
+ const { api, config, site } = command.netlify
261
+ const siteId = site.id
262
+ let functionsDirHolder = config.functionsDirectory
269
263
 
270
- if (!site.id) {
271
- error(`${NETLIFYDEVERR} No site id found, please run inside a site directory or \`netlify link\``)
272
- }
264
+ if (!functionsDirHolder) {
265
+ log(`${NETLIFYDEVLOG} functions directory not specified in netlify.toml or UI settings`)
273
266
 
274
- const { functionsDir } = await inquirer.prompt([
275
- {
276
- type: 'input',
277
- name: 'functionsDir',
278
- message: 'Enter the path, relative to your site, where your functions should live:',
279
- default: 'netlify/functions',
280
- },
281
- ])
267
+ if (!siteId) {
268
+ error(`${NETLIFYDEVERR} No site id found, please run inside a site directory or \`netlify link\``)
269
+ }
282
270
 
283
- try {
284
- log(`${NETLIFYDEVLOG} updating site settings with ${chalk.magenta.inverse(functionsDir)}`)
285
-
286
- // @ts-ignore Typings of API are not correct
287
- await api.updateSite({
288
- siteId: site.id,
289
- body: {
290
- build_settings: {
291
- functions_dir: functionsDir,
292
- },
271
+ const { functionsDir } = await inquirer.prompt([
272
+ {
273
+ type: 'input',
274
+ name: 'functionsDir',
275
+ message:
276
+ 'Enter the path, relative to your site’s base directory in your repository, where your functions should live:',
277
+ default: 'netlify/functions',
293
278
  },
294
- })
279
+ ])
295
280
 
296
- log(`${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(functionsDir)} updated in site settings`)
297
- } catch {
298
- throw error('Error updating site settings')
299
- }
300
- return functionsDir
301
- }
281
+ functionsDirHolder = functionsDir
302
282
 
303
- /**
304
- * Get functions directory (and make it if necessary)
305
- * @param {import('../base-command.mjs').default} command
306
- * @returns {Promise<string>} - functions directory or throws an error
307
- */
308
- const ensureFunctionDirExists = async function (command) {
309
- const { config } = command.netlify
310
- const functionsDirHolder =
311
- config.functionsDirectory || join(command.workingDir, await promptFunctionsDirectory(command))
312
- const relFunctionsDirHolder = relative(command.workingDir, functionsDirHolder)
283
+ try {
284
+ log(`${NETLIFYDEVLOG} updating site settings with ${chalk.magenta.inverse(functionsDirHolder)}`)
285
+
286
+ // @ts-ignore Typings of API are not correct
287
+ await api.updateSite({
288
+ siteId: site.id,
289
+ body: {
290
+ build_settings: {
291
+ functions_dir: functionsDirHolder,
292
+ },
293
+ },
294
+ })
313
295
 
314
- if (!fs.existsSync(functionsDirHolder)) {
296
+ log(`${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(functionsDirHolder)} updated in site settings`)
297
+ } catch {
298
+ throw error('Error updating site settings')
299
+ }
300
+ }
301
+
302
+ if (!(await fileExistsAsync(functionsDirHolder))) {
315
303
  log(
316
304
  `${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(
317
- relFunctionsDirHolder,
305
+ functionsDirHolder,
318
306
  )} does not exist yet, creating it...`,
319
307
  )
320
308
 
321
309
  await mkdir(functionsDirHolder, { recursive: true })
322
310
 
323
- log(`${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(relFunctionsDirHolder)} created`)
311
+ log(`${NETLIFYDEVLOG} functions directory ${chalk.magenta.inverse(functionsDirHolder)} created`)
324
312
  }
325
-
326
313
  return functionsDirHolder
327
314
  }
328
315
 
@@ -383,24 +370,20 @@ const downloadFromURL = async function (command, options, argumentName, function
383
370
  }
384
371
  }
385
372
 
386
- /**
387
- * Takes a list of existing packages and a list of packages required by a
388
- * function, and returns the packages from the latter that aren't present
389
- * in the former. The packages are returned as an array of strings with the
390
- * name and version range (e.g. '@netlify/functions@0.1.0').
391
- */
373
+ // Takes a list of existing packages and a list of packages required by a
374
+ // function, and returns the packages from the latter that aren't present
375
+ // in the former. The packages are returned as an array of strings with the
376
+ // name and version range (e.g. '@netlify/functions@0.1.0').
392
377
  const getNpmInstallPackages = (existingPackages = {}, neededPackages = {}) =>
393
378
  Object.entries(neededPackages)
394
379
  .filter(([name]) => existingPackages[name] === undefined)
395
380
  .map(([name, version]) => `${name}@${version}`)
396
381
 
397
- /**
398
- * When installing a function's dependencies, we first try to find a site-level
399
- * `package.json` file. If we do, we look for any dependencies of the function
400
- * that aren't already listed as dependencies of the site and install them. If
401
- * we don't do this check, we may be upgrading the version of a module used in
402
- * another part of the project, which we don't want to do.
403
- */
382
+ // When installing a function's dependencies, we first try to find a site-level
383
+ // `package.json` file. If we do, we look for any dependencies of the function
384
+ // that aren't already listed as dependencies of the site and install them. If
385
+ // we don't do this check, we may be upgrading the version of a module used in
386
+ // another part of the project, which we don't want to do.
404
387
  const installDeps = async ({ functionPackageJson, functionPath, functionsDir }) => {
405
388
  const { dependencies: functionDependencies, devDependencies: functionDevDependencies } = require(functionPackageJson)
406
389
  const sitePackageJson = await findUp('package.json', { cwd: functionsDir })
@@ -447,8 +430,8 @@ const installDeps = async ({ functionPackageJson, functionPath, functionsDir })
447
430
  * @param {import('../base-command.mjs').default} command
448
431
  * @param {import('commander').OptionValues} options
449
432
  * @param {string} argumentName
450
- * @param {string} functionsDir Absolute path of the functions directory
451
- * @param {'edge' | 'serverless'} funcType
433
+ * @param {string} functionsDir
434
+ * @param {string} funcType
452
435
  */
453
436
  // eslint-disable-next-line max-params
454
437
  const scaffoldFromTemplate = async function (command, options, argumentName, functionsDir, funcType) {
@@ -460,7 +443,7 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun
460
443
  name: 'chosenUrl',
461
444
  message: 'URL to clone: ',
462
445
  type: 'input',
463
- validate: (/** @type {string} */ val) => Boolean(validateRepoURL(val)),
446
+ validate: (val) => Boolean(validateRepoURL(val)),
464
447
  // make sure it is not undefined and is a valid filename.
465
448
  // this has some nuance i have ignored, eg crossenv and i18n concerns
466
449
  },
@@ -523,7 +506,7 @@ const scaffoldFromTemplate = async function (command, options, argumentName, fun
523
506
  }
524
507
 
525
508
  if (funcType === 'edge') {
526
- registerEFInToml(name, command.netlify)
509
+ registerEFInToml(name)
527
510
  }
528
511
 
529
512
  await installAddons(command, addons, path.resolve(functionPath))
@@ -648,15 +631,9 @@ const installAddons = async function (command, functionAddons, fnPath) {
648
631
  return Promise.all(arr)
649
632
  }
650
633
 
651
- /**
652
- *
653
- * @param {string} funcName
654
- * @param {import('../types.js').NetlifyOptions} options
655
- */
656
- const registerEFInToml = async (funcName, options) => {
657
- const { configFilePath, relConfigFilePath } = options
658
- if (!fs.existsSync(configFilePath)) {
659
- log(`${NETLIFYDEVLOG} \`${relConfigFilePath}\` file does not exist yet. Creating it...`)
634
+ const registerEFInToml = async (funcName) => {
635
+ if (!fs.existsSync('netlify.toml')) {
636
+ log(`${NETLIFYDEVLOG} \`netlify.toml\` file does not exist yet. Creating it...`)
660
637
  }
661
638
 
662
639
  let { funcPath } = await inquirer.prompt([
@@ -679,22 +656,17 @@ const registerEFInToml = async (funcName, options) => {
679
656
  const functionRegister = `\n\n[[edge_functions]]\nfunction = "${funcName}"\npath = "${funcPath}"`
680
657
 
681
658
  try {
682
- fs.promises.appendFile(configFilePath, functionRegister)
659
+ fs.promises.appendFile('netlify.toml', functionRegister)
683
660
  log(
684
- `${NETLIFYDEVLOG} Function '${funcName}' registered for route \`${funcPath}\`. To change, edit your \`${relConfigFilePath}\` file.`,
661
+ `${NETLIFYDEVLOG} Function '${funcName}' registered for route \`${funcPath}\`. To change, edit your \`netlify.toml\` file.`,
685
662
  )
686
663
  } catch {
687
- error(`${NETLIFYDEVERR} Unable to register function. Please check your \`${relConfigFilePath}\` file.`)
664
+ error(`${NETLIFYDEVERR} Unable to register function. Please check your \`netlify.toml\` file.`)
688
665
  }
689
666
  }
690
667
 
691
- /**
692
- * we used to allow for a --dir command,
693
- * but have retired that to force every scaffolded function to be a directory
694
- * @param {string} functionsDir
695
- * @param {string} name
696
- * @returns
697
- */
668
+ // we used to allow for a --dir command,
669
+ // but have retired that to force every scaffolded function to be a directory
698
670
  const ensureFunctionPathIsOk = function (functionsDir, name) {
699
671
  const functionPath = path.join(functionsDir, name)
700
672
  if (fs.existsSync(functionPath)) {
@@ -706,7 +678,6 @@ const ensureFunctionPathIsOk = function (functionsDir, name) {
706
678
 
707
679
  /**
708
680
  * The functions:create command
709
- * @param {string} name
710
681
  * @param {import('commander').OptionValues} options
711
682
  * @param {import('../base-command.mjs').default} command
712
683
  */
@@ -2,6 +2,7 @@
2
2
  import fs from 'fs'
3
3
  import { createRequire } from 'module'
4
4
  import path from 'path'
5
+ import process from 'process'
5
6
 
6
7
  import inquirer from 'inquirer'
7
8
  import fetch from 'node-fetch'
@@ -55,18 +56,14 @@ const formatQstring = function (querystring) {
55
56
  return ''
56
57
  }
57
58
 
58
- /**
59
- * process payloads from flag
60
- * @param {string} payloadString
61
- * @param {string} workingDir
62
- */
63
- const processPayloadFromFlag = function (payloadString, workingDir) {
59
+ /** process payloads from flag */
60
+ const processPayloadFromFlag = function (payloadString) {
64
61
  if (payloadString) {
65
62
  // case 1: jsonstring
66
63
  let payload = tryParseJSON(payloadString)
67
64
  if (payload) return payload
68
65
  // case 2: jsonpath
69
- const payloadpath = path.join(workingDir, payloadString)
66
+ const payloadpath = path.join(process.cwd(), payloadString)
70
67
  const pathexists = fs.existsSync(payloadpath)
71
68
  if (pathexists) {
72
69
  try {
@@ -144,11 +141,11 @@ const getFunctionToTrigger = function (options, argumentName) {
144
141
  * @param {import('../base-command.mjs').default} command
145
142
  */
146
143
  const functionsInvoke = async (nameArgument, options, command) => {
147
- const { config, relConfigFilePath } = command.netlify
144
+ const { config } = command.netlify
148
145
 
149
146
  const functionsDir = options.functions || (config.dev && config.dev.functions) || config.functionsDirectory
150
147
  if (typeof functionsDir === 'undefined') {
151
- error(`functions directory is undefined, did you forget to set it in ${relConfigFilePath}?`)
148
+ error('functions directory is undefined, did you forget to set it in netlify.toml?')
152
149
  }
153
150
 
154
151
  if (!options.port)
@@ -213,7 +210,7 @@ const functionsInvoke = async (nameArgument, options, command) => {
213
210
  // }
214
211
  }
215
212
  }
216
- const payload = processPayloadFromFlag(options.payload, command.workingDir)
213
+ const payload = processPayloadFromFlag(options.payload)
217
214
  body = { ...body, ...payload }
218
215
 
219
216
  try {