@vinktarhq/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/LICENSE +21 -0
- package/README.md +378 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +28 -0
- package/dist/bin.js.map +1 -0
- package/dist/bundler/core.d.ts +140 -0
- package/dist/bundler/core.js +320 -0
- package/dist/bundler/core.js.map +1 -0
- package/dist/bundler/esbuild.d.ts +44 -0
- package/dist/bundler/esbuild.js +85 -0
- package/dist/bundler/esbuild.js.map +1 -0
- package/dist/bundler/rollup.d.ts +84 -0
- package/dist/bundler/rollup.js +221 -0
- package/dist/bundler/rollup.js.map +1 -0
- package/dist/bundler/rspack.d.ts +8 -0
- package/dist/bundler/rspack.js +8 -0
- package/dist/bundler/rspack.js.map +1 -0
- package/dist/bundler/webpack.d.ts +83 -0
- package/dist/bundler/webpack.js +104 -0
- package/dist/bundler/webpack.js.map +1 -0
- package/dist/cjs/bundler/core.d.ts +140 -0
- package/dist/cjs/bundler/core.js +331 -0
- package/dist/cjs/bundler/esbuild.d.ts +44 -0
- package/dist/cjs/bundler/esbuild.js +87 -0
- package/dist/cjs/bundler/rollup.d.ts +84 -0
- package/dist/cjs/bundler/rollup.js +226 -0
- package/dist/cjs/bundler/rspack.d.ts +8 -0
- package/dist/cjs/bundler/rspack.js +12 -0
- package/dist/cjs/bundler/webpack.d.ts +83 -0
- package/dist/cjs/bundler/webpack.js +107 -0
- package/dist/cjs/cli.d.ts +17 -0
- package/dist/cjs/cli.js +358 -0
- package/dist/cjs/commands/doctor.d.ts +15 -0
- package/dist/cjs/commands/doctor.js +134 -0
- package/dist/cjs/commands/inject.d.ts +70 -0
- package/dist/cjs/commands/inject.js +123 -0
- package/dist/cjs/commands/resolve.d.ts +32 -0
- package/dist/cjs/commands/resolve.js +130 -0
- package/dist/cjs/commands/upload.d.ts +74 -0
- package/dist/cjs/commands/upload.js +254 -0
- package/dist/cjs/config.d.ts +51 -0
- package/dist/cjs/config.js +152 -0
- package/dist/cjs/debug-id.d.ts +176 -0
- package/dist/cjs/debug-id.js +323 -0
- package/dist/cjs/discover.d.ts +50 -0
- package/dist/cjs/discover.js +235 -0
- package/dist/cjs/env.d.ts +22 -0
- package/dist/cjs/env.js +52 -0
- package/dist/cjs/glob.d.ts +34 -0
- package/dist/cjs/glob.js +112 -0
- package/dist/cjs/http.d.ts +68 -0
- package/dist/cjs/http.js +211 -0
- package/dist/cjs/index.d.ts +17 -0
- package/dist/cjs/index.js +53 -0
- package/dist/cjs/limits.d.ts +35 -0
- package/dist/cjs/limits.js +38 -0
- package/dist/cjs/multipart.d.ts +28 -0
- package/dist/cjs/multipart.js +44 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/upload.d.ts +178 -0
- package/dist/cjs/upload.js +394 -0
- package/dist/cjs/url.d.ts +25 -0
- package/dist/cjs/url.js +43 -0
- package/dist/cjs/version.d.ts +10 -0
- package/dist/cjs/version.js +13 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.js +354 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +15 -0
- package/dist/commands/doctor.js +132 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/inject.d.ts +70 -0
- package/dist/commands/inject.js +120 -0
- package/dist/commands/inject.js.map +1 -0
- package/dist/commands/resolve.d.ts +32 -0
- package/dist/commands/resolve.js +128 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/upload.d.ts +74 -0
- package/dist/commands/upload.js +252 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.js +150 -0
- package/dist/config.js.map +1 -0
- package/dist/debug-id.d.ts +176 -0
- package/dist/debug-id.js +307 -0
- package/dist/debug-id.js.map +1 -0
- package/dist/discover.d.ts +50 -0
- package/dist/discover.js +229 -0
- package/dist/discover.js.map +1 -0
- package/dist/env.d.ts +22 -0
- package/dist/env.js +50 -0
- package/dist/env.js.map +1 -0
- package/dist/glob.d.ts +34 -0
- package/dist/glob.js +109 -0
- package/dist/glob.js.map +1 -0
- package/dist/http.d.ts +68 -0
- package/dist/http.js +203 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +35 -0
- package/dist/limits.js +36 -0
- package/dist/limits.js.map +1 -0
- package/dist/multipart.d.ts +28 -0
- package/dist/multipart.js +41 -0
- package/dist/multipart.js.map +1 -0
- package/dist/upload.d.ts +178 -0
- package/dist/upload.js +383 -0
- package/dist/upload.js.map +1 -0
- package/dist/url.d.ts +25 -0
- package/dist/url.js +40 -0
- package/dist/url.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/dist/vite.d.ts +74 -0
- package/dist/vite.js +166 -0
- package/dist/vite.js.map +1 -0
- package/package.json +141 -0
package/dist/discover.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { open, readdir, realpath, stat } from 'node:fs/promises';
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { matches } from './glob.js';
|
|
4
|
+
// Entry names, matched against a single directory name. `.next/cache` used to be in here and
|
|
5
|
+
// could never match anything, because a directory entry is never a path.
|
|
6
|
+
const SKIP_DIRECTORIES = new Set(['node_modules', '.git', 'coverage', 'cache']);
|
|
7
|
+
/** What counts as a chunk, absent `--ext`. */
|
|
8
|
+
export const DEFAULT_EXTENSIONS = ['js', 'cjs', 'mjs'];
|
|
9
|
+
/**
|
|
10
|
+
* `//# sourceMappingURL=`, and the legacy `//@` spelling some older toolchains still emit.
|
|
11
|
+
*
|
|
12
|
+
* Matched line-anchored so the string appearing inside a bundled literal — a tool that writes these
|
|
13
|
+
* comments, bundled into an application — cannot be mistaken for a real reference.
|
|
14
|
+
*/
|
|
15
|
+
const SOURCE_MAPPING_COMMENT = /^\/\/[#@] sourceMappingURL=(.*)$/gm;
|
|
16
|
+
/** How much of a chunk's tail is searched for the reference. It is emitted as the final line. */
|
|
17
|
+
const TAIL_BYTES = 65_536;
|
|
18
|
+
export async function discover(root, options = {}) {
|
|
19
|
+
const warnings = [];
|
|
20
|
+
const files = await walk(root, new Set());
|
|
21
|
+
const script = extensionMatcher(options.extensions);
|
|
22
|
+
const ignore = options.ignore ?? [];
|
|
23
|
+
const scripts = files
|
|
24
|
+
.filter((file) => script.test(file))
|
|
25
|
+
.filter((file) => !matches(relative(root, file).split(sep).join('/'), ignore))
|
|
26
|
+
.sort((a, b) => a.localeCompare(b));
|
|
27
|
+
const present = new Set(files);
|
|
28
|
+
const resolved = [];
|
|
29
|
+
for (const file of scripts) {
|
|
30
|
+
resolved.push(await locate(file, present, warnings));
|
|
31
|
+
}
|
|
32
|
+
return { artifacts: assign(resolved, root, warnings), warnings };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The map for one chunk: what it says, then what sits beside it.
|
|
36
|
+
*
|
|
37
|
+
* Asking the chunk first is not a refinement, it is the difference between working and not. A
|
|
38
|
+
* build configured with `sourcemapFileNames`, webpack's `sourceMapFilename`, or any output that
|
|
39
|
+
* puts maps in their own directory has no `<file>.map` sibling at all, so guessing alone found
|
|
40
|
+
* nothing and uploaded nothing, without a word.
|
|
41
|
+
*/
|
|
42
|
+
async function locate(file, present, warnings) {
|
|
43
|
+
const referenced = await reference(file);
|
|
44
|
+
if (referenced !== null) {
|
|
45
|
+
if (referenced.startsWith('data:')) {
|
|
46
|
+
// Decoding it would mean rewriting the chunk to carry a map we then upload separately, for a
|
|
47
|
+
// configuration that has already chosen to ship its map to users.
|
|
48
|
+
warnings.push(`${file} has an inline source map; inline maps are not uploaded.`);
|
|
49
|
+
return { file, map: null, explicit: false };
|
|
50
|
+
}
|
|
51
|
+
// A remote or protocol-relative URL names something on a CDN, not on this disk. Joining it to
|
|
52
|
+
// the chunk's directory produced paths like `dist/https:/cdn.example.com/app.js.map`.
|
|
53
|
+
if (!/^(?:[a-z][a-z0-9+.-]*:)?\/\//i.test(referenced)) {
|
|
54
|
+
const target = clean(referenced);
|
|
55
|
+
const candidate = isAbsolute(target) ? target : resolve(dirname(file), target);
|
|
56
|
+
if (present.has(candidate))
|
|
57
|
+
return { file, map: candidate, explicit: true };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const sibling = `${file}.map`;
|
|
61
|
+
return { file, map: present.has(sibling) ? sibling : null, explicit: false };
|
|
62
|
+
}
|
|
63
|
+
/** Strip the query and fragment a cache-busting build appends, then percent-decode. */
|
|
64
|
+
function clean(url) {
|
|
65
|
+
const bare = (url.split('#')[0] ?? '').split('?')[0] ?? '';
|
|
66
|
+
try {
|
|
67
|
+
return decodeURIComponent(bare);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return bare;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** The last `sourceMappingURL` in a chunk, read from its tail rather than its whole body. */
|
|
74
|
+
async function reference(file) {
|
|
75
|
+
let tail;
|
|
76
|
+
try {
|
|
77
|
+
const handle = await open(file, 'r');
|
|
78
|
+
try {
|
|
79
|
+
const { size } = await handle.stat();
|
|
80
|
+
const length = Math.min(size, TAIL_BYTES);
|
|
81
|
+
const buffer = Buffer.alloc(length);
|
|
82
|
+
await handle.read(buffer, 0, length, Math.max(0, size - length));
|
|
83
|
+
tail = buffer.toString('utf8');
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await handle.close();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
let last = null;
|
|
93
|
+
for (const match of tail.matchAll(SOURCE_MAPPING_COMMENT))
|
|
94
|
+
last = match;
|
|
95
|
+
const url = last?.[1]?.trim();
|
|
96
|
+
return url === undefined || url === '' ? null : url;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Turn resolved pairs into artifacts, refusing any map that more than one chunk claims.
|
|
100
|
+
*
|
|
101
|
+
* Two chunks pointing at one map is not a map serving two chunks: it is a stale reference, a copied
|
|
102
|
+
* file, or a guess that happened to land on someone else's map. Writing a debug id into it would
|
|
103
|
+
* make the last writer win, so the id in the map would disagree with the id in every chunk but one
|
|
104
|
+
* and none of them would resolve. An explicit reference beats a guess, because the chunk that named
|
|
105
|
+
* the map is the one that meant it.
|
|
106
|
+
*/
|
|
107
|
+
function assign(resolved, root, warnings) {
|
|
108
|
+
const claimants = new Map();
|
|
109
|
+
for (const entry of resolved) {
|
|
110
|
+
if (entry.map === null)
|
|
111
|
+
continue;
|
|
112
|
+
const list = claimants.get(entry.map) ?? [];
|
|
113
|
+
list.push({ file: entry.file, explicit: entry.explicit });
|
|
114
|
+
claimants.set(entry.map, list);
|
|
115
|
+
}
|
|
116
|
+
const owner = new Map();
|
|
117
|
+
for (const [map, list] of claimants) {
|
|
118
|
+
if (list.length === 1) {
|
|
119
|
+
owner.set(map, list[0].file);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const explicit = list.filter((entry) => entry.explicit);
|
|
123
|
+
if (explicit.length === 1) {
|
|
124
|
+
owner.set(map, explicit[0].file);
|
|
125
|
+
warnings.push(`${map} is claimed by ${list.length} chunks; using the one that references it (${explicit[0].file}).`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
owner.set(map, null);
|
|
129
|
+
warnings.push(`${map} is claimed by ${list.length} chunks and none of them names it; leaving all of them without a map.`);
|
|
130
|
+
}
|
|
131
|
+
return resolved.map((entry) => ({
|
|
132
|
+
file: entry.file,
|
|
133
|
+
map: entry.map !== null && owner.get(entry.map) === entry.file ? entry.map : null,
|
|
134
|
+
// Always forward slashes: a URL is not a Windows path.
|
|
135
|
+
relative: relative(root, entry.file).split(sep).join('/'),
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Every file under a directory, each one exactly once.
|
|
140
|
+
*
|
|
141
|
+
* Symlinks are followed, and the real path of each directory is remembered, because a build output
|
|
142
|
+
* that links to a shared asset directory is ordinary and a link that points back up the tree is a
|
|
143
|
+
* loop. Visiting a file twice would stamp it twice and upload a stale copy of it.
|
|
144
|
+
*/
|
|
145
|
+
async function walk(directory, seen) {
|
|
146
|
+
const real = await realpath(directory).catch(() => directory);
|
|
147
|
+
if (seen.has(real))
|
|
148
|
+
return [];
|
|
149
|
+
seen.add(real);
|
|
150
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
151
|
+
const found = [];
|
|
152
|
+
for (const entry of entries) {
|
|
153
|
+
const path = join(directory, entry.name);
|
|
154
|
+
let isDirectory = entry.isDirectory();
|
|
155
|
+
let isFile = entry.isFile();
|
|
156
|
+
if (entry.isSymbolicLink()) {
|
|
157
|
+
// `readdir` reports the link, never its target, so a symlinked chunk is neither a file nor a
|
|
158
|
+
// directory here and was silently dropped from every build that used one.
|
|
159
|
+
const target = await stat(path).catch(() => null);
|
|
160
|
+
if (target === null)
|
|
161
|
+
continue;
|
|
162
|
+
isDirectory = target.isDirectory();
|
|
163
|
+
isFile = target.isFile();
|
|
164
|
+
}
|
|
165
|
+
if (isDirectory) {
|
|
166
|
+
if (SKIP_DIRECTORIES.has(entry.name))
|
|
167
|
+
continue;
|
|
168
|
+
found.push(...(await walk(path, seen)));
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (isFile)
|
|
172
|
+
found.push(path);
|
|
173
|
+
}
|
|
174
|
+
return found;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Every file under a directory, absolute, each one once.
|
|
178
|
+
*
|
|
179
|
+
* Exported for the plugins' cleanup pass, which has to find files `discover` deliberately ignores
|
|
180
|
+
* — a `.css.map` is not a chunk, but it is still the stylesheet's sources sitting in a public
|
|
181
|
+
* directory.
|
|
182
|
+
*/
|
|
183
|
+
export async function allFiles(root) {
|
|
184
|
+
return walk(root, new Set());
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* `--ext ts,mts` and friends, escaped.
|
|
188
|
+
*
|
|
189
|
+
* Escaped because the value comes from a command line, and an extension containing a regex
|
|
190
|
+
* metacharacter would otherwise quietly widen the match rather than fail — which is the kind of
|
|
191
|
+
* bug that shows up as "why did it upload that".
|
|
192
|
+
*/
|
|
193
|
+
function extensionMatcher(extensions = DEFAULT_EXTENSIONS) {
|
|
194
|
+
const cleaned = extensions
|
|
195
|
+
.map((extension) => extension.trim().replace(/^\./, ''))
|
|
196
|
+
.filter((extension) => extension !== '')
|
|
197
|
+
.map((extension) => extension.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
198
|
+
if (cleaned.length === 0)
|
|
199
|
+
return new RegExp(`\\.(?:${DEFAULT_EXTENSIONS.join('|')})$`);
|
|
200
|
+
return new RegExp(`\\.(?:${cleaned.join('|')})$`);
|
|
201
|
+
}
|
|
202
|
+
export async function sizeOf(path) {
|
|
203
|
+
return (await stat(path)).size;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* A map that cannot resolve anything: no mappings and no sources.
|
|
207
|
+
*
|
|
208
|
+
* Vite emits one per HTML entry in a multi-page build, for a facade chunk that is nothing but
|
|
209
|
+
* imports. Stamping those produces ids no frame will ever report and uploads bytes that answer no
|
|
210
|
+
* question. "Empty" deliberately means the MAP is empty and never that the code is short: a small
|
|
211
|
+
* single-page entry chunk is real code whose frames matter.
|
|
212
|
+
*/
|
|
213
|
+
export function isEmptyMap(mapJson) {
|
|
214
|
+
try {
|
|
215
|
+
const parsed = JSON.parse(mapJson);
|
|
216
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
217
|
+
return false;
|
|
218
|
+
const map = parsed;
|
|
219
|
+
if (Array.isArray(map['sections']))
|
|
220
|
+
return map['sections'].length === 0;
|
|
221
|
+
const mappings = map['mappings'];
|
|
222
|
+
const sources = map['sources'];
|
|
223
|
+
return ((typeof mappings !== 'string' || mappings === '') && (!Array.isArray(sources) || sources.length === 0));
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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","sourcesContent":["import { open, readdir, realpath, stat } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';\n\nimport { matches } from './glob.js';\n\n/**\n * Finds built JavaScript and the map that belongs to it.\n *\n * Hand-rolled rather than a glob dependency: the package ships with zero runtime dependencies, and\n * \"walk a directory\" is not worth one.\n */\n\nexport interface Artifact {\n /** Absolute path to the .js file. */\n readonly file: string;\n /** Absolute path to its .map, when one could be resolved. */\n readonly map: string | null;\n /** Path relative to the upload root, which is what the URL is derived from. */\n readonly relative: string;\n}\n\nexport interface Discovery {\n readonly artifacts: Artifact[];\n /** Everything that was skipped and why. Never silent: a missing map is a minified release. */\n readonly warnings: string[];\n}\n\n// Entry names, matched against a single directory name. `.next/cache` used to be in here and\n// could never match anything, because a directory entry is never a path.\nconst SKIP_DIRECTORIES = new Set(['node_modules', '.git', 'coverage', 'cache']);\n\n/** What counts as a chunk, absent `--ext`. */\nexport const DEFAULT_EXTENSIONS = ['js', 'cjs', 'mjs'];\n\nexport interface DiscoverOptions {\n /**\n * Globs, matched against the path relative to the root. An ignored chunk is skipped whole — it\n * is neither stamped nor uploaded, so an ignore rule can never orphan an id by removing a map\n * whose chunk still names it.\n */\n readonly ignore?: readonly string[];\n /** Extensions to treat as chunks, without the dot. Defaults to {@link DEFAULT_EXTENSIONS}. */\n readonly extensions?: readonly string[];\n}\n\n/**\n * `//# sourceMappingURL=`, and the legacy `//@` spelling some older toolchains still emit.\n *\n * Matched line-anchored so the string appearing inside a bundled literal — a tool that writes these\n * comments, bundled into an application — cannot be mistaken for a real reference.\n */\nconst SOURCE_MAPPING_COMMENT = /^\\/\\/[#@] sourceMappingURL=(.*)$/gm;\n\n/** How much of a chunk's tail is searched for the reference. It is emitted as the final line. */\nconst TAIL_BYTES = 65_536;\n\nexport async function discover(root: string, options: DiscoverOptions = {}): Promise<Discovery> {\n const warnings: string[] = [];\n const files = await walk(root, new Set());\n const script = extensionMatcher(options.extensions);\n const ignore = options.ignore ?? [];\n\n const scripts = files\n .filter((file) => script.test(file))\n .filter((file) => !matches(relative(root, file).split(sep).join('/'), ignore))\n .sort((a, b) => a.localeCompare(b));\n const present = new Set(files);\n\n const resolved: Array<{ file: string; map: string | null; explicit: boolean }> = [];\n for (const file of scripts) {\n resolved.push(await locate(file, present, warnings));\n }\n\n return { artifacts: assign(resolved, root, warnings), warnings };\n}\n\n/**\n * The map for one chunk: what it says, then what sits beside it.\n *\n * Asking the chunk first is not a refinement, it is the difference between working and not. A\n * build configured with `sourcemapFileNames`, webpack's `sourceMapFilename`, or any output that\n * puts maps in their own directory has no `<file>.map` sibling at all, so guessing alone found\n * nothing and uploaded nothing, without a word.\n */\nasync function locate(\n file: string,\n present: ReadonlySet<string>,\n warnings: string[],\n): Promise<{ file: string; map: string | null; explicit: boolean }> {\n const referenced = await reference(file);\n\n if (referenced !== null) {\n if (referenced.startsWith('data:')) {\n // Decoding it would mean rewriting the chunk to carry a map we then upload separately, for a\n // configuration that has already chosen to ship its map to users.\n warnings.push(`${file} has an inline source map; inline maps are not uploaded.`);\n\n return { file, map: null, explicit: false };\n }\n\n // A remote or protocol-relative URL names something on a CDN, not on this disk. Joining it to\n // the chunk's directory produced paths like `dist/https:/cdn.example.com/app.js.map`.\n if (!/^(?:[a-z][a-z0-9+.-]*:)?\\/\\//i.test(referenced)) {\n const target = clean(referenced);\n const candidate = isAbsolute(target) ? target : resolve(dirname(file), target);\n\n if (present.has(candidate)) return { file, map: candidate, explicit: true };\n }\n }\n\n const sibling = `${file}.map`;\n\n return { file, map: present.has(sibling) ? sibling : null, explicit: false };\n}\n\n/** Strip the query and fragment a cache-busting build appends, then percent-decode. */\nfunction clean(url: string): string {\n const bare = (url.split('#')[0] ?? '').split('?')[0] ?? '';\n\n try {\n return decodeURIComponent(bare);\n } catch {\n return bare;\n }\n}\n\n/** The last `sourceMappingURL` in a chunk, read from its tail rather than its whole body. */\nasync function reference(file: string): Promise<string | null> {\n let tail: string;\n try {\n const handle = await open(file, 'r');\n try {\n const { size } = await handle.stat();\n const length = Math.min(size, TAIL_BYTES);\n const buffer = Buffer.alloc(length);\n await handle.read(buffer, 0, length, Math.max(0, size - length));\n tail = buffer.toString('utf8');\n } finally {\n await handle.close();\n }\n } catch {\n return null;\n }\n\n let last: RegExpExecArray | null = null;\n for (const match of tail.matchAll(SOURCE_MAPPING_COMMENT)) last = match;\n\n const url = last?.[1]?.trim();\n\n return url === undefined || url === '' ? null : url;\n}\n\n/**\n * Turn resolved pairs into artifacts, refusing any map that more than one chunk claims.\n *\n * Two chunks pointing at one map is not a map serving two chunks: it is a stale reference, a copied\n * file, or a guess that happened to land on someone else's map. Writing a debug id into it would\n * make the last writer win, so the id in the map would disagree with the id in every chunk but one\n * and none of them would resolve. An explicit reference beats a guess, because the chunk that named\n * the map is the one that meant it.\n */\nfunction assign(\n resolved: ReadonlyArray<{ file: string; map: string | null; explicit: boolean }>,\n root: string,\n warnings: string[],\n): Artifact[] {\n const claimants = new Map<string, Array<{ file: string; explicit: boolean }>>();\n for (const entry of resolved) {\n if (entry.map === null) continue;\n const list = claimants.get(entry.map) ?? [];\n list.push({ file: entry.file, explicit: entry.explicit });\n claimants.set(entry.map, list);\n }\n\n const owner = new Map<string, string | null>();\n for (const [map, list] of claimants) {\n if (list.length === 1) {\n owner.set(map, list[0]!.file);\n continue;\n }\n\n const explicit = list.filter((entry) => entry.explicit);\n if (explicit.length === 1) {\n owner.set(map, explicit[0]!.file);\n warnings.push(\n `${map} is claimed by ${list.length} chunks; using the one that references it (${explicit[0]!.file}).`,\n );\n continue;\n }\n\n owner.set(map, null);\n warnings.push(\n `${map} is claimed by ${list.length} chunks and none of them names it; leaving all of them without a map.`,\n );\n }\n\n return resolved.map((entry) => ({\n file: entry.file,\n map: entry.map !== null && owner.get(entry.map) === entry.file ? entry.map : null,\n // Always forward slashes: a URL is not a Windows path.\n relative: relative(root, entry.file).split(sep).join('/'),\n }));\n}\n\n/**\n * Every file under a directory, each one exactly once.\n *\n * Symlinks are followed, and the real path of each directory is remembered, because a build output\n * that links to a shared asset directory is ordinary and a link that points back up the tree is a\n * loop. Visiting a file twice would stamp it twice and upload a stale copy of it.\n */\nasync function walk(directory: string, seen: Set<string>): Promise<string[]> {\n const real = await realpath(directory).catch(() => directory);\n if (seen.has(real)) return [];\n seen.add(real);\n\n const entries = await readdir(directory, { withFileTypes: true });\n const found: string[] = [];\n\n for (const entry of entries) {\n const path = join(directory, entry.name);\n let isDirectory = entry.isDirectory();\n let isFile = entry.isFile();\n\n if (entry.isSymbolicLink()) {\n // `readdir` reports the link, never its target, so a symlinked chunk is neither a file nor a\n // directory here and was silently dropped from every build that used one.\n const target = await stat(path).catch(() => null);\n if (target === null) continue;\n isDirectory = target.isDirectory();\n isFile = target.isFile();\n }\n\n if (isDirectory) {\n if (SKIP_DIRECTORIES.has(entry.name)) continue;\n found.push(...(await walk(path, seen)));\n continue;\n }\n\n if (isFile) found.push(path);\n }\n\n return found;\n}\n\n/**\n * Every file under a directory, absolute, each one once.\n *\n * Exported for the plugins' cleanup pass, which has to find files `discover` deliberately ignores\n * — a `.css.map` is not a chunk, but it is still the stylesheet's sources sitting in a public\n * directory.\n */\nexport async function allFiles(root: string): Promise<string[]> {\n return walk(root, new Set());\n}\n\n/**\n * `--ext ts,mts` and friends, escaped.\n *\n * Escaped because the value comes from a command line, and an extension containing a regex\n * metacharacter would otherwise quietly widen the match rather than fail — which is the kind of\n * bug that shows up as \"why did it upload that\".\n */\nfunction extensionMatcher(extensions: readonly string[] = DEFAULT_EXTENSIONS): RegExp {\n const cleaned = extensions\n .map((extension) => extension.trim().replace(/^\\./, ''))\n .filter((extension) => extension !== '')\n .map((extension) => extension.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n\n if (cleaned.length === 0) return new RegExp(`\\\\.(?:${DEFAULT_EXTENSIONS.join('|')})$`);\n\n return new RegExp(`\\\\.(?:${cleaned.join('|')})$`);\n}\n\nexport async function sizeOf(path: string): Promise<number> {\n return (await stat(path)).size;\n}\n\n/**\n * A map that cannot resolve anything: no mappings and no sources.\n *\n * Vite emits one per HTML entry in a multi-page build, for a facade chunk that is nothing but\n * imports. Stamping those produces ids no frame will ever report and uploads bytes that answer no\n * question. \"Empty\" deliberately means the MAP is empty and never that the code is short: a small\n * single-page entry chunk is real code whose frames matter.\n */\nexport function isEmptyMap(mapJson: string): boolean {\n try {\n const parsed: unknown = JSON.parse(mapJson);\n if (typeof parsed !== 'object' || parsed === null) return false;\n\n const map = parsed as Record<string, unknown>;\n if (Array.isArray(map['sections'])) return map['sections'].length === 0;\n\n const mappings = map['mappings'];\n const sources = map['sources'];\n\n return (\n (typeof mappings !== 'string' || mappings === '') && (!Array.isArray(sources) || sources.length === 0)\n );\n } catch {\n return false;\n }\n}\n"]}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading `VINKTAR_*` out of a `.env` file.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately small. This is not a dotenv replacement: it exists so a developer running the CLI
|
|
5
|
+
* by hand gets the same values their Vite build already reads, and it stops there.
|
|
6
|
+
*
|
|
7
|
+
* **No `$VAR` interpolation.** A `.env` that can reference the process environment is a `.env`
|
|
8
|
+
* that can exfiltrate it — `VINKTAR_HOST=https://$AWS_SECRET_ACCESS_KEY.example.com` is a
|
|
9
|
+
* one-line data leak in a file people paste from a README. Values are literal.
|
|
10
|
+
*/
|
|
11
|
+
export interface DotEnv {
|
|
12
|
+
readonly values: Record<string, string>;
|
|
13
|
+
readonly warnings: string[];
|
|
14
|
+
/** Whether the file existed at all. A missing file is not an error, and not silent either. */
|
|
15
|
+
readonly found: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @param path the file to read. The flag that supplies it is `--dotenv-file`, never `--env-file`:
|
|
19
|
+
* Node has owned `--env-file` since 20.6 and swallows it before the CLI's own parser ever sees
|
|
20
|
+
* the argument, so a user passing it would silently configure Node instead.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadDotEnv(path: string): Promise<DotEnv>;
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
/**
|
|
3
|
+
* @param path the file to read. The flag that supplies it is `--dotenv-file`, never `--env-file`:
|
|
4
|
+
* Node has owned `--env-file` since 20.6 and swallows it before the CLI's own parser ever sees
|
|
5
|
+
* the argument, so a user passing it would silently configure Node instead.
|
|
6
|
+
*/
|
|
7
|
+
export async function loadDotEnv(path) {
|
|
8
|
+
let raw;
|
|
9
|
+
try {
|
|
10
|
+
raw = await readFile(path, 'utf8');
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return { values: {}, warnings: [], found: false };
|
|
14
|
+
}
|
|
15
|
+
const values = {};
|
|
16
|
+
const warnings = [];
|
|
17
|
+
raw.split(/\r?\n/).forEach((line, index) => {
|
|
18
|
+
const trimmed = line.trim();
|
|
19
|
+
if (trimmed === '' || trimmed.startsWith('#'))
|
|
20
|
+
return;
|
|
21
|
+
const match = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(trimmed);
|
|
22
|
+
if (match === null) {
|
|
23
|
+
// Named with the line number, because "malformed .env" and nothing else is a file people
|
|
24
|
+
// then read from the top, three times.
|
|
25
|
+
warnings.push(`${path}:${index + 1} is not NAME=value and was ignored.`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const name = match[1];
|
|
29
|
+
if (!name.startsWith('VINKTAR_'))
|
|
30
|
+
return;
|
|
31
|
+
values[name] = unquote(match[2] ?? '');
|
|
32
|
+
});
|
|
33
|
+
return { values, warnings, found: true };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Strip one layer of matching quotes, and the trailing comment on an unquoted value.
|
|
37
|
+
*
|
|
38
|
+
* `KEY=abc # staging` means the key is `abc`, which is the behaviour every dotenv implementation
|
|
39
|
+
* has and the one people write against. Inside quotes a `#` is part of the value.
|
|
40
|
+
*/
|
|
41
|
+
function unquote(value) {
|
|
42
|
+
const trimmed = value.trim();
|
|
43
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length > 1) ||
|
|
44
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'") && trimmed.length > 1)) {
|
|
45
|
+
return trimmed.slice(1, -1);
|
|
46
|
+
}
|
|
47
|
+
const comment = trimmed.indexOf(' #');
|
|
48
|
+
return (comment === -1 ? trimmed : trimmed.slice(0, comment)).trim();
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAoB5C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO;QAEtD,MAAM,KAAK,GAAG,qDAAqD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClF,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,yFAAyF;YACzF,uCAAuC;YACvC,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC,qCAAqC,CAAC,CAAC;YAEzE,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,OAAO;QAEzC,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,SAAS,OAAO,CAAC,KAAa;IAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,IACE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QACxE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EACxE,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC,OAAO,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACvE,CAAC","sourcesContent":["import { readFile } from 'node:fs/promises';\n\n/**\n * Reading `VINKTAR_*` out of a `.env` file.\n *\n * Deliberately small. This is not a dotenv replacement: it exists so a developer running the CLI\n * by hand gets the same values their Vite build already reads, and it stops there.\n *\n * **No `$VAR` interpolation.** A `.env` that can reference the process environment is a `.env`\n * that can exfiltrate it — `VINKTAR_HOST=https://$AWS_SECRET_ACCESS_KEY.example.com` is a\n * one-line data leak in a file people paste from a README. Values are literal.\n */\n\nexport interface DotEnv {\n readonly values: Record<string, string>;\n readonly warnings: string[];\n /** Whether the file existed at all. A missing file is not an error, and not silent either. */\n readonly found: boolean;\n}\n\n/**\n * @param path the file to read. The flag that supplies it is `--dotenv-file`, never `--env-file`:\n * Node has owned `--env-file` since 20.6 and swallows it before the CLI's own parser ever sees\n * the argument, so a user passing it would silently configure Node instead.\n */\nexport async function loadDotEnv(path: string): Promise<DotEnv> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf8');\n } catch {\n return { values: {}, warnings: [], found: false };\n }\n\n const values: Record<string, string> = {};\n const warnings: string[] = [];\n\n raw.split(/\\r?\\n/).forEach((line, index) => {\n const trimmed = line.trim();\n if (trimmed === '' || trimmed.startsWith('#')) return;\n\n const match = /^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=\\s*(.*)$/.exec(trimmed);\n if (match === null) {\n // Named with the line number, because \"malformed .env\" and nothing else is a file people\n // then read from the top, three times.\n warnings.push(`${path}:${index + 1} is not NAME=value and was ignored.`);\n\n return;\n }\n\n const name = match[1]!;\n if (!name.startsWith('VINKTAR_')) return;\n\n values[name] = unquote(match[2] ?? '');\n });\n\n return { values, warnings, found: true };\n}\n\n/**\n * Strip one layer of matching quotes, and the trailing comment on an unquoted value.\n *\n * `KEY=abc # staging` means the key is `abc`, which is the behaviour every dotenv implementation\n * has and the one people write against. Inside quotes a `#` is part of the value.\n */\nfunction unquote(value: string): string {\n const trimmed = value.trim();\n\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"') && trimmed.length > 1) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\") && trimmed.length > 1)\n ) {\n return trimmed.slice(1, -1);\n }\n\n const comment = trimmed.indexOf(' #');\n\n return (comment === -1 ? trimmed : trimmed.slice(0, comment)).trim();\n}\n"]}
|
package/dist/glob.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A glob matcher, hand-rolled.
|
|
3
|
+
*
|
|
4
|
+
* `--ignore` needs one, and every candidate dependency costs more than it is worth here: this
|
|
5
|
+
* package ships zero runtime dependencies, and the one library that would do it without pulling a
|
|
6
|
+
* tree behind it (`picomatch`) is still a download on every `npx` invocation, on every CI run.
|
|
7
|
+
* `node:fs`'s own glob support arrived in Node 22, which would move the supported floor from 18
|
|
8
|
+
* for a feature nobody upgrades Node for.
|
|
9
|
+
*
|
|
10
|
+
* Supported, which is the intersection of what a build output needs and what people actually
|
|
11
|
+
* write: `*` (anything but `/`), `**` (anything, including `/`), `?` (one character but `/`),
|
|
12
|
+
* `[abc]` and `[!abc]` classes, and `{a,b}` alternation. Brace nesting is one level, because a
|
|
13
|
+
* pattern that needs two is a pattern nobody will read twice.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Compile a glob to a RegExp anchored at both ends.
|
|
17
|
+
*
|
|
18
|
+
* Written as a single left-to-right scan rather than a chain of `String.replace` calls, which is
|
|
19
|
+
* the usual shape and is wrong for the same reason every time: an earlier replacement's output
|
|
20
|
+
* becomes a later one's input, so `**` is rewritten by the `*` rule and a `\*` escape is honoured
|
|
21
|
+
* by whichever rule happens to run last.
|
|
22
|
+
*/
|
|
23
|
+
export declare function compile(pattern: string): RegExp;
|
|
24
|
+
/**
|
|
25
|
+
* Whether a path matches any of the patterns.
|
|
26
|
+
*
|
|
27
|
+
* A bare pattern with no `/` is matched against the basename as well as the whole path, because
|
|
28
|
+
* `--ignore '*.min.js'` means "any minified file", not "a minified file at the root" — and being
|
|
29
|
+
* told the flag did nothing is not the same as being told why.
|
|
30
|
+
*
|
|
31
|
+
* Paths are compared with forward slashes, always: the patterns people write come from a shell or
|
|
32
|
+
* a config file and never contain backslashes, whatever platform they run on.
|
|
33
|
+
*/
|
|
34
|
+
export declare function matches(path: string, patterns: readonly string[]): boolean;
|
package/dist/glob.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A glob matcher, hand-rolled.
|
|
3
|
+
*
|
|
4
|
+
* `--ignore` needs one, and every candidate dependency costs more than it is worth here: this
|
|
5
|
+
* package ships zero runtime dependencies, and the one library that would do it without pulling a
|
|
6
|
+
* tree behind it (`picomatch`) is still a download on every `npx` invocation, on every CI run.
|
|
7
|
+
* `node:fs`'s own glob support arrived in Node 22, which would move the supported floor from 18
|
|
8
|
+
* for a feature nobody upgrades Node for.
|
|
9
|
+
*
|
|
10
|
+
* Supported, which is the intersection of what a build output needs and what people actually
|
|
11
|
+
* write: `*` (anything but `/`), `**` (anything, including `/`), `?` (one character but `/`),
|
|
12
|
+
* `[abc]` and `[!abc]` classes, and `{a,b}` alternation. Brace nesting is one level, because a
|
|
13
|
+
* pattern that needs two is a pattern nobody will read twice.
|
|
14
|
+
*/
|
|
15
|
+
const SPECIAL = /[.+^${}()|[\]\\]/g;
|
|
16
|
+
/**
|
|
17
|
+
* Compile a glob to a RegExp anchored at both ends.
|
|
18
|
+
*
|
|
19
|
+
* Written as a single left-to-right scan rather than a chain of `String.replace` calls, which is
|
|
20
|
+
* the usual shape and is wrong for the same reason every time: an earlier replacement's output
|
|
21
|
+
* becomes a later one's input, so `**` is rewritten by the `*` rule and a `\*` escape is honoured
|
|
22
|
+
* by whichever rule happens to run last.
|
|
23
|
+
*/
|
|
24
|
+
export function compile(pattern) {
|
|
25
|
+
let source = '';
|
|
26
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
27
|
+
const char = pattern[i];
|
|
28
|
+
if (char === '*') {
|
|
29
|
+
const double = pattern[i + 1] === '*';
|
|
30
|
+
if (double) {
|
|
31
|
+
i += 1;
|
|
32
|
+
// `a/**/b` must also match `a/b`: the separator after `**` is part of what it consumes.
|
|
33
|
+
if (pattern[i + 1] === '/') {
|
|
34
|
+
i += 1;
|
|
35
|
+
source += '(?:.*/)?';
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
source += '.*';
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
source += '[^/]*';
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (char === '?') {
|
|
45
|
+
source += '[^/]';
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === '[') {
|
|
49
|
+
const end = pattern.indexOf(']', i + 1);
|
|
50
|
+
if (end === -1) {
|
|
51
|
+
source += '\\[';
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const body = pattern.slice(i + 1, end);
|
|
55
|
+
source += `[${body.startsWith('!') ? `^${body.slice(1)}` : body}]`;
|
|
56
|
+
i = end;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (char === '{') {
|
|
60
|
+
const end = pattern.indexOf('}', i + 1);
|
|
61
|
+
if (end === -1) {
|
|
62
|
+
source += '\\{';
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const options = pattern.slice(i + 1, end).split(',');
|
|
66
|
+
source += `(?:${options.map((option) => compile(option).source.slice(1, -1)).join('|')})`;
|
|
67
|
+
i = end;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
source += char.replace(SPECIAL, '\\$&');
|
|
71
|
+
}
|
|
72
|
+
return new RegExp(`^${source}$`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Whether a path matches any of the patterns.
|
|
76
|
+
*
|
|
77
|
+
* A bare pattern with no `/` is matched against the basename as well as the whole path, because
|
|
78
|
+
* `--ignore '*.min.js'` means "any minified file", not "a minified file at the root" — and being
|
|
79
|
+
* told the flag did nothing is not the same as being told why.
|
|
80
|
+
*
|
|
81
|
+
* Paths are compared with forward slashes, always: the patterns people write come from a shell or
|
|
82
|
+
* a config file and never contain backslashes, whatever platform they run on.
|
|
83
|
+
*/
|
|
84
|
+
export function matches(path, patterns) {
|
|
85
|
+
if (patterns.length === 0)
|
|
86
|
+
return false;
|
|
87
|
+
const target = path.split('\\').join('/');
|
|
88
|
+
const base = target.slice(target.lastIndexOf('/') + 1);
|
|
89
|
+
return patterns.some((pattern) => {
|
|
90
|
+
const expression = compiled(pattern);
|
|
91
|
+
if (expression.test(target))
|
|
92
|
+
return true;
|
|
93
|
+
if (!pattern.includes('/') && expression.test(base))
|
|
94
|
+
return true;
|
|
95
|
+
// A directory pattern covers everything under it: `--ignore vendor` should not need
|
|
96
|
+
// `vendor/**` as well, which is the first thing anyone gets wrong.
|
|
97
|
+
return compiled(pattern.endsWith('/') ? `${pattern}**` : `${pattern}/**`).test(target);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const cache = new Map();
|
|
101
|
+
function compiled(pattern) {
|
|
102
|
+
const found = cache.get(pattern);
|
|
103
|
+
if (found !== undefined)
|
|
104
|
+
return found;
|
|
105
|
+
const expression = compile(pattern);
|
|
106
|
+
cache.set(pattern, expression);
|
|
107
|
+
return expression;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=glob.js.map
|
package/dist/glob.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../src/glob.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A glob matcher, hand-rolled.\n *\n * `--ignore` needs one, and every candidate dependency costs more than it is worth here: this\n * package ships zero runtime dependencies, and the one library that would do it without pulling a\n * tree behind it (`picomatch`) is still a download on every `npx` invocation, on every CI run.\n * `node:fs`'s own glob support arrived in Node 22, which would move the supported floor from 18\n * for a feature nobody upgrades Node for.\n *\n * Supported, which is the intersection of what a build output needs and what people actually\n * write: `*` (anything but `/`), `**` (anything, including `/`), `?` (one character but `/`),\n * `[abc]` and `[!abc]` classes, and `{a,b}` alternation. Brace nesting is one level, because a\n * pattern that needs two is a pattern nobody will read twice.\n */\n\nconst SPECIAL = /[.+^${}()|[\\]\\\\]/g;\n\n/**\n * Compile a glob to a RegExp anchored at both ends.\n *\n * Written as a single left-to-right scan rather than a chain of `String.replace` calls, which is\n * the usual shape and is wrong for the same reason every time: an earlier replacement's output\n * becomes a later one's input, so `**` is rewritten by the `*` rule and a `\\*` escape is honoured\n * by whichever rule happens to run last.\n */\nexport function compile(pattern: string): RegExp {\n let source = '';\n\n for (let i = 0; i < pattern.length; i += 1) {\n const char = pattern[i]!;\n\n if (char === '*') {\n const double = pattern[i + 1] === '*';\n if (double) {\n i += 1;\n // `a/**/b` must also match `a/b`: the separator after `**` is part of what it consumes.\n if (pattern[i + 1] === '/') {\n i += 1;\n source += '(?:.*/)?';\n continue;\n }\n source += '.*';\n continue;\n }\n source += '[^/]*';\n continue;\n }\n\n if (char === '?') {\n source += '[^/]';\n continue;\n }\n\n if (char === '[') {\n const end = pattern.indexOf(']', i + 1);\n if (end === -1) {\n source += '\\\\[';\n continue;\n }\n const body = pattern.slice(i + 1, end);\n source += `[${body.startsWith('!') ? `^${body.slice(1)}` : body}]`;\n i = end;\n continue;\n }\n\n if (char === '{') {\n const end = pattern.indexOf('}', i + 1);\n if (end === -1) {\n source += '\\\\{';\n continue;\n }\n const options = pattern.slice(i + 1, end).split(',');\n source += `(?:${options.map((option) => compile(option).source.slice(1, -1)).join('|')})`;\n i = end;\n continue;\n }\n\n source += char.replace(SPECIAL, '\\\\$&');\n }\n\n return new RegExp(`^${source}$`);\n}\n\n/**\n * Whether a path matches any of the patterns.\n *\n * A bare pattern with no `/` is matched against the basename as well as the whole path, because\n * `--ignore '*.min.js'` means \"any minified file\", not \"a minified file at the root\" — and being\n * told the flag did nothing is not the same as being told why.\n *\n * Paths are compared with forward slashes, always: the patterns people write come from a shell or\n * a config file and never contain backslashes, whatever platform they run on.\n */\nexport function matches(path: string, patterns: readonly string[]): boolean {\n if (patterns.length === 0) return false;\n\n const target = path.split('\\\\').join('/');\n const base = target.slice(target.lastIndexOf('/') + 1);\n\n return patterns.some((pattern) => {\n const expression = compiled(pattern);\n\n if (expression.test(target)) return true;\n if (!pattern.includes('/') && expression.test(base)) return true;\n\n // A directory pattern covers everything under it: `--ignore vendor` should not need\n // `vendor/**` as well, which is the first thing anyone gets wrong.\n return compiled(pattern.endsWith('/') ? `${pattern}**` : `${pattern}/**`).test(target);\n });\n}\n\nconst cache = new Map<string, RegExp>();\n\nfunction compiled(pattern: string): RegExp {\n const found = cache.get(pattern);\n if (found !== undefined) return found;\n\n const expression = compile(pattern);\n cache.set(pattern, expression);\n\n return expression;\n}\n"]}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place a request leaves this package.
|
|
3
|
+
*
|
|
4
|
+
* `fetch` does the work, except when it cannot: Node's `fetch` ignores `HTTPS_PROXY` entirely, and
|
|
5
|
+
* in a corporate network that is not a slow upload but an `ECONNREFUSED` from a CLI that "works on
|
|
6
|
+
* my machine" while every other tool in the pipeline succeeds. When a proxy is configured the
|
|
7
|
+
* request goes out over `node:http`/`node:https` through a CONNECT tunnel instead; when one is
|
|
8
|
+
* not — the overwhelmingly common case — nothing about the path changes.
|
|
9
|
+
*/
|
|
10
|
+
export interface RequestOptions {
|
|
11
|
+
readonly method: 'GET' | 'POST';
|
|
12
|
+
readonly url: string;
|
|
13
|
+
readonly key?: string;
|
|
14
|
+
readonly body?: Buffer | string;
|
|
15
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
16
|
+
/** Whole-request deadline. Callers scale it for large bodies. */
|
|
17
|
+
readonly timeoutMs: number;
|
|
18
|
+
/** Appended to the User-Agent, e.g. `vite-plugin/0.1.0`. */
|
|
19
|
+
readonly plugin?: string;
|
|
20
|
+
readonly env?: Record<string, string | undefined>;
|
|
21
|
+
}
|
|
22
|
+
export interface Reply {
|
|
23
|
+
readonly status: number;
|
|
24
|
+
readonly text: string;
|
|
25
|
+
header(name: string): string | null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* `vinktar-cli/<version> (node/<version>)`, plus the plugin when a bundler is driving.
|
|
29
|
+
*
|
|
30
|
+
* The server logs it, and "which of these is the Vite plugin and which is a hand-run CI script" is
|
|
31
|
+
* the first question anyone asks of an ingest log.
|
|
32
|
+
*/
|
|
33
|
+
export declare function userAgent(plugin?: string): string;
|
|
34
|
+
export declare function send(options: RequestOptions): Promise<Reply>;
|
|
35
|
+
/**
|
|
36
|
+
* The proxy that should carry a request to `url`, honouring `NO_PROXY`.
|
|
37
|
+
*
|
|
38
|
+
* Lower case wins over upper case, which is what curl does and therefore what people expect:
|
|
39
|
+
* `http_proxy` is the historical spelling and the one a shell profile sets.
|
|
40
|
+
*/
|
|
41
|
+
export declare function proxyFor(url: string, env?: Record<string, string | undefined>): URL | null;
|
|
42
|
+
/** Exposed so the retry policy can be asserted rather than inferred from a stack trace. */
|
|
43
|
+
export declare const RETRIABLE_STATUS: Set<number>;
|
|
44
|
+
/**
|
|
45
|
+
* Whether a failed request is worth repeating.
|
|
46
|
+
*
|
|
47
|
+
* `ENOTFOUND` is on the list only for the default host: a self-hosted URL that does not resolve is
|
|
48
|
+
* a typo, and retrying a typo three times with backoff turns a one-second error into a ten-second
|
|
49
|
+
* one and teaches nobody anything.
|
|
50
|
+
*/
|
|
51
|
+
export declare function retriable(error: unknown, isDefaultHost: boolean): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* How long to wait before trying again.
|
|
54
|
+
*
|
|
55
|
+
* `Retry-After` is honoured when the server sends one — it is the only party that knows when its
|
|
56
|
+
* rate limit resets — and capped, because a proxy answering `Retry-After: 3600` must not hang a
|
|
57
|
+
* deploy for an hour. Otherwise exponential with jitter, so two builds that fail together do not
|
|
58
|
+
* retry together.
|
|
59
|
+
*/
|
|
60
|
+
export declare function backoffMs(attempt: number, retryAfter?: string | null): number;
|
|
61
|
+
/**
|
|
62
|
+
* The deadline for a request carrying `bytes`.
|
|
63
|
+
*
|
|
64
|
+
* One flat timeout punishes a large upload for being large: 30 s is generous for a handshake and
|
|
65
|
+
* mean for 40 MB over a hotel connection. This is the connect-and-settle allowance plus an
|
|
66
|
+
* assumption of a slow-but-real 1 Mbit/s.
|
|
67
|
+
*/
|
|
68
|
+
export declare function timeoutFor(bytes: number, base: number): number;
|