@vercel/build-utils 2.12.3-canary.24 → 2.12.3-canary.28

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.
@@ -1,29 +1,21 @@
1
1
  import { Lambda } from './lambda';
2
- import type { BuilderFunctions, BuildOptions } from './types';
2
+ import type { BuildOptions } from './types';
3
3
  /**
4
4
  * Convert legacy Runtime to a Plugin.
5
5
  * @param buildRuntime - a legacy build() function from a Runtime
6
+ * @param packageName - the name of the package, for example `vercel-plugin-python`
6
7
  * @param ext - the file extension, for example `.py`
7
8
  */
8
9
  export declare function convertRuntimeToPlugin(buildRuntime: (options: BuildOptions) => Promise<{
9
10
  output: Lambda;
10
- }>, ext: string): ({ vercelConfig, workPath, }: {
11
- vercelConfig: {
12
- functions?: BuilderFunctions;
13
- regions?: string[];
14
- };
11
+ }>, packageName: string, ext: string): ({ workPath }: {
15
12
  workPath: string;
16
13
  }) => Promise<void>;
17
14
  /**
18
15
  * If `.output/functions-manifest.json` exists, append to the pages
19
- * property. Otherwise write a new file. This will also read `vercel.json`
20
- * and apply relevant `functions` property config.
16
+ * property. Otherwise write a new file.
21
17
  */
