Repository: netlify/zip-it-and-ship-it
Pull request #231 (2020-10-27 17:04:11)

Return function names in `listFunctions()` and `listFunctionsFiles()`
Required by https://github.com/netlify/cli/issues/1477

Function names are important because they are the ones used in the function URL. 
They are different from the function filename since they do not include the file extension.

This PR returns the function `name` in both `listFunctions()` and `listFunctionsFiles()`.


Patch:
diff --git a/README.md b/README.md
index 901db47..c8ac7e0 100644
--- a/README.md
+++ b/README.md
@@ -133,6 +133,13 @@ const functions = await listFunctions('functions/function.js')
 
 Each object has the following properties.
 
+#### name
+
+_Type_: `string`
+
+Function's name. This is the one used in the Function URL. For example, if a Function is a `myFunc.js` regular file, the
+`name` is `myFunc` and the URL is `https://{hostname}/.netlify/functions/myFunc`.
+
 #### mainFile
 
 _Type_: `string`
diff --git a/src/dependencies.js b/src/dependencies.js
index a2ca2b1..40af583 100644
--- a/src/dependencies.js
+++ b/src/dependencies.js
@@ -14,7 +14,7 @@ const pGlob = promisify(glob)
 // Retrieve the paths to the Node.js files to zip.
 // We only include the files actually needed by the function because AWS Lambda
 // has a size limit for the zipped file. It also makes cold starts faster.
