@vercel/build-utils 2.12.3-canary.27 → 2.12.3-canary.30

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.
@@ -3,11 +3,12 @@ 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): ({ workPath }: {
11
+ }>, packageName: string, ext: string): ({ workPath }: {
11
12
  workPath: string;
12
13
  }) => Promise<void>;
13
14
  /**
@@ -9,20 +9,54 @@ 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 _1 = require(".");
13
+ // `.output` was already created by the Build Command, so we have
14
+ // to ensure its contents don't get bundled into the Lambda. Similarily,
15
+ // we don't want to bundle anything from `.vercel` either. Lastly,
16
+ // Builders/Runtimes didn't have `vercel.json` or `now.json`.
17
+ const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
18
+ const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
19
+ const isNative = ignoredPaths.some(item => {
20
+ return file.startsWith(item);
21
+ });
22
+ if (!ignoreFile) {
23
+ return isNative;
24
+ }
25
+ return isNative || ignoreFilter(file);
26
+ };
12
27
  /**
13
28
  * Convert legacy Runtime to a Plugin.
14
29
  * @param buildRuntime - a legacy build() function from a Runtime
30
+ * @param packageName - the name of the package, for example `vercel-plugin-python`
15
31
  * @param ext - the file extension, for example `.py`
16
32
  */