22
- export declare function updateFunctionsManifest({ vercelConfig, workPath, pages, }: {
23
- vercelConfig: {
24
- functions?: BuilderFunctions;
25
- regions?: string[];
26
- };
18
+ export declare function updateFunctionsManifest({ workPath, pages, }: {
27
19
  workPath: string;
28
20
  pages: {
29
21
  [key: string]: any;
@@ -9,34 +9,58 @@ const path_1 = require("path");
9
9
  const glob_1 = __importDefault(require("./fs/glob"));
10
10
  const normalize_path_1 = require("./fs/normalize-path");
11
11
  const lambda_1 = require("./lambda");
12
- const minimatch_1 = __importDefault(require("minimatch"));
12
+ const _1 = require(".");
13
13
  /**
14
14
  * Convert legacy Runtime to a Plugin.
15
15
  * @param buildRuntime - a legacy build() function from a Runtime
16
+ * @param packageName - the name of the package, for example `vercel-plugin-python`
16
17
  * @param ext - the file extension, for example `.py`
17
18
  */
18
- function convertRuntimeToPlugin(buildRuntime, ext) {
19
+ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
19
20
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
20
- return async function build({ vercelConfig, workPath, }) {
21
+ return async function build({ workPath }) {
21
22
  const opts = { cwd: workPath };
22
23
  const files = await glob_1.default('**', opts);
23
- delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
24
- const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
24
+ // `.output` was already created by the Build Command, so we have
25
+ // to ensure its contents don't get bundled into the Lambda. Similarily,
26
+ // we don't want to bundle anything from `.vercel` either. Lastly,
27
+ // Builders/Runtimes didn't have `vercel.json` or `now.json`.
28
+ const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
29
+ // We also don't want to provide any files to Runtimes that were ignored
30
+ // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
31
+ const ignoreFilter = await _1.getIgnoreFilter(workPath);
32
+ // We're not passing this as an `ignore` filter to the `glob` function above,
33
+ // so that we can re-use exactly the same `getIgnoreFilter` method that the
34
+ // Build Step uses (literally the same code).
35
+ for (const file in files) {
36
+ const isNative = ignoredPaths.some(item => {
37
+ return file.startsWith(item);
38
+ });
39
+ if (isNative || ignoreFilter(file)) {
40
+ delete files[file];
41
+ }
42
+ }
43
+ const entrypointPattern = `api/**/*${ext}`;
44
+ const entrypoints = await glob_1.default(entrypointPattern, opts);
25
45
  const pages = {};
26
- const { functions = {} } = vercelConfig;
27
- const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
46
+ const pluginName = packageName.replace('vercel-plugin-', '');
47
+ const traceDir = path_1.join(workPath, `.output`, `inputs`,
48
+ // Legacy Runtimes can only provide API Routes, so that's
49
+ // why we can use this prefix for all of them. Here, we have to
50
+ // make sure to not use a cryptic hash name, because people
51
+ // need to be able to easily inspect the output.
52
+ `api-routes-${pluginName}`);
28
53
  await fs_extra_1.default.ensureDir(traceDir);
29
54
  for (const entrypoint of Object.keys(entrypoints)) {
30
- const key = Object.keys(functions).find(src => src === entrypoint || minimatch_1.default(entrypoint, src)) || '';
31
- const config = functions[key] || {};
32
55
  const { output } = await buildRuntime({
33
56
  files,
34
57
  entrypoint,
35
58
  workPath,
36
59
  config: {
37
60
  zeroConfig: true,
38
- includeFiles: config.includeFiles,
39
- excludeFiles: config.excludeFiles,
61
+ },
62
+ meta: {
63
+ avoidTopLevelInstall: true,
40
64
  },
41
65
  });
42
66
  pages[entrypoint] = {
@@ -46,7 +70,6 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
46
70
  maxDuration: output.maxDuration,
47
71
  environment: output.environment,
48
72
  allowQuery: output.allowQuery,
49
- //regions: output.regions,
50
73
  };
51
74
  // @ts-ignore This symbol is a private API
52
75
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
@@ -79,7 +102,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
79
102
  await fs_extra_1.default.ensureDir(path_1.dirname(nft));
80
103
  await fs_extra_1.default.writeFile(nft, json);
81
104
  }
82
- await updateFunctionsManifest({ vercelConfig, workPath, pages });
105
+ await updateFunctionsManifest({ workPath, pages });
83
106
  };
84
107
  }
85
108
  exports.convertRuntimeToPlugin = convertRuntimeToPlugin;
@@ -107,10 +130,9 @@ async function readJson(filePath) {
107
130
  }
108
131
  /**
109
132
  * If `.output/functions-manifest.json` exists, append to the pages
110
- * property. Otherwise write a new file. This will also read `vercel.json`
111
- * and apply relevant `functions` property config.
133
+ * property. Otherwise write a new file.
112
134
  */
113
- async function updateFunctionsManifest({ vercelConfig, workPath, pages, }) {
135
+ async function updateFunctionsManifest({ workPath, pages, }) {
114
136
  const functionsManifestPath = path_1.join(workPath, '.output', 'functions-manifest.json');
115
137
  const functionsManifest = await readJson(functionsManifestPath);
116
138
  if (!functionsManifest.version)
@@ -118,16 +140,7 @@ async function updateFunctionsManifest({ vercelConfig, workPath, pages, }) {
118
140
  if (!functionsManifest.pages)
119
141
  functionsManifest.pages = {};
120
142
  for (const [pageKey, pageConfig] of Object.entries(pages)) {
121
- const fnConfig = await lambda_1.getLambdaOptionsFromFunction({
122
- sourceFile: pageKey,
123
- config: vercelConfig,
124
- });
125
- functionsManifest.pages[pageKey] = {
126
- ...pageConfig,
127
- memory: fnConfig.memory || pageConfig.memory,
128
- maxDuration: fnConfig.maxDuration || pageConfig.maxDuration,
129
- regions: vercelConfig.regions || pageConfig.regions,
130
- };
143
+ functionsManifest.pages[pageKey] = { ...pageConfig };
131
144
  }
132
145
  await fs_extra_1.default.writeFile(functionsManifestPath, JSON.stringify(functionsManifest));
133
146
  }
@@ -0,0 +1 @@
1
+ export default function (downloadPath: string, rootDirectory?: string | undefined): Promise<(p: string) => any>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const ignore_1 = __importDefault(require("ignore"));
9
+ function isCodedError(error) {
10
+ return (error !== null &&
11
+ error !== undefined &&
12
+ error.code !== undefined);
13
+ }
14
+ function clearRelative(s) {
15
+ return s.replace(/(\n|^)\.\//g, '$1');
16
+ }
17
+ async function default_1(downloadPath, rootDirectory) {
18
+ const readFile = async (p) => {
19
+ try {
20
+ return await fs_extra_1.default.readFile(p, 'utf8');
21
+ }
22
+ catch (error) {
23
+ if (error.code === 'ENOENT' ||
24
+ (error instanceof Error && error.message.includes('ENOENT'))) {
25
+ return undefined;
26
+ }
27
+ throw error;
28
+ }
29
+ };
30
+ const vercelIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.vercelignore');
31
+ const nowIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.nowignore');
32
+ const ignoreContents = [];
33
+ try {
34
+ ignoreContents.push(...(await Promise.all([readFile(vercelIgnorePath), readFile(nowIgnorePath)])).filter(Boolean));
35
+ }
36
+ catch (error) {
37
+ if (isCodedError(error) && error.code === 'ENOTDIR') {
38
+ console.log(`Warning: Cannot read ignore file from ${vercelIgnorePath}`);
39
+ }
40
+ else {
41
+ throw error;
42
+ }
43
+ }
44
+ if (ignoreContents.length === 2) {
45
+ throw new Error('Cannot use both a `.vercelignore` and `.nowignore` file. Please delete the `.nowignore` file.');
46
+ }
47
+ if (ignoreContents.length === 0) {
48
+ return () => false;
49
+ }
50
+ const ignoreFilter = ignore_1.default().add(clearRelative(ignoreContents[0]));
51
+ return function (p) {
52
+ // we should not ignore now.json and vercel.json if it asked to.
53
+ // we depend on these files for building the app with sourceless
54
+ if (p === 'now.json' || p === 'vercel.json')
55
+ return false;
56
+ return ignoreFilter.test(p).ignored;
57
+ };
58
+ }
59
+ exports.default = default_1;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import FileBlob from './file-blob';
2
3
  import FileFsRef from './file-fs-ref';
3
4
  import FileRef from './file-ref';
@@ -12,7 +13,8 @@ import { getLatestNodeVersion, getDiscontinuedNodeVersions } from './fs/node-ver
12
13
  import streamToBuffer from './fs/stream-to-buffer';
13
14
  import shouldServe from './should-serve';
14
15
  import debug from './debug';
15
- export { FileBlob, FileFsRef, FileRef, Lambda, createLambda, Prerender, download, DownloadedFiles, getWriteableDirectory, glob, GlobOptions, rename, execAsync, spawnAsync, getScriptName, installDependencies, runPackageJsonScript, execCommand, spawnCommand, walkParentDirs, getNodeBinPath, runNpmInstall, runBundleInstall, runPipInstall, runShellScript, getNodeVersion, getLatestNodeVersion, getDiscontinuedNodeVersions, getSpawnOptions, streamToBuffer, shouldServe, debug, isSymbolicLink, getLambdaOptionsFromFunction, scanParentDirs, };
16
+ import getIgnoreFilter from './get-ignore-filter';
17
+ export { FileBlob, FileFsRef, FileRef, Lambda, createLambda, Prerender, download, DownloadedFiles, getWriteableDirectory, glob, GlobOptions, rename, execAsync, spawnAsync, getScriptName, installDependencies, runPackageJsonScript, execCommand, spawnCommand, walkParentDirs, getNodeBinPath, runNpmInstall, runBundleInstall, runPipInstall, runShellScript, getNodeVersion, getLatestNodeVersion, getDiscontinuedNodeVersions, getSpawnOptions, streamToBuffer, shouldServe, debug, isSymbolicLink, getLambdaOptionsFromFunction, scanParentDirs, getIgnoreFilter, };
16
18
  export { detectBuilders, detectOutputDirectory, detectApiDirectory, detectApiExtensions, } from './detect-builders';
17
19
  export { detectFramework } from './detect-framework';
18
20
  export { DetectorFilesystem } from './detectors/filesystem';
@@ -32,3 +34,8 @@ export declare const isStaticRuntime: (name?: string | undefined) => boolean;
32
34
  * Throws an error if *both* env vars are defined.
33
35
  */
34
36
  export declare const getPlatformEnv: (name: string) => string | undefined;
37
+ /**
38
+ * Helper function for generating file or directories names in `.output/inputs`
39
+ * for dependencies of files provided to the File System API.
40
+ */
41
+ export declare const getInputHash: (source: Buffer | string) => string;
package/dist/index.js CHANGED
@@ -7657,6 +7657,476 @@ IconvLiteDecoderStream.prototype.collect = function(cb) {
7657
7657
 
7658
7658
 
7659
7659
 
7660
+ /***/ }),
7661
+
7662
+ /***/ 3556:
7663
+ /***/ ((module) => {
7664
+
7665
+ // A simple implementation of make-array
7666
+ function make_array (subject) {
7667
+ return Array.isArray(subject)
7668
+ ? subject
7669
+ : [subject]
7670
+ }
7671
+
7672
+ const REGEX_BLANK_LINE = /^\s+$/
7673
+ const REGEX_LEADING_EXCAPED_EXCLAMATION = /^\\!/
7674
+ const REGEX_LEADING_EXCAPED_HASH = /^\\#/
7675
+ const SLASH = '/'
7676
+ const KEY_IGNORE = typeof Symbol !== 'undefined'
7677
+ ? Symbol.for('node-ignore')
7678
+ /* istanbul ignore next */
7679
+ : 'node-ignore'
7680
+
7681
+ const define = (object, key, value) =>
7682
+ Object.defineProperty(object, key, {value})
7683
+
7684
+ const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g
7685
+
7686
+ // Sanitize the range of a regular expression
7687
+ // The cases are complicated, see test cases for details
7688
+ const sanitizeRange = range => range.replace(
7689
+ REGEX_REGEXP_RANGE,
7690
+ (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0)
7691
+ ? match
7692
+ // Invalid range (out of order) which is ok for gitignore rules but
7693
+ // fatal for JavaScript regular expression, so eliminate it.
7694
+ : ''
7695
+ )
7696
+
7697
+ // > If the pattern ends with a slash,
7698
+ // > it is removed for the purpose of the following description,
7699
+ // > but it would only find a match with a directory.
7700
+ // > In other words, foo/ will match a directory foo and paths underneath it,
7701
+ // > but will not match a regular file or a symbolic link foo
7702
+ // > (this is consistent with the way how pathspec works in general in Git).
7703
+ // '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`'
7704
+ // -> ignore-rules will not deal with it, because it costs extra `fs.stat` call
7705
+ // you could use option `mark: true` with `glob`
7706
+
7707
+ // '`foo/`' should not continue with the '`..`'
7708
+ const DEFAULT_REPLACER_PREFIX = [
7709
+
7710
+ // > Trailing spaces are ignored unless they are quoted with backslash ("\")
7711
+ [
7712
+ // (a\ ) -> (a )
7713
+ // (a ) -> (a)
7714
+ // (a \ ) -> (a )
7715
+ /\\?\s+$/,
7716
+ match => match.indexOf('\\') === 0
7717
+ ? ' '
7718
+ : ''
7719
+ ],
7720
+
7721
+ // replace (\ ) with ' '
7722
+ [
7723
+ /\\\s/g,
7724
+ () => ' '
7725
+ ],
7726
+
7727
+ // Escape metacharacters
7728
+ // which is written down by users but means special for regular expressions.
7729
+
7730
+ // > There are 12 characters with special meanings:
7731
+ // > - the backslash \,
7732
+ // > - the caret ^,
7733
+ // > - the dollar sign $,
7734
+ // > - the period or dot .,
7735
+ // > - the vertical bar or pipe symbol |,
7736
+ // > - the question mark ?,
7737
+ // > - the asterisk or star *,
7738
+ // > - the plus sign +,
7739
+ // > - the opening parenthesis (,
7740
+ // > - the closing parenthesis ),
7741
+ // > - and the opening square bracket [,
7742
+ // > - the opening curly brace {,
7743
+ // > These special characters are often called "metacharacters".
7744
+ [
7745
+ /[\\^$.|*+(){]/g,
7746
+ match => `\\${match}`
7747
+ ],
7748
+
7749
+ [
7750
+ // > [abc] matches any character inside the brackets
7751
+ // > (in this case a, b, or c);
7752
+ /\[([^\]/]*)($|\])/g,
7753
+ (match, p1, p2) => p2 === ']'
7754
+ ? `[${sanitizeRange(p1)}]`
7755
+ : `\\${match}`
7756
+ ],
7757
+
7758
+ [
7759
+ // > a question mark (?) matches a single character
7760
+ /(?!\\)\?/g,
7761
+ () => '[^/]'
7762
+ ],
7763
+
7764
+ // leading slash
7765
+ [
7766
+
7767
+ // > A leading slash matches the beginning of the pathname.
7768
+ // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
7769
+ // A leading slash matches the beginning of the pathname
7770
+ /^\//,
7771
+ () => '^'
7772
+ ],
7773
+
7774
+ // replace special metacharacter slash after the leading slash
7775
+ [
7776
+ /\//g,
7777
+ () => '\\/'
7778
+ ],
7779
+
7780
+ [
7781
+ // > A leading "**" followed by a slash means match in all directories.
7782
+ // > For example, "**/foo" matches file or directory "foo" anywhere,
7783
+ // > the same as pattern "foo".
7784
+ // > "**/foo/bar" matches file or directory "bar" anywhere that is directly
7785
+ // > under directory "foo".
7786
+ // Notice that the '*'s have been replaced as '\\*'
7787
+ /^\^*\\\*\\\*\\\//,
7788
+
7789
+ // '**/foo' <-> 'foo'
7790
+ () => '^(?:.*\\/)?'
7791
+ ]
7792
+ ]
7793
+
7794
+ const DEFAULT_REPLACER_SUFFIX = [
7795
+ // starting
7796
+ [
7797
+ // there will be no leading '/'
7798
+ // (which has been replaced by section "leading slash")
7799
+ // If starts with '**', adding a '^' to the regular expression also works
7800
+ /^(?=[^^])/,
7801
+ function startingReplacer () {
7802
+ return !/\/(?!$)/.test(this)
7803
+ // > If the pattern does not contain a slash /,
7804
+ // > Git treats it as a shell glob pattern
7805
+ // Actually, if there is only a trailing slash,
7806
+ // git also treats it as a shell glob pattern
7807
+ ? '(?:^|\\/)'
7808
+
7809
+ // > Otherwise, Git treats the pattern as a shell glob suitable for
7810
+ // > consumption by fnmatch(3)
7811
+ : '^'
7812
+ }
7813
+ ],
7814
+
7815
+ // two globstars
7816
+ [
7817
+ // Use lookahead assertions so that we could match more than one `'/**'`
7818
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
7819
+
7820
+ // Zero, one or several directories
7821
+ // should not use '*', or it will be replaced by the next replacer
7822
+
7823
+ // Check if it is not the last `'/**'`
7824
+ (match, index, str) => index + 6 < str.length
7825
+
7826
+ // case: /**/
7827
+ // > A slash followed by two consecutive asterisks then a slash matches
7828
+ // > zero or more directories.
7829
+ // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on.
7830
+ // '/**/'
7831
+ ? '(?:\\/[^\\/]+)*'
7832
+
7833
+ // case: /**
7834
+ // > A trailing `"/**"` matches everything inside.
7835
+
7836
+ // #21: everything inside but it should not include the current folder
7837
+ : '\\/.+'
7838
+ ],
7839
+
7840
+ // intermediate wildcards
7841
+ [
7842
+ // Never replace escaped '*'
7843
+ // ignore rule '\*' will match the path '*'
7844
+
7845
+ // 'abc.*/' -> go
7846
+ // 'abc.*' -> skip this rule
7847
+ /(^|[^\\]+)\\\*(?=.+)/g,
7848
+
7849
+ // '*.js' matches '.js'
7850
+ // '*.js' doesn't match 'abc'
7851
+ (match, p1) => `${p1}[^\\/]*`
7852
+ ],
7853
+
7854
+ // trailing wildcard
7855
+ [
7856
+ /(\^|\\\/)?\\\*$/,
7857
+ (match, p1) => {
7858
+ const prefix = p1
7859
+ // '\^':
7860
+ // '/*' does not match ''
7861
+ // '/*' does not match everything
7862
+
7863
+ // '\\\/':
7864
+ // 'abc/*' does not match 'abc/'
7865
+ ? `${p1}[^/]+`
7866
+
7867
+ // 'a*' matches 'a'
7868
+ // 'a*' matches 'aa'
7869
+ : '[^/]*'
7870
+
7871
+ return `${prefix}(?=$|\\/$)`
7872
+ }
7873
+ ],
7874
+
7875
+ [
7876
+ // unescape
7877
+ /\\\\\\/g,
7878
+ () => '\\'
7879
+ ]
7880
+ ]
7881
+
7882
+ const POSITIVE_REPLACERS = [
7883
+ ...DEFAULT_REPLACER_PREFIX,
7884
+
7885
+ // 'f'
7886
+ // matches
7887
+ // - /f(end)
7888
+ // - /f/
7889
+ // - (start)f(end)
7890
+ // - (start)f/
7891
+ // doesn't match
7892
+ // - oof
7893
+ // - foo
7894
+ // pseudo:
7895
+ // -> (^|/)f(/|$)
7896
+
7897
+ // ending
7898
+ [
7899
+ // 'js' will not match 'js.'
7900
+ // 'ab' will not match 'abc'
7901
+ /(?:[^*/])$/,
7902
+
7903
+ // 'js*' will not match 'a.js'
7904
+ // 'js/' will not match 'a.js'
7905
+ // 'js' will match 'a.js' and 'a.js/'
7906
+ match => `${match}(?=$|\\/)`
7907
+ ],
7908
+
7909
+ ...DEFAULT_REPLACER_SUFFIX
7910
+ ]
7911
+
7912
+ const NEGATIVE_REPLACERS = [
7913
+ ...DEFAULT_REPLACER_PREFIX,
7914
+
7915
+ // #24, #38
7916
+ // The MISSING rule of [gitignore docs](https://git-scm.com/docs/gitignore)
7917
+ // A negative pattern without a trailing wildcard should not
7918
+ // re-include the things inside that directory.
7919
+
7920
+ // eg:
7921
+ // ['node_modules/*', '!node_modules']
7922
+ // should ignore `node_modules/a.js`
7923
+ [
7924
+ /(?:[^*])$/,
7925
+ match => `${match}(?=$|\\/$)`
7926
+ ],
7927
+
7928
+ ...DEFAULT_REPLACER_SUFFIX
7929
+ ]
7930
+
7931
+ // A simple cache, because an ignore rule only has only one certain meaning
7932
+ const cache = Object.create(null)
7933
+
7934
+ // @param {pattern}
7935
+ const make_regex = (pattern, negative, ignorecase) => {
7936
+ const r = cache[pattern]
7937
+ if (r) {
7938
+ return r
7939
+ }
7940
+
7941
+ const replacers = negative
7942
+ ? NEGATIVE_REPLACERS
7943
+ : POSITIVE_REPLACERS
7944
+
7945
+ const source = replacers.reduce(
7946
+ (prev, current) => prev.replace(current[0], current[1].bind(pattern)),
7947
+ pattern
7948
+ )
7949
+
7950
+ return cache[pattern] = ignorecase
7951
+ ? new RegExp(source, 'i')
7952
+ : new RegExp(source)
7953
+ }
7954
+
7955
+ // > A blank line matches no files, so it can serve as a separator for readability.
7956
+ const checkPattern = pattern => pattern
7957
+ && typeof pattern === 'string'
7958
+ && !REGEX_BLANK_LINE.test(pattern)
7959
+
7960
+ // > A line starting with # serves as a comment.
7961
+ && pattern.indexOf('#') !== 0
7962
+
7963
+ const createRule = (pattern, ignorecase) => {
7964
+ const origin = pattern
7965
+ let negative = false
7966
+
7967
+ // > An optional prefix "!" which negates the pattern;
7968
+ if (pattern.indexOf('!') === 0) {
7969
+ negative = true
7970
+ pattern = pattern.substr(1)
7971
+ }
7972
+
7973
+ pattern = pattern
7974
+ // > Put a backslash ("\") in front of the first "!" for patterns that
7975
+ // > begin with a literal "!", for example, `"\!important!.txt"`.
7976
+ .replace(REGEX_LEADING_EXCAPED_EXCLAMATION, '!')
7977
+ // > Put a backslash ("\") in front of the first hash for patterns that
7978
+ // > begin with a hash.
7979
+ .replace(REGEX_LEADING_EXCAPED_HASH, '#')
7980
+
7981
+ const regex = make_regex(pattern, negative, ignorecase)
7982
+
7983
+ return {
7984
+ origin,
7985
+ pattern,
7986
+ negative,
7987
+ regex
7988
+ }
7989
+ }
7990
+
7991
+ class IgnoreBase {
7992
+ constructor ({
7993
+ ignorecase = true
7994
+ } = {}) {
7995
+ this._rules = []
7996
+ this._ignorecase = ignorecase
7997
+ define(this, KEY_IGNORE, true)
7998
+ this._initCache()
7999
+ }
8000
+
8001
+ _initCache () {
8002
+ this._cache = Object.create(null)
8003
+ }
8004
+
8005
+ // @param {Array.<string>|string|Ignore} pattern
8006
+ add (pattern) {
8007
+ this._added = false
8008
+
8009
+ if (typeof pattern === 'string') {
8010
+ pattern = pattern.split(/\r?\n/g)
8011
+ }
8012
+
8013
+ make_array(pattern).forEach(this._addPattern, this)
8014
+
8015
+ // Some rules have just added to the ignore,
8016
+ // making the behavior changed.
8017
+ if (this._added) {
8018
+ this._initCache()
8019
+ }
8020
+
8021
+ return this
8022
+ }
8023
+
8024
+ // legacy
8025
+ addPattern (pattern) {
8026
+ return this.add(pattern)
8027
+ }
8028
+
8029
+ _addPattern (pattern) {
8030
+ // #32
8031
+ if (pattern && pattern[KEY_IGNORE]) {
8032
+ this._rules = this._rules.concat(pattern._rules)
8033
+ this._added = true
8034
+ return
8035
+ }
8036
+
8037
+ if (checkPattern(pattern)) {
8038
+ const rule = createRule(pattern, this._ignorecase)
8039
+ this._added = true
8040
+ this._rules.push(rule)
8041
+ }
8042
+ }
8043
+
8044
+ filter (paths) {
8045
+ return make_array(paths).filter(path => this._filter(path))
8046
+ }
8047
+
8048
+ createFilter () {
8049
+ return path => this._filter(path)
8050
+ }
8051
+
8052
+ ignores (path) {
8053
+ return !this._filter(path)
8054
+ }
8055
+
8056
+ // @returns `Boolean` true if the `path` is NOT ignored
8057
+ _filter (path, slices) {
8058
+ if (!path) {
8059
+ return false
8060
+ }
8061
+
8062
+ if (path in this._cache) {
8063
+ return this._cache[path]
8064
+ }
8065
+
8066
+ if (!slices) {
8067
+ // path/to/a.js
8068
+ // ['path', 'to', 'a.js']
8069
+ slices = path.split(SLASH)
8070
+ }
8071
+
8072
+ slices.pop()
8073
+
8074
+ return this._cache[path] = slices.length
8075
+ // > It is not possible to re-include a file if a parent directory of
8076
+ // > that file is excluded.
8077
+ // If the path contains a parent directory, check the parent first
8078
+ ? this._filter(slices.join(SLASH) + SLASH, slices)
8079
+ && this._test(path)
8080
+
8081
+ // Or only test the path
8082
+ : this._test(path)
8083
+ }
8084
+
8085
+ // @returns {Boolean} true if a file is NOT ignored
8086
+ _test (path) {
8087
+ // Explicitly define variable type by setting matched to `0`
8088
+ let matched = 0
8089
+
8090
+ this._rules.forEach(rule => {
8091
+ // if matched = true, then we only test negative rules
8092
+ // if matched = false, then we test non-negative rules
8093
+ if (!(matched ^ rule.negative)) {
8094
+ matched = rule.negative ^ rule.regex.test(path)
8095
+ }
8096
+ })
8097
+
8098
+ return !matched
8099
+ }
8100
+ }
8101
+
8102
+ // Windows
8103
+ // --------------------------------------------------------------
8104
+ /* istanbul ignore if */
8105
+ if (
8106
+ // Detect `process` so that it can run in browsers.
8107
+ typeof process !== 'undefined'
8108
+ && (
8109
+ process.env && process.env.IGNORE_TEST_WIN32
8110
+ || process.platform === 'win32'
8111
+ )
8112
+ ) {
8113
+ const filter = IgnoreBase.prototype._filter
8114
+
8115
+ /* eslint no-control-regex: "off" */
8116
+ const make_posix = str => /^\\\\\?\\/.test(str)
8117
+ || /[^\x00-\x80]+/.test(str)
8118
+ ? str
8119
+ : str.replace(/\\/g, '/')
8120
+
8121
+ IgnoreBase.prototype._filter = function filterWin32 (path, slices) {
8122
+ path = make_posix(path)
8123
+ return filter.call(this, path, slices)
8124
+ }
8125
+ }
8126
+
8127
+ module.exports = options => new IgnoreBase(options)
8128
+
8129
+
7660
8130
  /***/ }),
7661
8131
 
7662
8132
  /***/ 9442:
@@ -26274,7 +26744,7 @@ exports.frameworks = [
26274
26744
  name: 'Remix',
26275
26745
  slug: 'remix',
26276
26746
  demo: 'https://remix.examples.vercel.com',
26277
- logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/remix.svg',
26747
+ logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/remix-no-shadow.svg',
26278
26748
  tagline: 'Build Better Websites',
26279
26749
  description: 'A new Remix app — the result of running `npx create-remix`.',
26280
26750
  website: 'https://remix.run',
@@ -32286,34 +32756,58 @@ const path_1 = __webpack_require__(5622);
32286
32756
  const glob_1 = __importDefault(__webpack_require__(4240));
32287
32757
  const normalize_path_1 = __webpack_require__(6261);
32288
32758
  const lambda_1 = __webpack_require__(6721);
32289
- const minimatch_1 = __importDefault(__webpack_require__(9566));
32759
+ const _1 = __webpack_require__(2855);
32290
32760
  /**
32291
32761
  * Convert legacy Runtime to a Plugin.
32292
32762
  * @param buildRuntime - a legacy build() function from a Runtime
32763
+ * @param packageName - the name of the package, for example `vercel-plugin-python`
32293
32764
  * @param ext - the file extension, for example `.py`
32294
32765
  */
32295
- function convertRuntimeToPlugin(buildRuntime, ext) {
32766
+ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32296
32767
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
32297
- return async function build({ vercelConfig, workPath, }) {
32768
+ return async function build({ workPath }) {
32298
32769
  const opts = { cwd: workPath };
32299
32770
  const files = await glob_1.default('**', opts);
32300
- delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
32301
- const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
32771
+ // `.output` was already created by the Build Command, so we have
32772
+ // to ensure its contents don't get bundled into the Lambda. Similarily,
32773
+ // we don't want to bundle anything from `.vercel` either. Lastly,
32774
+ // Builders/Runtimes didn't have `vercel.json` or `now.json`.
32775
+ const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
32776
+ // We also don't want to provide any files to Runtimes that were ignored
32777
+ // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
32778
+ const ignoreFilter = await _1.getIgnoreFilter(workPath);
32779
+ // We're not passing this as an `ignore` filter to the `glob` function above,
32780
+ // so that we can re-use exactly the same `getIgnoreFilter` method that the
32781
+ // Build Step uses (literally the same code).
32782
+ for (const file in files) {
32783
+ const isNative = ignoredPaths.some(item => {
32784
+ return file.startsWith(item);
32785
+ });
32786
+ if (isNative || ignoreFilter(file)) {
32787
+ delete files[file];
32788
+ }
32789
+ }
32790
+ const entrypointPattern = `api/**/*${ext}`;
32791
+ const entrypoints = await glob_1.default(entrypointPattern, opts);
32302
32792
  const pages = {};
32303
- const { functions = {} } = vercelConfig;
32304
- const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
32793
+ const pluginName = packageName.replace('vercel-plugin-', '');
32794
+ const traceDir = path_1.join(workPath, `.output`, `inputs`,
32795
+ // Legacy Runtimes can only provide API Routes, so that's
32796
+ // why we can use this prefix for all of them. Here, we have to
32797
+ // make sure to not use a cryptic hash name, because people
32798
+ // need to be able to easily inspect the output.
32799
+ `api-routes-${pluginName}`);
32305
32800
  await fs_extra_1.default.ensureDir(traceDir);
32306
32801
  for (const entrypoint of Object.keys(entrypoints)) {
32307
- const key = Object.keys(functions).find(src => src === entrypoint || minimatch_1.default(entrypoint, src)) || '';
32308
- const config = functions[key] || {};
32309
32802
  const { output } = await buildRuntime({
32310
32803
  files,
32311
32804
  entrypoint,
32312
32805
  workPath,
32313
32806
  config: {
32314
32807
  zeroConfig: true,
32315
- includeFiles: config.includeFiles,
32316
- excludeFiles: config.excludeFiles,
32808
+ },
32809
+ meta: {
32810
+ avoidTopLevelInstall: true,
32317
32811
  },
32318
32812
  });
32319
32813
  pages[entrypoint] = {
@@ -32323,7 +32817,6 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
32323
32817
  maxDuration: output.maxDuration,
32324
32818
  environment: output.environment,
32325
32819
  allowQuery: output.allowQuery,
32326
- //regions: output.regions,
32327
32820
  };
32328
32821
  // @ts-ignore This symbol is a private API
32329
32822
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
@@ -32356,7 +32849,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
32356
32849
  await fs_extra_1.default.ensureDir(path_1.dirname(nft));
32357
32850
  await fs_extra_1.default.writeFile(nft, json);
32358
32851
  }
32359
- await updateFunctionsManifest({ vercelConfig, workPath, pages });
32852
+ await updateFunctionsManifest({ workPath, pages });
32360
32853
  };
32361
32854
  }
32362
32855
  exports.convertRuntimeToPlugin = convertRuntimeToPlugin;
@@ -32384,10 +32877,9 @@ async function readJson(filePath) {
32384
32877
  }
32385
32878
  /**
32386
32879
  * If `.output/functions-manifest.json` exists, append to the pages
32387
- * property. Otherwise write a new file. This will also read `vercel.json`
32388
- * and apply relevant `functions` property config.
32880
+ * property. Otherwise write a new file.
32389
32881
  */
32390
- async function updateFunctionsManifest({ vercelConfig, workPath, pages, }) {
32882
+ async function updateFunctionsManifest({ workPath, pages, }) {
32391
32883
  const functionsManifestPath = path_1.join(workPath, '.output', 'functions-manifest.json');
32392
32884
  const functionsManifest = await readJson(functionsManifestPath);
32393
32885
  if (!functionsManifest.version)
@@ -32395,16 +32887,7 @@ async function updateFunctionsManifest({ vercelConfig, workPath, pages, }) {
32395
32887
  if (!functionsManifest.pages)
32396
32888
  functionsManifest.pages = {};
32397
32889
  for (const [pageKey, pageConfig] of Object.entries(pages)) {
32398
- const fnConfig = await lambda_1.getLambdaOptionsFromFunction({
32399
- sourceFile: pageKey,
32400
- config: vercelConfig,
32401
- });
32402
- functionsManifest.pages[pageKey] = {
32403
- ...pageConfig,
32404
- memory: fnConfig.memory || pageConfig.memory,
32405
- maxDuration: fnConfig.maxDuration || pageConfig.maxDuration,
32406
- regions: vercelConfig.regions || pageConfig.regions,
32407
- };
32890
+ functionsManifest.pages[pageKey] = { ...pageConfig };
32408
32891
  }
32409
32892
  await fs_extra_1.default.writeFile(functionsManifestPath, JSON.stringify(functionsManifest));
32410
32893
  }
@@ -34440,6 +34923,73 @@ function streamToBuffer(stream) {
34440
34923
  exports.default = streamToBuffer;
34441
34924
 
34442
34925
 
34926
+ /***/ }),
34927
+
34928
+ /***/ 1148:
34929
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
34930
+
34931
+ "use strict";
34932
+
34933
+ var __importDefault = (this && this.__importDefault) || function (mod) {
34934
+ return (mod && mod.__esModule) ? mod : { "default": mod };
34935
+ };
34936
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
34937
+ const path_1 = __importDefault(__webpack_require__(5622));
34938
+ const fs_extra_1 = __importDefault(__webpack_require__(5392));
34939
+ const ignore_1 = __importDefault(__webpack_require__(3556));
34940
+ function isCodedError(error) {
34941
+ return (error !== null &&
34942
+ error !== undefined &&
34943
+ error.code !== undefined);
34944
+ }
34945
+ function clearRelative(s) {
34946
+ return s.replace(/(\n|^)\.\//g, '$1');
34947
+ }
34948
+ async function default_1(downloadPath, rootDirectory) {
34949
+ const readFile = async (p) => {
34950
+ try {
34951
+ return await fs_extra_1.default.readFile(p, 'utf8');
34952
+ }
34953
+ catch (error) {
34954
+ if (error.code === 'ENOENT' ||
34955
+ (error instanceof Error && error.message.includes('ENOENT'))) {
34956
+ return undefined;
34957
+ }
34958
+ throw error;
34959
+ }
34960
+ };
34961
+ const vercelIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.vercelignore');
34962
+ const nowIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.nowignore');
34963
+ const ignoreContents = [];
34964
+ try {
34965
+ ignoreContents.push(...(await Promise.all([readFile(vercelIgnorePath), readFile(nowIgnorePath)])).filter(Boolean));
34966
+ }
34967
+ catch (error) {
34968
+ if (isCodedError(error) && error.code === 'ENOTDIR') {
34969
+ console.log(`Warning: Cannot read ignore file from ${vercelIgnorePath}`);
34970
+ }
34971
+ else {
34972
+ throw error;
34973
+ }
34974
+ }
34975
+ if (ignoreContents.length === 2) {
34976
+ throw new Error('Cannot use both a `.vercelignore` and `.nowignore` file. Please delete the `.nowignore` file.');
34977
+ }
34978
+ if (ignoreContents.length === 0) {
34979
+ return () => false;
34980
+ }
34981
+ const ignoreFilter = ignore_1.default().add(clearRelative(ignoreContents[0]));
34982
+ return function (p) {
34983
+ // we should not ignore now.json and vercel.json if it asked to.
34984
+ // we depend on these files for building the app with sourceless
34985
+ if (p === 'now.json' || p === 'vercel.json')
34986
+ return false;
34987
+ return ignoreFilter.test(p).ignored;
34988
+ };
34989
+ }
34990
+ exports.default = default_1;
34991
+
34992
+
34443
34993
  /***/ }),
34444
34994
 
34445
34995
  /***/ 2855:
@@ -34473,7 +35023,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
34473
35023
  return (mod && mod.__esModule) ? mod : { "default": mod };
34474
35024
  };
34475
35025
  Object.defineProperty(exports, "__esModule", ({ value: true }));
34476
- exports.getPlatformEnv = exports.isStaticRuntime = exports.isOfficialRuntime = exports.updateRoutesManifest = exports.updateFunctionsManifest = exports.convertRuntimeToPlugin = exports.normalizePath = exports.readConfigFile = exports.DetectorFilesystem = exports.detectFramework = exports.detectApiExtensions = exports.detectApiDirectory = exports.detectOutputDirectory = exports.detectBuilders = exports.scanParentDirs = exports.getLambdaOptionsFromFunction = exports.isSymbolicLink = exports.debug = exports.shouldServe = exports.streamToBuffer = exports.getSpawnOptions = exports.getDiscontinuedNodeVersions = exports.getLatestNodeVersion = exports.getNodeVersion = exports.runShellScript = exports.runPipInstall = exports.runBundleInstall = exports.runNpmInstall = exports.getNodeBinPath = exports.walkParentDirs = exports.spawnCommand = exports.execCommand = exports.runPackageJsonScript = exports.installDependencies = exports.getScriptName = exports.spawnAsync = exports.execAsync = exports.rename = exports.glob = exports.getWriteableDirectory = exports.download = exports.Prerender = exports.createLambda = exports.Lambda = exports.FileRef = exports.FileFsRef = exports.FileBlob = void 0;
35026
+ exports.getInputHash = exports.getPlatformEnv = exports.isStaticRuntime = exports.isOfficialRuntime = exports.updateRoutesManifest = exports.updateFunctionsManifest = exports.convertRuntimeToPlugin = exports.normalizePath = exports.readConfigFile = exports.DetectorFilesystem = exports.detectFramework = exports.detectApiExtensions = exports.detectApiDirectory = exports.detectOutputDirectory = exports.detectBuilders = exports.getIgnoreFilter = exports.scanParentDirs = exports.getLambdaOptionsFromFunction = exports.isSymbolicLink = exports.debug = exports.shouldServe = exports.streamToBuffer = exports.getSpawnOptions = exports.getDiscontinuedNodeVersions = exports.getLatestNodeVersion = exports.getNodeVersion = exports.runShellScript = exports.runPipInstall = exports.runBundleInstall = exports.runNpmInstall = exports.getNodeBinPath = exports.walkParentDirs = exports.spawnCommand = exports.execCommand = exports.runPackageJsonScript = exports.installDependencies = exports.getScriptName = exports.spawnAsync = exports.execAsync = exports.rename = exports.glob = exports.getWriteableDirectory = exports.download = exports.Prerender = exports.createLambda = exports.Lambda = exports.FileRef = exports.FileFsRef = exports.FileBlob = void 0;
35027
+ const crypto_1 = __webpack_require__(6417);
34477
35028
  const file_blob_1 = __importDefault(__webpack_require__(2397));
34478
35029
  exports.FileBlob = file_blob_1.default;
34479
35030
  const file_fs_ref_1 = __importDefault(__webpack_require__(9331));
@@ -34522,6 +35073,8 @@ const should_serve_1 = __importDefault(__webpack_require__(2564));
34522
35073
  exports.shouldServe = should_serve_1.default;
34523
35074
  const debug_1 = __importDefault(__webpack_require__(1868));
34524
35075
  exports.debug = debug_1.default;
35076
+ const get_ignore_filter_1 = __importDefault(__webpack_require__(1148));
35077
+ exports.getIgnoreFilter = get_ignore_filter_1.default;
34525
35078
  var detect_builders_1 = __webpack_require__(4246);
34526
35079
  Object.defineProperty(exports, "detectBuilders", ({ enumerable: true, get: function () { return detect_builders_1.detectBuilders; } }));
34527
35080
  Object.defineProperty(exports, "detectOutputDirectory", ({ enumerable: true, get: function () { return detect_builders_1.detectOutputDirectory; } }));
@@ -34581,6 +35134,14 @@ const getPlatformEnv = (name) => {
34581
35134
  return n;
34582
35135
  };
34583
35136
  exports.getPlatformEnv = getPlatformEnv;
35137
+ /**
35138
+ * Helper function for generating file or directories names in `.output/inputs`
35139
+ * for dependencies of files provided to the File System API.
35140
+ */
35141
+ const getInputHash = (source) => {
35142
+ return crypto_1.createHash('sha1').update(source).digest('hex');
35143
+ };
35144
+ exports.getInputHash = getInputHash;
34584
35145
 
34585
35146
 
34586
35147
  /***/ }),
@@ -34970,6 +35531,14 @@ module.exports = require("constants");
34970
35531
 
34971
35532
  /***/ }),
34972
35533
 
35534
+ /***/ 6417:
35535
+ /***/ ((module) => {
35536
+
35537
+ "use strict";
35538
+ module.exports = require("crypto");
35539
+
35540
+ /***/ }),
35541
+
34973
35542
  /***/ 8614:
34974
35543
  /***/ ((module) => {
34975
35544
 
package/dist/types.d.ts CHANGED
@@ -51,6 +51,7 @@ export interface Meta {
51
51
  filesRemoved?: string[];
52
52
  env?: Env;
53
53
  buildEnv?: Env;
54
+ avoidTopLevelInstall?: boolean;
54
55
  }
55
56
  export interface AnalyzeOptions {
56
57
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "2.12.3-canary.24",
3
+ "version": "2.12.3-canary.28",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -30,7 +30,7 @@
30
30
  "@types/node-fetch": "^2.1.6",
31
31
  "@types/semver": "6.0.0",
32
32
  "@types/yazl": "^2.4.1",
33
- "@vercel/frameworks": "0.5.1-canary.14",
33
+ "@vercel/frameworks": "0.5.1-canary.16",
34
34
  "@vercel/ncc": "0.24.0",
35
35
  "aggregate-error": "3.0.1",
36
36
  "async-retry": "1.2.3",
@@ -49,5 +49,5 @@
49
49
  "typescript": "4.3.4",
50
50
  "yazl": "2.4.3"
51
51
  },
52
- "gitHead": "3559531e4c14875a275059e3f43aeba38deda275"
52
+ "gitHead": "792ab38760eca4543a7ac02dd05eda280b5328a1"
53
53
  }