-const listNodeFiles = async function(srcPath, filename, mainFile, srcDir, stat) {
+const listNodeFiles = async function(srcPath, mainFile, srcDir, stat) {
   const [treeFiles, depFiles] = await Promise.all([getTreeFiles(srcPath, stat), getDependencies(mainFile, srcDir)])
   const files = [...treeFiles, ...depFiles].map(normalize)
   const uniqueFiles = [...new Set(files)]
diff --git a/src/fixtures/list/four.js/four.js.js b/src/fixtures/list/four.js/four.js.js
new file mode 100644
index 0000000..33c1891
--- /dev/null
+++ b/src/fixtures/list/four.js/four.js.js
@@ -0,0 +1,1 @@
+module.exports = true
diff --git a/src/main.js b/src/main.js
index 14c1f74..13fc603 100644
--- a/src/main.js
+++ b/src/main.js
@@ -33,7 +33,7 @@ const zipFunction = async function(srcPath, destFolder, { skipGo = true, zipGo =
     return
   }
 
-  const srcFiles = await getSrcFiles({ runtime, filename, stat, mainFile, extension, srcPath, srcDir })
+  const srcFiles = await getSrcFiles({ runtime, stat, mainFile, extension, srcPath, srcDir })
 
   await makeDir(destFolder)
 
@@ -98,18 +98,18 @@ const listFilenames = async function(srcFolder) {
 }
 
 const getFunctionInfo = async function(srcPath) {
-  const { filename, stat, mainFile, extension, srcDir } = await getSrcInfo(srcPath)
+  const { name, filename, stat, mainFile, extension, srcDir } = await getSrcInfo(srcPath)
 
   if (mainFile === undefined) {
     return {}
   }
 
   if (extension === '.zip' || extension === '.js') {
-    return { runtime: 'js', filename, stat, mainFile, extension, srcPath, srcDir }
+    return { runtime: 'js', name, filename, stat, mainFile, extension, srcPath, srcDir }
   }
 
   if (await isGoExe(srcPath)) {
-    return { runtime: 'go', filename, stat, mainFile, extension, srcPath, srcDir }
+    return { runtime: 'go', name, filename, stat, mainFile, extension, srcPath, srcDir }
   }
 
   return {}
@@ -128,8 +128,9 @@ const getSrcInfo = async function(srcPath) {
   }
 
   const extension = extname(mainFile)
+  const name = basename(srcPath, extname(srcPath))
   const srcDir = stat.isDirectory() ? srcPath : dirname(srcPath)
-  return { filename, stat, mainFile, extension, srcDir }
+  return { name, filename, stat, mainFile, extension, srcDir }
 }
 
 // Each `srcPath` can also be a directory with an `index.js` file or a file
@@ -146,18 +147,18 @@ const hasMainFile = function({ mainFile }) {
   return mainFile !== undefined
 }
 
-const getListedFunction = function({ runtime, mainFile, extension }) {
-  return { mainFile, runtime, extension }
+const getListedFunction = function({ runtime, name, mainFile, extension }) {
+  return { name, mainFile, runtime, extension }
 }
 
-const getListedFunctionFiles = async function({ runtime, filename, stat, mainFile, extension, srcPath, srcDir }) {
-  const srcFiles = await getSrcFiles({ runtime, filename, stat, mainFile, extension, srcPath, srcDir })
-  return srcFiles.map(srcFile => ({ srcFile, mainFile, runtime, extension: extname(srcFile) }))
+const getListedFunctionFiles = async function({ runtime, name, stat, mainFile, extension, srcPath, srcDir }) {
+  const srcFiles = await getSrcFiles({ runtime, stat, mainFile, extension, srcPath, srcDir })
+  return srcFiles.map(srcFile => ({ srcFile, name, mainFile, runtime, extension: extname(srcFile) }))
 }
 
-const getSrcFiles = function({ runtime, filename, stat, mainFile, extension, srcPath, srcDir }) {
+const getSrcFiles = function({ runtime, stat, mainFile, extension, srcPath, srcDir }) {
   if (runtime === 'js' && extension === '.js') {
-    return listNodeFiles(srcPath, filename, mainFile, srcDir, stat)
+    return listNodeFiles(srcPath, mainFile, srcDir, stat)
   }
 
   return [srcPath]


Test patch:
diff --git a/src/main.test.js b/src/main.test.js
index 5f7b881..8960b2b 100644
--- a/src/main.test.js
+++ b/src/main.test.js
@@ -297,10 +297,10 @@ test('Can use zipFunction()', async t => {
   t.is(runtime, 'js')
 })
 
-const normalizeFiles = function(fixtureDir, { mainFile, runtime, extension, srcFile }) {
+const normalizeFiles = function(fixtureDir, { name, mainFile, runtime, extension, srcFile }) {
   const mainFileA = normalize(`${fixtureDir}/${mainFile}`)
   const srcFileA = srcFile === undefined ? {} : { srcFile: normalize(`${fixtureDir}/${srcFile}`) }
-  return { mainFile: mainFileA, runtime, extension, ...srcFileA }
+  return { name, mainFile: mainFileA, runtime, extension, ...srcFileA }
 }
 
 test('Can list function main files with listFunctions()', async t => {
@@ -309,11 +309,12 @@ test('Can list function main files with listFunctions()', async t => {
   t.deepEqual(
     functions,
     [
-      { mainFile: 'one/index.js', runtime: 'js', extension: '.js' },
-      { mainFile: 'test', runtime: 'go', extension: '' },
-      { mainFile: 'test.js', runtime: 'js', extension: '.js' },
-      { mainFile: 'test.zip', runtime: 'js', extension: '.zip' },
-      { mainFile: 'two/two.js', runtime: 'js', extension: '.js' }
+      { name: 'four', mainFile: 'four.js/four.js.js', runtime: 'js', extension: '.js' },
+      { name: 'one', mainFile: 'one/index.js', runtime: 'js', extension: '.js' },
+      { name: 'test', mainFile: 'test', runtime: 'go', extension: '' },
+      { name: 'test', mainFile: 'test.js', runtime: 'js', extension: '.js' },
+      { name: 'test', mainFile: 'test.zip', runtime: 'js', extension: '.zip' },
+      { name: 'two', mainFile: 'two/two.js', runtime: 'js', extension: '.js' }
     ].map(normalizeFiles.bind(null, fixtureDir))
   )
 })
@@ -324,12 +325,13 @@ test('Can list all function files with listFunctionsFiles()', async t => {
   t.deepEqual(
     functions,
     [
-      { mainFile: 'one/index.js', runtime: 'js', extension: '.js', srcFile: 'one/index.js' },
-      { mainFile: 'test', runtime: 'go', extension: '', srcFile: 'test' },
-      { mainFile: 'test.js', runtime: 'js', extension: '.js', srcFile: 'test.js' },
-      { mainFile: 'test.zip', runtime: 'js', extension: '.zip', srcFile: 'test.zip' },
-      { mainFile: 'two/two.js', runtime: 'js', extension: '.json', srcFile: 'two/three.json' },
-      { mainFile: 'two/two.js', runtime: 'js', extension: '.js', srcFile: 'two/two.js' }
+      { name: 'four', mainFile: 'four.js/four.js.js', runtime: 'js', extension: '.js', srcFile: 'four.js/four.js.js' },
+      { name: 'one', mainFile: 'one/index.js', runtime: 'js', extension: '.js', srcFile: 'one/index.js' },
+      { name: 'test', mainFile: 'test', runtime: 'go', extension: '', srcFile: 'test' },
+      { name: 'test', mainFile: 'test.js', runtime: 'js', extension: '.js', srcFile: 'test.js' },
+      { name: 'test', mainFile: 'test.zip', runtime: 'js', extension: '.zip', srcFile: 'test.zip' },
+      { name: 'two', mainFile: 'two/two.js', runtime: 'js', extension: '.json', srcFile: 'two/three.json' },
+      { name: 'two', mainFile: 'two/two.js', runtime: 'js', extension: '.js', srcFile: 'two/two.js' }
     ].map(normalizeFiles.bind(null, fixtureDir))
   )
 })