17
- function convertRuntimeToPlugin(buildRuntime, ext) {
33
+ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
18
34
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
19
35
  return async function build({ workPath }) {
20
36
  const opts = { cwd: workPath };
21
37
  const files = await glob_1.default('**', opts);
22
- delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
23
- const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
38
+ // We also don't want to provide any files to Runtimes that were ignored
39
+ // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
40
+ const ignoreFilter = await _1.getIgnoreFilter(workPath);
41
+ // We're not passing this as an `ignore` filter to the `glob` function above,
42
+ // so that we can re-use exactly the same `getIgnoreFilter` method that the
43
+ // Build Step uses (literally the same code). Note that this exclusion only applies
44
+ // when deploying. Locally, another exclusion further below is needed.
45
+ for (const file in files) {
46
+ if (shouldIgnorePath(file, ignoreFilter, true)) {
47
+ delete files[file];
48
+ }
49
+ }
50
+ const entrypointPattern = `api/**/*${ext}`;
51
+ const entrypoints = await glob_1.default(entrypointPattern, opts);
24
52
  const pages = {};
25
- const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
53
+ const pluginName = packageName.replace('vercel-plugin-', '');
54
+ const traceDir = path_1.join(workPath, `.output`, `inputs`,
55
+ // Legacy Runtimes can only provide API Routes, so that's
56
+ // why we can use this prefix for all of them. Here, we have to
57
+ // make sure to not use a cryptic hash name, because people
58
+ // need to be able to easily inspect the output.
59
+ `api-routes-${pluginName}`);
26
60
  await fs_extra_1.default.ensureDir(traceDir);
27
61
  for (const entrypoint of Object.keys(entrypoints)) {
28
62
  const { output } = await buildRuntime({
@@ -46,6 +80,15 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
46
80
  };
47
81
  // @ts-ignore This symbol is a private API
48
82
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
83
+ // When deploying, the `files` that are passed to the Legacy Runtimes already
84
+ // have certain files that are ignored stripped, but locally, that list of
85
+ // files isn't used by the Legacy Runtimes, so we need to apply the filters
86
+ // to the outputs that they are returning instead.
87
+ for (const file in lambdaFiles) {
88
+ if (shouldIgnorePath(file, ignoreFilter, false)) {
89
+ delete lambdaFiles[file];
90
+ }
91
+ }
49
92
  const entry = path_1.join(workPath, '.output', 'server', 'pages', entrypoint);
50
93
  await fs_extra_1.default.ensureDir(path_1.dirname(entry));
51
94
  await linkOrCopy(files[entrypoint].fsPath, entry);
@@ -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:
@@ -32286,20 +32756,54 @@ 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);
32759
+ const _1 = __webpack_require__(2855);
32760
+ // `.output` was already created by the Build Command, so we have
32761
+ // to ensure its contents don't get bundled into the Lambda. Similarily,
32762
+ // we don't want to bundle anything from `.vercel` either. Lastly,
32763
+ // Builders/Runtimes didn't have `vercel.json` or `now.json`.
32764
+ const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
32765
+ const shouldIgnorePath = (file, ignoreFilter, ignoreFile) => {
32766
+ const isNative = ignoredPaths.some(item => {
32767
+ return file.startsWith(item);
32768
+ });
32769
+ if (!ignoreFile) {
32770
+ return isNative;
32771
+ }
32772
+ return isNative || ignoreFilter(file);
32773
+ };
32289
32774
  /**
32290
32775
  * Convert legacy Runtime to a Plugin.
32291
32776
  * @param buildRuntime - a legacy build() function from a Runtime
32777
+ * @param packageName - the name of the package, for example `vercel-plugin-python`
32292
32778
  * @param ext - the file extension, for example `.py`
32293
32779
  */
32294
- function convertRuntimeToPlugin(buildRuntime, ext) {
32780
+ function convertRuntimeToPlugin(buildRuntime, packageName, ext) {
32295
32781
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
32296
32782
  return async function build({ workPath }) {
32297
32783
  const opts = { cwd: workPath };
32298
32784
  const files = await glob_1.default('**', opts);
32299
- delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
32300
- const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
32785
+ // We also don't want to provide any files to Runtimes that were ignored
32786
+ // through `.vercelignore` or `.nowignore`, because the Build Step does the same.
32787
+ const ignoreFilter = await _1.getIgnoreFilter(workPath);
32788
+ // We're not passing this as an `ignore` filter to the `glob` function above,
32789
+ // so that we can re-use exactly the same `getIgnoreFilter` method that the
32790
+ // Build Step uses (literally the same code). Note that this exclusion only applies
32791
+ // when deploying. Locally, another exclusion further below is needed.
32792
+ for (const file in files) {
32793
+ if (shouldIgnorePath(file, ignoreFilter, true)) {
32794
+ delete files[file];
32795
+ }
32796
+ }
32797
+ const entrypointPattern = `api/**/*${ext}`;
32798
+ const entrypoints = await glob_1.default(entrypointPattern, opts);
32301
32799
  const pages = {};
32302
- const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
32800
+ const pluginName = packageName.replace('vercel-plugin-', '');
32801
+ const traceDir = path_1.join(workPath, `.output`, `inputs`,
32802
+ // Legacy Runtimes can only provide API Routes, so that's
32803
+ // why we can use this prefix for all of them. Here, we have to
32804
+ // make sure to not use a cryptic hash name, because people
32805
+ // need to be able to easily inspect the output.
32806
+ `api-routes-${pluginName}`);
32303
32807
  await fs_extra_1.default.ensureDir(traceDir);
32304
32808
  for (const entrypoint of Object.keys(entrypoints)) {
32305
32809
  const { output } = await buildRuntime({
@@ -32323,6 +32827,15 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
32323
32827
  };
32324
32828
  // @ts-ignore This symbol is a private API
32325
32829
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
32830
+ // When deploying, the `files` that are passed to the Legacy Runtimes already
32831
+ // have certain files that are ignored stripped, but locally, that list of
32832
+ // files isn't used by the Legacy Runtimes, so we need to apply the filters
32833
+ // to the outputs that they are returning instead.
32834
+ for (const file in lambdaFiles) {
32835
+ if (shouldIgnorePath(file, ignoreFilter, false)) {
32836
+ delete lambdaFiles[file];
32837
+ }
32838
+ }
32326
32839
  const entry = path_1.join(workPath, '.output', 'server', 'pages', entrypoint);
32327
32840
  await fs_extra_1.default.ensureDir(path_1.dirname(entry));
32328
32841
  await linkOrCopy(files[entrypoint].fsPath, entry);
@@ -34426,6 +34939,73 @@ function streamToBuffer(stream) {
34426
34939
  exports.default = streamToBuffer;
34427
34940
 
34428
34941
 
34942
+ /***/ }),
34943
+
34944
+ /***/ 1148:
34945
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
34946
+
34947
+ "use strict";
34948
+
34949
+ var __importDefault = (this && this.__importDefault) || function (mod) {
34950
+ return (mod && mod.__esModule) ? mod : { "default": mod };
34951
+ };
34952
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
34953
+ const path_1 = __importDefault(__webpack_require__(5622));
34954
+ const fs_extra_1 = __importDefault(__webpack_require__(5392));
34955
+ const ignore_1 = __importDefault(__webpack_require__(3556));
34956
+ function isCodedError(error) {
34957
+ return (error !== null &&
34958
+ error !== undefined &&
34959
+ error.code !== undefined);
34960
+ }
34961
+ function clearRelative(s) {
34962
+ return s.replace(/(\n|^)\.\//g, '$1');
34963
+ }
34964
+ async function default_1(downloadPath, rootDirectory) {
34965
+ const readFile = async (p) => {
34966
+ try {
34967
+ return await fs_extra_1.default.readFile(p, 'utf8');
34968
+ }
34969
+ catch (error) {
34970
+ if (error.code === 'ENOENT' ||
34971
+ (error instanceof Error && error.message.includes('ENOENT'))) {
34972
+ return undefined;
34973
+ }
34974
+ throw error;
34975
+ }
34976
+ };
34977
+ const vercelIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.vercelignore');
34978
+ const nowIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.nowignore');
34979
+ const ignoreContents = [];
34980
+ try {
34981
+ ignoreContents.push(...(await Promise.all([readFile(vercelIgnorePath), readFile(nowIgnorePath)])).filter(Boolean));
34982
+ }
34983
+ catch (error) {
34984
+ if (isCodedError(error) && error.code === 'ENOTDIR') {
34985
+ console.log(`Warning: Cannot read ignore file from ${vercelIgnorePath}`);
34986
+ }
34987
+ else {
34988
+ throw error;
34989
+ }
34990
+ }
34991
+ if (ignoreContents.length === 2) {
34992
+ throw new Error('Cannot use both a `.vercelignore` and `.nowignore` file. Please delete the `.nowignore` file.');
34993
+ }
34994
+ if (ignoreContents.length === 0) {
34995
+ return () => false;
34996
+ }
34997
+ const ignoreFilter = ignore_1.default().add(clearRelative(ignoreContents[0]));
34998
+ return function (p) {
34999
+ // we should not ignore now.json and vercel.json if it asked to.
35000
+ // we depend on these files for building the app with sourceless
35001
+ if (p === 'now.json' || p === 'vercel.json')
35002
+ return false;
35003
+ return ignoreFilter.test(p).ignored;
35004
+ };
35005
+ }
35006
+ exports.default = default_1;
35007
+
35008
+
34429
35009
  /***/ }),
34430
35010
 
34431
35011
  /***/ 2855:
@@ -34459,7 +35039,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
34459
35039
  return (mod && mod.__esModule) ? mod : { "default": mod };
34460
35040
  };
34461
35041
  Object.defineProperty(exports, "__esModule", ({ value: true }));
34462
- 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;
35042
+ 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;
35043
+ const crypto_1 = __webpack_require__(6417);
34463
35044
  const file_blob_1 = __importDefault(__webpack_require__(2397));
34464
35045
  exports.FileBlob = file_blob_1.default;
34465
35046
  const file_fs_ref_1 = __importDefault(__webpack_require__(9331));
@@ -34508,6 +35089,8 @@ const should_serve_1 = __importDefault(__webpack_require__(2564));
34508
35089
  exports.shouldServe = should_serve_1.default;
34509
35090
  const debug_1 = __importDefault(__webpack_require__(1868));
34510
35091
  exports.debug = debug_1.default;
35092
+ const get_ignore_filter_1 = __importDefault(__webpack_require__(1148));
35093
+ exports.getIgnoreFilter = get_ignore_filter_1.default;
34511
35094
  var detect_builders_1 = __webpack_require__(4246);
34512
35095
  Object.defineProperty(exports, "detectBuilders", ({ enumerable: true, get: function () { return detect_builders_1.detectBuilders; } }));
34513
35096
  Object.defineProperty(exports, "detectOutputDirectory", ({ enumerable: true, get: function () { return detect_builders_1.detectOutputDirectory; } }));
@@ -34567,6 +35150,14 @@ const getPlatformEnv = (name) => {
34567
35150
  return n;
34568
35151
  };
34569
35152
  exports.getPlatformEnv = getPlatformEnv;
35153
+ /**
35154
+ * Helper function for generating file or directories names in `.output/inputs`
35155
+ * for dependencies of files provided to the File System API.
35156
+ */
35157
+ const getInputHash = (source) => {
35158
+ return crypto_1.createHash('sha1').update(source).digest('hex');
35159
+ };
35160
+ exports.getInputHash = getInputHash;
34570
35161
 
34571
35162
 
34572
35163
  /***/ }),
@@ -34956,6 +35547,14 @@ module.exports = require("constants");
34956
35547
 
34957
35548
  /***/ }),
34958
35549
 
35550
+ /***/ 6417:
35551
+ /***/ ((module) => {
35552
+
35553
+ "use strict";
35554
+ module.exports = require("crypto");
35555
+
35556
+ /***/ }),
35557
+
34959
35558
  /***/ 8614:
34960
35559
  /***/ ((module) => {
34961
35560
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "2.12.3-canary.27",
3
+ "version": "2.12.3-canary.30",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -49,5 +49,5 @@
49
49
  "typescript": "4.3.4",
50
50
  "yazl": "2.4.3"
51
51
  },
52
- "gitHead": "5499fa9a042ef4f44cd4a48f2a168bf5c6d164f5"
52
+ "gitHead": "9227471acaa7102c0e37b338c6ebcc05cbc95486"
53
53
  }