diff --git a/src/runtimes/node/utils/zip.ts b/src/runtimes/node/utils/zip.ts index bf2ddfd97..70515aa6d 100644 --- a/src/runtimes/node/utils/zip.ts +++ b/src/runtimes/node/utils/zip.ts @@ -1,6 +1,6 @@ import { Buffer } from 'buffer' import { Stats } from 'fs' -import { mkdir, rm, writeFile } from 'fs/promises' +import { mkdir, readlink as readLink, rm, symlink, writeFile } from 'fs/promises' import os from 'os' import { basename, extname, join } from 'path' @@ -68,6 +68,7 @@ const addBootstrapFile = function (srcFiles: string[], aliases: Map() + // Copying source files. await pMap( srcFiles, - (srcFile) => { + async (srcFile) => { const destPath = aliases.get(srcFile) || srcFile const normalizedDestPath = normalizeFilePath({ commonPrefix: basePath, @@ -132,11 +135,29 @@ const createDirectory = async function ({ return mkdirAndWriteFile(absoluteDestPath, rewrites.get(srcFile) as string) } + const stat = await cachedLstat(cache.lstatCache, srcFile) + + // If the path is a symlink, find the link target and add the link to a + // `symlinks` map, which we'll later use to create the symlinks in the + // target directory. We can't do that right now because the target path + // may not have been copied over yet. + if (stat.isSymbolicLink()) { + const targetPath = await readLink(srcFile) + + symlinks.set(targetPath, absoluteDestPath) + + return + } + return copyFile(srcFile, absoluteDestPath) }, { concurrency: COPY_FILE_CONCURRENCY }, ) + await pMap([...symlinks.entries()], ([target, path]) => symlink(target, path), { + concurrency: COPY_FILE_CONCURRENCY, + }) + return { path: functionFolder, entryFilename } } diff --git a/tests/fixtures/pnpm-esm-v2/netlify/functions/test.ts b/tests/fixtures/pnpm-esm-v2/netlify/functions/test.ts new file mode 100644 index 000000000..408b5daf5 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/netlify/functions/test.ts @@ -0,0 +1,11 @@ +import filenamify from 'filenamify'; + +export default function handler(event, context) { + return new Response(filenamify('foo/bar'), { + headers: { 'content-type': 'text/plain' }, + }); +} + +export const config = { + paths: "/api" +} \ No newline at end of file diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.modules.yaml b/tests/fixtures/pnpm-esm-v2/node_modules/.modules.yaml new file mode 100644 index 000000000..9fb1da632 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.modules.yaml @@ -0,0 +1,23 @@ +hoistPattern: + - '*' +hoistedDependencies: + /filename-reserved-regex/3.0.0: + filename-reserved-regex: private +included: + dependencies: true + devDependencies: true + optionalDependencies: true +injectedDeps: {} +layoutVersion: 5 +nodeLinker: isolated +packageManager: pnpm@7.11.0 +pendingBuilds: [] +prunedAt: Wed, 01 Nov 2023 09:32:20 GMT +publicHoistPattern: + - '*eslint*' + - '*prettier*' +registries: + default: https://registry.npmjs.org/ +skipped: [] +storeDir: /Users/eduardoboucas/Library/pnpm/store/v3 +virtualStoreDir: .pnpm diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/index.js b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/index.js new file mode 100644 index 000000000..632d5a152 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/index.js @@ -0,0 +1,9 @@ +/* eslint-disable no-control-regex */ + +export default function filenameReservedRegex() { + return /[<>:"/\\|?*\u0000-\u001F]/g; +} + +export function windowsReservedNameRegex() { + return /^(con|prn|aux|nul|com\d|lpt\d)$/i; +} diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/license b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/license new file mode 100644 index 000000000..fa7ceba3e --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/package.json b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/package.json new file mode 100644 index 000000000..2f31acd1b --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/package.json @@ -0,0 +1,35 @@ +{ + "name": "filename-reserved-regex", + "version": "3.0.0", + "description": "Regular expression for matching reserved filename characters", + "license": "MIT", + "repository": "sindresorhus/filename-reserved-regex", + "funding": "https://github.com/sponsors/sindresorhus", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "type": "module", + "exports": "./index.js", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "scripts": { + "test": "xo && ava" + }, + "files": [ + "index.js" + ], + "keywords": [ + "regex", + "regexp", + "filename", + "reserved", + "illegal" + ], + "devDependencies": { + "ava": "^3.15.0", + "xo": "^0.44.0" + } +} diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/readme.md b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/readme.md new file mode 100644 index 000000000..b2e36242b --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex/readme.md @@ -0,0 +1,42 @@ +# filename-reserved-regex + +> Regular expression for matching reserved filename characters + +On Unix-like systems `/` is reserved and [`<>:"/\|?*`](https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions) as well as non-printable characters `\u0000-\u001F` on Windows. + +## Install + +``` +$ npm install filename-reserved-regex +``` + +## Usage + +```js +import filenameReservedRegex, {windowsReservedNameRegex} from 'filename-reserved-regex'; + +filenameReservedRegex().test('foo/bar'); +//=> true + +filenameReservedRegex().test('foo-bar'); +//=> false + +'foo/bar'.replace(filenameReservedRegex(), '!'); +//=> 'foo!bar' + +windowsReservedNameRegex().test('aux'); +//=> true +``` + +## API + +### filenameReservedRegex() + +Returns a regex that matches all invalid characters. + +### windowsReservedNameRegex() + +Returns an exact-match case-insensitive regex that matches invalid Windows +filenames. These include `CON`, `PRN`, `AUX`, `NUL`, `COM1`, `COM2`, `COM3`, `COM4`, `COM5`, +`COM6`, `COM7`, `COM8`, `COM9`, `LPT1`, `LPT2`, `LPT3`, `LPT4`, `LPT5`, `LPT6`, `LPT7`, `LPT8` +and `LPT9`. diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filename-reserved-regex b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filename-reserved-regex new file mode 120000 index 000000000..64fdfc11a --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filename-reserved-regex @@ -0,0 +1 @@ +../../filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex \ No newline at end of file diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify-path.d.ts b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify-path.d.ts new file mode 100644 index 000000000..aa76cf02e --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify-path.d.ts @@ -0,0 +1,16 @@ +import {type Options} from './filenamify.js'; + +/** +Convert the filename in a path a valid filename and return the augmented path. + +@example +``` +import {filenamifyPath} from 'filenamify'; + +filenamifyPath('foo:bar'); +//=> 'foo!bar' +``` +*/ +export default function filenamifyPath(path: string, options?: Options): string; + +export type {Options} from './filenamify.js'; diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify-path.js b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify-path.js new file mode 100644 index 000000000..101e0f56b --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify-path.js @@ -0,0 +1,7 @@ +import path from 'node:path'; +import filenamify from './filenamify.js'; + +export default function filenamifyPath(filePath, options) { + filePath = path.resolve(filePath); + return path.join(path.dirname(filePath), filenamify(path.basename(filePath), options)); +} diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify.d.ts b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify.d.ts new file mode 100644 index 000000000..f67159b55 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify.d.ts @@ -0,0 +1,37 @@ +export type Options = { + /** + String to use as replacement for reserved filename characters. + + Cannot contain: `<` `>` `:` `"` `/` `\` `|` `?` `*` + + @default '!' + */ + readonly replacement?: string; + + /** + Truncate the filename to the given length. + + Only the base of the filename is truncated, preserving the extension. If the extension itself is longer than `maxLength`, you will get a string that is longer than `maxLength`, so you need to check for that if you allow arbitrary extensions. + + Systems generally allow up to 255 characters, but we default to 100 for usability reasons. + + @default 100 + */ + readonly maxLength?: number; +}; + +/** +Convert a string to a valid filename. + +@example +``` +import filenamify from 'filenamify'; + +filenamify(''); +//=> '!foo!bar!' + +filenamify('foo:"bar"', {replacement: '🐴'}); +//=> 'foo🐴bar🐴' +``` +*/ +export default function filenamify(string: string, options?: Options): string; diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify.js b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify.js new file mode 100644 index 000000000..728c16fa8 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/filenamify.js @@ -0,0 +1,61 @@ +import filenameReservedRegex, {windowsReservedNameRegex} from 'filename-reserved-regex'; + +// Doesn't make sense to have longer filenames +const MAX_FILENAME_LENGTH = 100; + +const reRelativePath = /^\.+(\\|\/)|^\.+$/; +const reTrailingPeriods = /\.+$/; + +export default function filenamify(string, options = {}) { + const reControlChars = /[\u0000-\u001F\u0080-\u009F]/g; // eslint-disable-line no-control-regex + const reRepeatedReservedCharacters = /([<>:"/\\|?*\u0000-\u001F]){2,}/g; // eslint-disable-line no-control-regex + + if (typeof string !== 'string') { + throw new TypeError('Expected a string'); + } + + const replacement = options.replacement === undefined ? '!' : options.replacement; + + if (filenameReservedRegex().test(replacement) && reControlChars.test(replacement)) { + throw new Error('Replacement string cannot contain reserved filename characters'); + } + + if (replacement.length > 0) { + string = string.replace(reRepeatedReservedCharacters, '$1'); + } + + string = string.normalize('NFD'); + string = string.replace(reRelativePath, replacement); + string = string.replace(filenameReservedRegex(), replacement); + string = string.replace(reControlChars, replacement); + string = string.replace(reTrailingPeriods, ''); + + if (replacement.length > 0) { + const startedWithDot = string[0] === '.'; + + // We removed the whole filename + if (!startedWithDot && string[0] === '.') { + string = replacement + string; + } + + // We removed the whole extension + if (string[string.length - 1] === '.') { + string += replacement; + } + } + + string = windowsReservedNameRegex().test(string) ? string + replacement : string; + const allowedLength = typeof options.maxLength === 'number' ? options.maxLength : MAX_FILENAME_LENGTH; + if (string.length > allowedLength) { + const extensionIndex = string.lastIndexOf('.'); + if (extensionIndex === -1) { + string = string.slice(0, allowedLength); + } else { + const filename = string.slice(0, extensionIndex); + const extension = string.slice(extensionIndex); + string = filename.slice(0, Math.max(1, allowedLength - extension.length)) + extension; + } + } + + return string; +} diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/index.d.ts b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/index.d.ts new file mode 100644 index 000000000..3dbb5b41e --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/index.d.ts @@ -0,0 +1,3 @@ +export {default} from './filenamify.js'; +export * from './filenamify.js'; +export {default as filenamifyPath} from './filenamify-path.js'; diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/index.js b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/index.js new file mode 100644 index 000000000..e32195b7b --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/index.js @@ -0,0 +1,2 @@ +export {default} from './filenamify.js'; +export {default as filenamifyPath} from './filenamify-path.js'; diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/license b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/license new file mode 100644 index 000000000..fa7ceba3e --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/package.json b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/package.json new file mode 100644 index 000000000..91cd83020 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/package.json @@ -0,0 +1,53 @@ +{ + "name": "filenamify", + "version": "6.0.0", + "description": "Convert a string to a valid safe filename", + "license": "MIT", + "repository": "sindresorhus/filenamify", + "funding": "https://github.com/sponsors/sindresorhus", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "type": "module", + "exports": { + ".": "./index.js", + "./browser": "./filenamify.js" + }, + "engines": { + "node": ">=16" + }, + "scripts": { + "test": "xo && ava && tsd" + }, + "files": [ + "filenamify-path.d.ts", + "filenamify-path.js", + "filenamify.d.ts", + "filenamify.js", + "index.d.ts", + "index.js" + ], + "keywords": [ + "filename", + "safe", + "sanitize", + "file", + "name", + "string", + "path", + "filepath", + "convert", + "valid", + "dirname" + ], + "dependencies": { + "filename-reserved-regex": "^3.0.0" + }, + "devDependencies": { + "ava": "^5.2.0", + "tsd": "^0.28.1", + "xo": "^0.54.1" + } +} diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/readme.md b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/readme.md new file mode 100644 index 000000000..8bc3648c2 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/filenamify@6.0.0/node_modules/filenamify/readme.md @@ -0,0 +1,83 @@ +# filenamify + +> Convert a string to a valid safe filename + +On Unix-like systems, `/` is reserved. On Windows, [`<>:"/\|?*`](http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29#naming_conventions) along with trailing periods are reserved. + +## Install + +```sh +npm install filenamify +``` + +## Usage + +```js +import filenamify from 'filenamify'; + +filenamify(''); +//=> '!foo!bar!' + +filenamify('foo:"bar"', {replacement: '🐴'}); +//=> 'foo🐴bar🐴' +``` + +## API + +### filenamify(string, options?) + +Convert a string to a valid filename. + +### filenamifyPath(path, options?) + +Convert the filename in a path a valid filename and return the augmented path. + +```js +import {filenamifyPath} from 'filenamify'; + +filenamifyPath('foo:bar'); +//=> 'foo!bar' +``` + +#### options + +Type: `object` + +##### replacement + +Type: `string`\ +Default: `'!'` + +String to use as replacement for reserved filename characters. + +Cannot contain: `<` `>` `:` `"` `/` `\` `|` `?` `*` + +##### maxLength + +Type: `number`\ +Default: `100` + +Truncate the filename to the given length. + +Only the base of the filename is truncated, preserving the extension. If the extension itself is longer than `maxLength`, you will get a string that is longer than `maxLength`, so you need to check for that if you allow arbitrary extensions. + +Systems generally allow up to 255 characters, but we default to 100 for usability reasons. + +## Browser-only import + +You can also import `filenamify/browser`, which only imports `filenamify` and not `filenamifyPath`, which relies on `path` being available or polyfilled. Importing `filenamify` this way is therefore useful when it is shipped using `webpack` or similar tools, and if `filenamifyPath` is not needed. + +```js +import filenamify from 'filenamify/browser'; + +filenamify(''); +//=> '!foo!bar!' +``` + +## Related + +- [filenamify-cli](https://github.com/sindresorhus/filenamify-cli) - CLI for this module +- [filenamify-url](https://github.com/sindresorhus/filenamify-url) - Convert a URL to a valid filename +- [valid-filename](https://github.com/sindresorhus/valid-filename) - Check if a string is a valid filename +- [unused-filename](https://github.com/sindresorhus/unused-filename) - Get a unused filename by appending a number if it exists +- [slugify](https://github.com/sindresorhus/slugify) - Slugify a string diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/lock.yaml b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/lock.yaml new file mode 100644 index 000000000..898f3bf8a --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/lock.yaml @@ -0,0 +1,21 @@ +lockfileVersion: 5.4 + +specifiers: + filenamify: ^6.0.0 + +dependencies: + filenamify: 6.0.0 + +packages: + + /filename-reserved-regex/3.0.0: + resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /filenamify/6.0.0: + resolution: {integrity: sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==} + engines: {node: '>=16'} + dependencies: + filename-reserved-regex: 3.0.0 + dev: false diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/node_modules/filename-reserved-regex b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/node_modules/filename-reserved-regex new file mode 120000 index 000000000..d65eb8d93 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/.pnpm/node_modules/filename-reserved-regex @@ -0,0 +1 @@ +../filename-reserved-regex@3.0.0/node_modules/filename-reserved-regex \ No newline at end of file diff --git a/tests/fixtures/pnpm-esm-v2/node_modules/filenamify b/tests/fixtures/pnpm-esm-v2/node_modules/filenamify new file mode 120000 index 000000000..71c73fe32 --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/node_modules/filenamify @@ -0,0 +1 @@ +.pnpm/filenamify@6.0.0/node_modules/filenamify \ No newline at end of file diff --git a/tests/fixtures/pnpm-esm-v2/package.json b/tests/fixtures/pnpm-esm-v2/package.json new file mode 100644 index 000000000..342e8acea --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/package.json @@ -0,0 +1,16 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "filenamify": "^6.0.0" + } +} \ No newline at end of file diff --git a/tests/fixtures/pnpm-esm-v2/pnpm-lock.yaml b/tests/fixtures/pnpm-esm-v2/pnpm-lock.yaml new file mode 100644 index 000000000..898f3bf8a --- /dev/null +++ b/tests/fixtures/pnpm-esm-v2/pnpm-lock.yaml @@ -0,0 +1,21 @@ +lockfileVersion: 5.4 + +specifiers: + filenamify: ^6.0.0 + +dependencies: + filenamify: 6.0.0 + +packages: + + /filename-reserved-regex/3.0.0: + resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /filenamify/6.0.0: + resolution: {integrity: sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==} + engines: {node: '>=16'} + dependencies: + filename-reserved-regex: 3.0.0 + dev: false diff --git a/tests/v2api.test.ts b/tests/v2api.test.ts index dd3c1024f..4cd71448a 100644 --- a/tests/v2api.test.ts +++ b/tests/v2api.test.ts @@ -1,6 +1,6 @@ import { readFile } from 'fs/promises' import { join, resolve } from 'path' -import { version as nodeVersion } from 'process' +import { platform, version as nodeVersion } from 'process' import { promisify } from 'util' import merge from 'deepmerge' @@ -12,7 +12,7 @@ import { afterEach, describe, expect, test, vi } from 'vitest' import { ARCHIVE_FORMAT } from '../src/archive.js' import { invokeLambda, readAsBuffer } from './helpers/lambda.js' -import { zipFixture, unzipFiles, importFunctionFile, FIXTURES_ESM_DIR } from './helpers/main.js' +import { zipFixture, unzipFiles, importFunctionFile, FIXTURES_ESM_DIR, FIXTURES_DIR } from './helpers/main.js' import { testMany } from './helpers/test_many.js' const pGlob = promisify(glob) @@ -500,4 +500,44 @@ describe.runIf(semver.gte(nodeVersion, '18.13.0'))('V2 functions API', () => { expect(statusCode).toBe(200) }, ) + + describe('Handles an ESM module installed with pnpm', () => { + test('With `archiveFormat: none`', async (options) => { + const fixtureName = 'pnpm-esm-v2' + const { files, tmpDir } = await zipFixture(join(fixtureName, 'netlify', 'functions'), { + opts: merge(options, { + archiveFormat: ARCHIVE_FORMAT.NONE, + basePath: join(FIXTURES_DIR, fixtureName), + }), + }) + + const [{ name: archive, entryFilename }] = files + const func = await importFunctionFile(`${tmpDir}/${archive}/${entryFilename}`) + const { body: bodyStream, statusCode } = await invokeLambda(func) + const body = await readAsBuffer(bodyStream) + + expect(statusCode).toBe(200) + expect(body).toBe('foo!bar') + }) + + // TODO: Investigate why this is failing on Windows. + test.skipIf(platform === 'win32')('With `archiveFormat: zip`', async (options) => { + const fixtureName = 'pnpm-esm-v2' + const { files } = await zipFixture(join(fixtureName, 'netlify', 'functions'), { + opts: merge(options, { + archiveFormat: ARCHIVE_FORMAT.ZIP, + basePath: join(FIXTURES_DIR, fixtureName), + }), + }) + + const unzippedFunctions = await unzipFiles(files) + + const func = await importFunctionFile(`${unzippedFunctions[0].unzipPath}/${files[0].entryFilename}`) + const { body: bodyStream, statusCode } = await invokeLambda(func) + const body = await readAsBuffer(bodyStream) + + expect(statusCode).toBe(200) + expect(body).toBe('foo!bar') + }) + }) })