@prosopo/config 3.4.2 → 3.4.4
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/.turbo/turbo-build$colon$cjs.log +5 -8
- package/.turbo/turbo-build$colon$tsc.log +4 -7
- package/.turbo/turbo-build.log +6 -12
- package/CHANGELOG.md +22 -0
- package/LICENSE +201 -0
- package/dist/cjs/dependencies.cjs +86 -46
- package/dist/cjs/vite/vite.frontend.config.cjs +7 -0
- package/dist/cjs/webpack/webpack.config.cjs +7 -8
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +85 -44
- package/dist/dependencies.js.map +1 -1
- package/dist/getDependencies.test.js +151 -125
- package/dist/getDependencies.test.js.map +1 -1
- package/dist/vite/vite.frontend.config.d.ts.map +1 -1
- package/dist/vite/vite.frontend.config.js +8 -1
- package/dist/vite/vite.frontend.config.js.map +1 -1
- package/dist/webpack/webpack.config.d.ts +2 -2
- package/dist/webpack/webpack.config.d.ts.map +1 -1
- package/dist/webpack/webpack.config.js +7 -8
- package/dist/webpack/webpack.config.js.map +1 -1
- package/package.json +103 -103
- package/src/dependencies.test.ts +0 -249
- package/src/dependencies.ts +0 -259
- package/src/getDependencies.test.ts +0 -385
- package/src/index.ts +0 -16
- package/src/vite/CopyAssetsPlugin.ts +0 -49
- package/src/vite/NodejsPolarsDirnamePlugin.ts +0 -50
- package/src/vite/NodejsPolarsNativeFilePlugin.ts +0 -105
- package/src/vite/TsNoCheckPlugin.ts +0 -31
- package/src/vite/bundleConfigs.test.ts +0 -461
- package/src/vite/configs.test.ts +0 -223
- package/src/vite/index.ts +0 -30
- package/src/vite/modifyExportsFiles.test.ts +0 -56
- package/src/vite/plugins.test.ts +0 -365
- package/src/vite/testFileGlobs.test.ts +0 -162
- package/src/vite/testFileGlobs.ts +0 -57
- package/src/vite/translations.test.ts +0 -164
- package/src/vite/types.ts +0 -13
- package/src/vite/vite-plugin-close-and-copy.ts +0 -76
- package/src/vite/vite-plugin-copy.ts +0 -67
- package/src/vite/vite-plugin-externalize-obfuscator-deadcode.ts +0 -43
- package/src/vite/vite-plugin-fix-absolute-imports.ts +0 -40
- package/src/vite/vite-plugin-modify-exports-files.ts +0 -64
- package/src/vite/vite-plugin-remove-unused-translations.ts +0 -128
- package/src/vite/vite-plugin-sourcemap-exclude.ts +0 -36
- package/src/vite/vite.backend.config.ts +0 -172
- package/src/vite/vite.commonjs.config.ts +0 -98
- package/src/vite/vite.esm.config.ts +0 -99
- package/src/vite/vite.frontend.config.ts +0 -340
- package/src/vite/vite.test.config.ts +0 -115
- package/src/vite/vite.threads.test.config.ts +0 -100
- package/src/webpack/index.ts +0 -14
- package/src/webpack/webpack.config.ts +0 -159
- package/tsconfig.cjs.json +0 -9
- package/tsconfig.json +0 -17
- package/tsconfig.tsbuildinfo +0 -1
- package/tsconfig.types.json +0 -9
package/src/dependencies.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import child_process from "node:child_process";
|
|
16
|
-
import fs from "node:fs";
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
import util from "node:util";
|
|
19
|
-
import type { ProjectReference } from "typescript";
|
|
20
|
-
|
|
21
|
-
const exec = util.promisify(child_process.exec);
|
|
22
|
-
const peerDepsRegex = /UNMET\sOPTIONAL\sDEPENDENCY\s+(@*[\w\-/.]+)@/;
|
|
23
|
-
const depsRegex = /\s+(@*[\w\-/.]+)@/;
|
|
24
|
-
|
|
25
|
-
const getTsconfigDir = (tsConfigPath: string): string =>
|
|
26
|
-
".json" === path.extname(tsConfigPath)
|
|
27
|
-
? path.dirname(tsConfigPath)
|
|
28
|
-
: tsConfigPath;
|
|
29
|
-
|
|
30
|
-
async function getPackageDir(packageName: string): Promise<string> {
|
|
31
|
-
let pkg = packageName;
|
|
32
|
-
if (packageName && !packageName.startsWith("@prosopo/")) {
|
|
33
|
-
pkg = `@prosopo/${packageName}`;
|
|
34
|
-
}
|
|
35
|
-
const pkgCommand = `npm list ${pkg} -ap`;
|
|
36
|
-
console.info(`Running command ${pkgCommand}`);
|
|
37
|
-
// get package directory
|
|
38
|
-
const { stdout: packageDir, stderr } = await exec(pkgCommand);
|
|
39
|
-
if (stderr) {
|
|
40
|
-
if (stderr.includes("ERR!")) {
|
|
41
|
-
throw new Error("CONFIG.INVALID_PACKAGE_DIR");
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return packageDir.trim() || path.resolve();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Resolve the tsconfig path for a reference using the initial tsconfig path and the reference path. If the reference
|
|
49
|
-
* does not contain a tsconfig filename, `tsconfig.json` will be appended to the path.
|
|
50
|
-
* @param initialTsConfigPath
|
|
51
|
-
* @param reference
|
|
52
|
-
*/
|
|
53
|
-
function getReferenceTsConfigPath(
|
|
54
|
-
initialTsConfigPath: string,
|
|
55
|
-
reference: ProjectReference,
|
|
56
|
-
) {
|
|
57
|
-
// remove tsconfig.*.json from the path and get the path to the new directory via the reference path
|
|
58
|
-
let refTSConfigPath = path.resolve(
|
|
59
|
-
getTsconfigDir(initialTsConfigPath),
|
|
60
|
-
reference.path,
|
|
61
|
-
);
|
|
62
|
-
if (!refTSConfigPath.endsWith(".json")) {
|
|
63
|
-
refTSConfigPath = path.resolve(refTSConfigPath, "tsconfig.json");
|
|
64
|
-
}
|
|
65
|
-
return refTSConfigPath;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Get the tsconfig paths for a package
|
|
70
|
-
* @param tsConfigPath the tsconfig path to start with
|
|
71
|
-
* @param ignorePatterns the patterns to ignore
|
|
72
|
-
* @param tsConfigPaths the tsconfig paths to add to
|
|
73
|
-
* @param includeInitialTsConfig return the initial tsconfig path in the returned array
|
|
74
|
-
*/
|
|
75
|
-
export function getTsConfigs(
|
|
76
|
-
tsConfigPath: string,
|
|
77
|
-
ignorePatterns: RegExp[] = [],
|
|
78
|
-
tsConfigPaths: string[] = [],
|
|
79
|
-
includeInitialTsConfig = true,
|
|
80
|
-
): string[] {
|
|
81
|
-
let tsConfigs = [...tsConfigPaths];
|
|
82
|
-
//TODO use dynamic import with JSON assertion (TS complains that resolveJsonModule is not set)
|
|
83
|
-
const references = JSON.parse(
|
|
84
|
-
fs.readFileSync(tsConfigPath).toString(),
|
|
85
|
-
).references;
|
|
86
|
-
if (!tsConfigs.includes(tsConfigPath)) {
|
|
87
|
-
if (references) {
|
|
88
|
-
const ignore =
|
|
89
|
-
ignorePatterns && ignorePatterns.length > 0
|
|
90
|
-
? new RegExp(`${ignorePatterns.join("|")}`)
|
|
91
|
-
: undefined;
|
|
92
|
-
if (includeInitialTsConfig) {
|
|
93
|
-
tsConfigs.push(tsConfigPath);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ignore the packages we don't want to bundle
|
|
97
|
-
const filteredReferences = references.filter(
|
|
98
|
-
(reference: ProjectReference) =>
|
|
99
|
-
ignore ? !ignore.test(reference.path) : false,
|
|
100
|
-
);
|
|
101
|
-
// for each reference, get the tsconfig paths - recursively calling this function
|
|
102
|
-
for (const reference of filteredReferences) {
|
|
103
|
-
// remove tsconfig.*.json from the path and get the path to the new directory via the reference path
|
|
104
|
-
const refTSConfigPath = getReferenceTsConfigPath(
|
|
105
|
-
tsConfigPath,
|
|
106
|
-
reference,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
// take the reference TS config path (refTSConfigPath) and get the tsconfig paths for it (newTsConfigs),
|
|
110
|
-
// adding both to a distinct list, as there may be duplicates
|
|
111
|
-
const newTsConfigs = getTsConfigs(
|
|
112
|
-
refTSConfigPath,
|
|
113
|
-
ignorePatterns,
|
|
114
|
-
tsConfigs,
|
|
115
|
-
);
|
|
116
|
-
if (newTsConfigs.length > 0) {
|
|
117
|
-
const distinctTsConfigPaths = new Set(tsConfigs.concat(newTsConfigs));
|
|
118
|
-
tsConfigs = [...distinctTsConfigPaths];
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return tsConfigs;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Get the workspace externals for a package
|
|
128
|
-
* @param tsConfigPath
|
|
129
|
-
* @param ignorePatterns
|
|
130
|
-
*/
|
|
131
|
-
export async function getExternalsFromReferences(
|
|
132
|
-
tsConfigPath: string,
|
|
133
|
-
ignorePatterns: RegExp[] = [],
|
|
134
|
-
): Promise<string[]> {
|
|
135
|
-
const tsConfigPaths = getTsConfigs(tsConfigPath, ignorePatterns, [], false);
|
|
136
|
-
console.debug({ tsConfigPaths });
|
|
137
|
-
const promises: Promise<string>[] = [];
|
|
138
|
-
for (const refTsConfigPath of tsConfigPaths) {
|
|
139
|
-
const packageJsonPath = path.resolve(
|
|
140
|
-
getTsconfigDir(refTsConfigPath),
|
|
141
|
-
"package.json",
|
|
142
|
-
);
|
|
143
|
-
promises.push(
|
|
144
|
-
new Promise((resolve, reject) => {
|
|
145
|
-
// if package.json exists, read it and get the package name
|
|
146
|
-
fs.stat(packageJsonPath, (err) => {
|
|
147
|
-
if (err) {
|
|
148
|
-
reject(err);
|
|
149
|
-
}
|
|
150
|
-
fs.readFile(packageJsonPath, (err, buffer) => {
|
|
151
|
-
if (err) {
|
|
152
|
-
reject(err);
|
|
153
|
-
} else {
|
|
154
|
-
const packageJson = JSON.parse(buffer.toString());
|
|
155
|
-
const pkg = packageJson.name;
|
|
156
|
-
resolve(pkg);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
}),
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
const externals = await Promise.all(promises);
|
|
164
|
-
console.debug({ externals });
|
|
165
|
-
return externals;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Get the dependencies for a package
|
|
170
|
-
* @param packageName
|
|
171
|
-
* @param production
|
|
172
|
-
*/
|
|
173
|
-
export async function getDependencies(
|
|
174
|
-
packageName?: string,
|
|
175
|
-
production?: boolean,
|
|
176
|
-
): Promise<{ dependencies: string[]; optionalPeerDependencies: string[] }> {
|
|
177
|
-
let cmd = production
|
|
178
|
-
? "npm ls -a --silent --omit=dev --package-lock-only"
|
|
179
|
-
: "npm ls --silent -a --package-lock-only";
|
|
180
|
-
|
|
181
|
-
if (packageName) {
|
|
182
|
-
const packageDir = await getPackageDir(packageName);
|
|
183
|
-
cmd = `cd ${packageDir.trim()} && ${cmd}`;
|
|
184
|
-
console.info(`Running command ${cmd} in ${packageDir}`);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
let concat = "";
|
|
188
|
-
// `npm ls` exits non-zero on any invalid/unmet/extraneous dependency (e.g.
|
|
189
|
-
// Vite 8's optional `yaml` peer being satisfied by a hoisted v1 from
|
|
190
|
-
// cosmiconfig). It still prints the full tree to stdout in that case, so we
|
|
191
|
-
// tolerate the non-zero exit and parse whatever was emitted.
|
|
192
|
-
try {
|
|
193
|
-
const { stdout, stderr } = await exec(cmd);
|
|
194
|
-
concat = stdout + stderr;
|
|
195
|
-
} catch (error) {
|
|
196
|
-
const execError = error as { stdout?: string; stderr?: string };
|
|
197
|
-
if (typeof execError.stdout === "string") {
|
|
198
|
-
concat = execError.stdout + (execError.stderr ?? "");
|
|
199
|
-
} else {
|
|
200
|
-
throw error;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
let deps: string[] = [];
|
|
205
|
-
let peerDeps: string[] = [];
|
|
206
|
-
// for each line, check if there is an unmet optional dependency
|
|
207
|
-
for (const line of concat.split("\n")) {
|
|
208
|
-
if (line.includes("UNMET OPTIONAL DEPENDENCY")) {
|
|
209
|
-
// │ │ │ ├── UNMET OPTIONAL DEPENDENCY bufferutil@^4.0.1
|
|
210
|
-
const parts = line.match(peerDepsRegex);
|
|
211
|
-
if (parts && parts.length > 1) {
|
|
212
|
-
peerDeps.push(parts[1] as string);
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
// │ │ │ ├─┬ mongodb-memory-server-core@8.15.1
|
|
216
|
-
const parts = line.match(depsRegex);
|
|
217
|
-
if (parts && parts.length > 1) {
|
|
218
|
-
deps.push(parts[1] as string);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ensure deps and peerDeps are unique
|
|
224
|
-
deps = [...new Set(deps)];
|
|
225
|
-
peerDeps = [...new Set(peerDeps)];
|
|
226
|
-
|
|
227
|
-
// dedupe and return deps and peer deps
|
|
228
|
-
return {
|
|
229
|
-
dependencies: deps.filter((x, i) => i === deps.indexOf(x)),
|
|
230
|
-
optionalPeerDependencies: peerDeps.filter(
|
|
231
|
-
(x, i) => i === peerDeps.indexOf(x),
|
|
232
|
-
),
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Filter out the dependencies we don't want
|
|
238
|
-
* @param deps
|
|
239
|
-
* @param filters
|
|
240
|
-
*/
|
|
241
|
-
export function filterDependencies(
|
|
242
|
-
deps: string[],
|
|
243
|
-
filters: string[],
|
|
244
|
-
): { internal: string[]; external: string[] } {
|
|
245
|
-
const depsDeduped = deps.filter((x, i) => i === deps.indexOf(x));
|
|
246
|
-
const depsWithLength = depsDeduped.filter((dep) => dep.length > 0).sort();
|
|
247
|
-
const exclude = new RegExp(`${filters.join("|")}`);
|
|
248
|
-
// filter out the deps we don't want
|
|
249
|
-
const internal: string[] = [];
|
|
250
|
-
const external: string[] = [];
|
|
251
|
-
for (const dep of depsWithLength) {
|
|
252
|
-
if (exclude.test(dep)) {
|
|
253
|
-
external.push(dep);
|
|
254
|
-
} else {
|
|
255
|
-
internal.push(dep);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
return { internal, external };
|
|
259
|
-
}
|
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
|
|
15
|
-
import type { ExecException } from "node:child_process";
|
|
16
|
-
import path from "node:path";
|
|
17
|
-
import { promisify } from "node:util";
|
|
18
|
-
import type { UserConfig } from "vite";
|
|
19
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
20
|
-
|
|
21
|
-
/** What `npm ls` handed back for a given command. */
|
|
22
|
-
interface ExecResult {
|
|
23
|
-
stdout: string;
|
|
24
|
-
stderr: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
type ExecCallback = (
|
|
28
|
-
error: ExecException | null,
|
|
29
|
-
stdout: string,
|
|
30
|
-
stderr: string,
|
|
31
|
-
) => void;
|
|
32
|
-
|
|
33
|
-
/** Commands seen, in order, so the tests can assert on what was run. */
|
|
34
|
-
let commands: string[] = [];
|
|
35
|
-
/** Queue of responses, consumed one per `exec` call. */
|
|
36
|
-
let responses: (ExecResult | Error)[] = [];
|
|
37
|
-
|
|
38
|
-
const fakeExec = (command: string, callback: ExecCallback): void => {
|
|
39
|
-
commands.push(command);
|
|
40
|
-
const next = responses.shift();
|
|
41
|
-
if (next === undefined) {
|
|
42
|
-
throw new Error(`unexpected exec: ${command}`);
|
|
43
|
-
}
|
|
44
|
-
if (next instanceof Error) {
|
|
45
|
-
callback(next, "", "");
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
callback(null, next.stdout, next.stderr);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// `util.promisify` honours this symbol, which is how the real
|
|
52
|
-
// `child_process.exec` resolves to `{ stdout, stderr }` rather than to stdout
|
|
53
|
-
// alone. The mock has to provide it or the promisified call shape differs from
|
|
54
|
-
// production.
|
|
55
|
-
Object.defineProperty(fakeExec, promisify.custom, {
|
|
56
|
-
value: (command: string): Promise<ExecResult> =>
|
|
57
|
-
new Promise((resolve, reject) => {
|
|
58
|
-
fakeExec(command, (error, stdout, stderr) => {
|
|
59
|
-
if (error) {
|
|
60
|
-
reject(error);
|
|
61
|
-
} else {
|
|
62
|
-
resolve({ stdout, stderr });
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}),
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
vi.mock("node:child_process", () => ({ default: { exec: fakeExec } }));
|
|
69
|
-
|
|
70
|
-
const { getDependencies } = await import("./dependencies.js");
|
|
71
|
-
|
|
72
|
-
beforeEach(() => {
|
|
73
|
-
commands = [];
|
|
74
|
-
responses = [];
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
afterEach(() => {
|
|
78
|
-
expect(responses).toEqual([]);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const ok = (stdout: string, stderr = ""): ExecResult => ({ stdout, stderr });
|
|
82
|
-
|
|
83
|
-
/** `util.promisify` reads stdout/stderr off the error for a failing exec. */
|
|
84
|
-
const failing = (stdout: string, stderr = ""): Error => {
|
|
85
|
-
const error: ExecException & { stdout?: string; stderr?: string } =
|
|
86
|
-
Object.assign(new Error("npm ls exited 1"), { stdout, stderr });
|
|
87
|
-
return error;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const TREE = [
|
|
91
|
-
"@prosopo/root@1.0.0 /repo",
|
|
92
|
-
"├─┬ mongodb@6.3.0",
|
|
93
|
-
"│ └── bson@6.2.0",
|
|
94
|
-
"└── zod@3.22.4",
|
|
95
|
-
].join("\n");
|
|
96
|
-
|
|
97
|
-
describe("getDependencies", () => {
|
|
98
|
-
it("parses every package name out of the npm ls tree", async () => {
|
|
99
|
-
responses = [ok(TREE)];
|
|
100
|
-
const { dependencies } = await getDependencies();
|
|
101
|
-
expect(dependencies).toEqual(["mongodb", "bson", "zod"]);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it("does not treat the root package line as a dependency", async () => {
|
|
105
|
-
// The root line has no leading whitespace, which is what the regex keys
|
|
106
|
-
// off — a package must never externalise itself.
|
|
107
|
-
responses = [ok(TREE)];
|
|
108
|
-
const { dependencies } = await getDependencies();
|
|
109
|
-
expect(dependencies).not.toContain("@prosopo/root");
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("collects unmet optional peers separately", async () => {
|
|
113
|
-
responses = [
|
|
114
|
-
ok(
|
|
115
|
-
[
|
|
116
|
-
"│ ├── UNMET OPTIONAL DEPENDENCY bufferutil@^4.0.1",
|
|
117
|
-
"│ ├── UNMET OPTIONAL DEPENDENCY utf-8-validate@^5.0.2",
|
|
118
|
-
"└── zod@3.22.4",
|
|
119
|
-
].join("\n"),
|
|
120
|
-
),
|
|
121
|
-
];
|
|
122
|
-
const { dependencies, optionalPeerDependencies } = await getDependencies();
|
|
123
|
-
expect(optionalPeerDependencies).toEqual(["bufferutil", "utf-8-validate"]);
|
|
124
|
-
expect(dependencies).toEqual(["zod"]);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("deduplicates packages that appear all over the tree", async () => {
|
|
128
|
-
responses = [ok(["├── zod@3.22.4", "│ └── zod@3.22.4"].join("\n"))];
|
|
129
|
-
await expect(getDependencies()).resolves.toEqual({
|
|
130
|
-
dependencies: ["zod"],
|
|
131
|
-
optionalPeerDependencies: [],
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("returns empty lists for an empty tree", async () => {
|
|
136
|
-
responses = [ok("")];
|
|
137
|
-
await expect(getDependencies()).resolves.toEqual({
|
|
138
|
-
dependencies: [],
|
|
139
|
-
optionalPeerDependencies: [],
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("omits dev dependencies when asked for a production tree", async () => {
|
|
144
|
-
responses = [ok(TREE)];
|
|
145
|
-
await getDependencies(undefined, true);
|
|
146
|
-
expect(commands[0]).toContain("--omit=dev");
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("keeps dev dependencies otherwise", async () => {
|
|
150
|
-
responses = [ok(TREE)];
|
|
151
|
-
await getDependencies(undefined, false);
|
|
152
|
-
expect(commands[0]).not.toContain("--omit=dev");
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("resolves the package directory first and runs npm ls inside it", async () => {
|
|
156
|
-
responses = [ok("/repo/packages/server\n"), ok(TREE)];
|
|
157
|
-
await getDependencies("@prosopo/server");
|
|
158
|
-
expect(commands[0]).toBe("npm list @prosopo/server -ap");
|
|
159
|
-
expect(commands[1]).toContain("cd /repo/packages/server &&");
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it("prefixes a bare package name with the scope", async () => {
|
|
163
|
-
responses = [ok("/repo/packages/server\n"), ok(TREE)];
|
|
164
|
-
await getDependencies("server");
|
|
165
|
-
expect(commands[0]).toBe("npm list @prosopo/server -ap");
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it("leaves an already-scoped name alone", async () => {
|
|
169
|
-
responses = [ok("/repo/packages/server\n"), ok(TREE)];
|
|
170
|
-
await getDependencies("@prosopo/server");
|
|
171
|
-
expect(commands[0]).toBe("npm list @prosopo/server -ap");
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it("falls back to the working directory when npm prints no path", async () => {
|
|
175
|
-
responses = [ok(" \n"), ok(TREE)];
|
|
176
|
-
await getDependencies("@prosopo/server");
|
|
177
|
-
expect(commands[1]).toContain(`cd ${process.cwd()} &&`);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it("rejects when the package cannot be located", async () => {
|
|
181
|
-
responses = [ok("", "npm ERR! code E404")];
|
|
182
|
-
await expect(getDependencies("@prosopo/absent")).rejects.toThrow(
|
|
183
|
-
"CONFIG.INVALID_PACKAGE_DIR",
|
|
184
|
-
);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it("tolerates npm warnings on stderr that are not errors", async () => {
|
|
188
|
-
responses = [
|
|
189
|
-
ok("/repo/packages/server\n", "npm warn deprecated"),
|
|
190
|
-
ok(TREE),
|
|
191
|
-
];
|
|
192
|
-
await expect(getDependencies("@prosopo/server")).resolves.toMatchObject({
|
|
193
|
-
dependencies: ["mongodb", "bson", "zod"],
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it("still parses the tree when npm ls exits non-zero", async () => {
|
|
198
|
-
// `npm ls` exits 1 for any unmet or extraneous dependency but still
|
|
199
|
-
// prints the whole tree, so the build must not be blocked by it.
|
|
200
|
-
responses = [failing(TREE)];
|
|
201
|
-
const { dependencies } = await getDependencies();
|
|
202
|
-
expect(dependencies).toEqual(["mongodb", "bson", "zod"]);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it("rethrows when a failing npm ls produced no output at all", async () => {
|
|
206
|
-
const error: ExecException = new Error("npm not found");
|
|
207
|
-
responses = [error];
|
|
208
|
-
await expect(getDependencies()).rejects.toThrow("npm not found");
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
it("reads stderr as well as stdout, since npm splits the tree across both", async () => {
|
|
212
|
-
responses = [ok("├── zod@3.22.4", "\n└── axios@1.6.0")];
|
|
213
|
-
const { dependencies } = await getDependencies();
|
|
214
|
-
expect(dependencies).toEqual(["zod", "axios"]);
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
const { default: ViteBackendConfig } = await import(
|
|
219
|
-
"./vite/vite.backend.config.js"
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
/** Every backend config starts with the same two npm ls calls. */
|
|
223
|
-
const npmLsResponses = (): (ExecResult | Error)[] => [
|
|
224
|
-
ok("/repo/packages/server\n"),
|
|
225
|
-
ok(TREE),
|
|
226
|
-
];
|
|
227
|
-
|
|
228
|
-
const externalsOf = (config: UserConfig): string[] => {
|
|
229
|
-
const external = config.build?.rollupOptions?.external;
|
|
230
|
-
if (!Array.isArray(external)) {
|
|
231
|
-
throw new Error("expected an array of externals");
|
|
232
|
-
}
|
|
233
|
-
return external.map(String);
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
// Hand-rolled rather than `.flat(Infinity)`: a non-literal depth makes tsc
|
|
237
|
-
// expand FlatArray until it gives up with TS2589.
|
|
238
|
-
const flattenDeep = (value: unknown): unknown[] =>
|
|
239
|
-
Array.isArray(value) ? value.flatMap(flattenDeep) : [value];
|
|
240
|
-
|
|
241
|
-
const pluginNamesOf = (plugins: UserConfig["plugins"]): string[] =>
|
|
242
|
-
flattenDeep(plugins ?? []).map((plugin) => {
|
|
243
|
-
if (plugin && typeof plugin === "object" && "name" in plugin) {
|
|
244
|
-
return String(plugin.name);
|
|
245
|
-
}
|
|
246
|
-
return "";
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
describe("ViteBackendConfig", () => {
|
|
250
|
-
const build = (
|
|
251
|
-
command?: string,
|
|
252
|
-
mode?: string,
|
|
253
|
-
outputDir?: string,
|
|
254
|
-
): Promise<UserConfig> => {
|
|
255
|
-
responses = npmLsResponses();
|
|
256
|
-
return ViteBackendConfig(
|
|
257
|
-
"@prosopo/server",
|
|
258
|
-
"1.2.3",
|
|
259
|
-
"server",
|
|
260
|
-
"/repo/packages/server",
|
|
261
|
-
"src/index.ts",
|
|
262
|
-
command,
|
|
263
|
-
mode,
|
|
264
|
-
outputDir,
|
|
265
|
-
);
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
it("emits an esm bundle named after the bundle name", async () => {
|
|
269
|
-
const config = await build();
|
|
270
|
-
expect(config.build?.lib).toMatchObject({
|
|
271
|
-
name: "server",
|
|
272
|
-
formats: ["es"],
|
|
273
|
-
fileName: "server.[name].bundle.js",
|
|
274
|
-
});
|
|
275
|
-
expect(config.build?.rollupOptions?.output).toMatchObject({
|
|
276
|
-
entryFileNames: "server.[name].bundle.js",
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it("defaults the output to dist/bundle inside the package", async () => {
|
|
281
|
-
const config = await build();
|
|
282
|
-
expect(config.build?.outDir).toBe(
|
|
283
|
-
path.resolve("/repo/packages/server", "dist/bundle"),
|
|
284
|
-
);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it("honours an explicit output directory", async () => {
|
|
288
|
-
const config = await build(undefined, undefined, "/tmp/out");
|
|
289
|
-
expect(config.build?.outDir).toBe(path.resolve("/tmp/out"));
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it("minifies only in production", async () => {
|
|
293
|
-
await expect(build(undefined, "production")).resolves.toMatchObject({
|
|
294
|
-
build: { minify: true },
|
|
295
|
-
});
|
|
296
|
-
await expect(build(undefined, "development")).resolves.toMatchObject({
|
|
297
|
-
build: { minify: false },
|
|
298
|
-
});
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it("bakes the package version into the bundle", async () => {
|
|
302
|
-
const config = await build();
|
|
303
|
-
expect(config.define).toMatchObject({
|
|
304
|
-
"process.env.PROSOPO_PACKAGE_VERSION": '"1.2.3"',
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("stubs out the optional websocket native helpers", async () => {
|
|
309
|
-
// bufferutil and utf-8-validate are optional native deps; without these
|
|
310
|
-
// flags ws tries to require them and the bundle dies at boot.
|
|
311
|
-
const config = await build();
|
|
312
|
-
expect(config.define).toMatchObject({
|
|
313
|
-
"process.env.WS_NO_BUFFER_UTIL": "true",
|
|
314
|
-
"process.env.WS_NO_UTF_8_VALIDATE": "true",
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it("bundles punycode rather than externalising it", async () => {
|
|
319
|
-
// The provider image ships no node_modules, so an external deep import
|
|
320
|
-
// like "punycode/punycode.es6.js" is an immediate boot failure.
|
|
321
|
-
const config = await build();
|
|
322
|
-
expect(externalsOf(config)).not.toContain("punycode");
|
|
323
|
-
expect(externalsOf(config)).toContain("node:punycode");
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it("externalises the remaining node builtins", async () => {
|
|
327
|
-
const list = externalsOf(await build());
|
|
328
|
-
expect(list).toContain("fs");
|
|
329
|
-
expect(list).toContain("node:fs");
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
it("resolves the entry against the package directory", async () => {
|
|
333
|
-
const config = await build();
|
|
334
|
-
expect(config.build?.lib).toMatchObject({
|
|
335
|
-
entry: [path.resolve("/repo/packages/server", "src/index.ts")],
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it("resolves a list of entries", async () => {
|
|
340
|
-
responses = npmLsResponses();
|
|
341
|
-
const config = await ViteBackendConfig(
|
|
342
|
-
"@prosopo/server",
|
|
343
|
-
"1.2.3",
|
|
344
|
-
"server",
|
|
345
|
-
"/repo/packages/server",
|
|
346
|
-
["src/a.ts", "src/b.ts"],
|
|
347
|
-
);
|
|
348
|
-
expect(config.build?.lib).toMatchObject({
|
|
349
|
-
entry: [
|
|
350
|
-
path.resolve("/repo/packages/server", "src/a.ts"),
|
|
351
|
-
path.resolve("/repo/packages/server", "src/b.ts"),
|
|
352
|
-
],
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it("resolves a named entry map", async () => {
|
|
357
|
-
responses = npmLsResponses();
|
|
358
|
-
const config = await ViteBackendConfig(
|
|
359
|
-
"@prosopo/server",
|
|
360
|
-
"1.2.3",
|
|
361
|
-
"server",
|
|
362
|
-
"/repo/packages/server",
|
|
363
|
-
{ cli: "src/cli.ts" },
|
|
364
|
-
);
|
|
365
|
-
expect(config.build?.lib).toMatchObject({
|
|
366
|
-
entry: { cli: path.resolve("/repo/packages/server", "src/cli.ts") },
|
|
367
|
-
});
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
it("skips the close plugin while serving, so the dev server stays up", async () => {
|
|
371
|
-
const serving = (await build("serve")).plugins ?? [];
|
|
372
|
-
const building = (await build("build")).plugins ?? [];
|
|
373
|
-
expect(pluginNamesOf(serving)).not.toContain("close-plugin");
|
|
374
|
-
expect(pluginNamesOf(building)).toContain("close-plugin");
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it("keeps module side effects when treeshaking", async () => {
|
|
378
|
-
// Dropping them broke polyfills that register themselves on import.
|
|
379
|
-
const config = await build();
|
|
380
|
-
expect(config.build?.rollupOptions?.treeshake).toMatchObject({
|
|
381
|
-
annotations: true,
|
|
382
|
-
moduleSideEffects: true,
|
|
383
|
-
});
|
|
384
|
-
});
|
|
385
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
-
//
|
|
3
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
// you may not use this file except in compliance with the License.
|
|
5
|
-
// You may obtain a copy of the License at
|
|
6
|
-
//
|
|
7
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
//
|
|
9
|
-
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
// See the License for the specific language governing permissions and
|
|
13
|
-
// limitations under the License.
|
|
14
|
-
export * from "./vite/index.js";
|
|
15
|
-
export * from "./dependencies.js";
|
|
16
|
-
export * from "./webpack/index.js";
|