@prosopo/config 3.4.2 → 3.4.3
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 +13 -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 +8 -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 -0
- package/dist/webpack/webpack.config.d.ts.map +1 -1
- package/dist/webpack/webpack.config.js +8 -8
- package/dist/webpack/webpack.config.js.map +1 -1
- package/package.json +106 -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
|
@@ -1,162 +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
|
-
// Drives vitest's own file collection over a fixture package, so the
|
|
16
|
-
// assertions are about which files actually run, not about glob strings.
|
|
17
|
-
|
|
18
|
-
import fs from "node:fs";
|
|
19
|
-
import os from "node:os";
|
|
20
|
-
import path from "node:path";
|
|
21
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
22
|
-
import { createVitest } from "vitest/node";
|
|
23
|
-
import { parseTestTypes, testFileGlobs } from "./testFileGlobs.js";
|
|
24
|
-
import ViteTestConfig from "./vite.test.config.js";
|
|
25
|
-
import ViteThreadsTestConfig from "./vite.threads.test.config.js";
|
|
26
|
-
|
|
27
|
-
const FIXTURE_FILES: readonly string[] = [
|
|
28
|
-
"src/untyped.test.ts",
|
|
29
|
-
"src/typed.unit.test.ts",
|
|
30
|
-
"src/typed.integration.test.ts",
|
|
31
|
-
"src/nested/named.withDots.test.ts",
|
|
32
|
-
"src/component.spec.tsx",
|
|
33
|
-
"src/notATest.ts",
|
|
34
|
-
"src/types.test-d.ts",
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
const ALL_RUNTIME_TESTS: readonly string[] = [
|
|
38
|
-
"src/component.spec.tsx",
|
|
39
|
-
"src/nested/named.withDots.test.ts",
|
|
40
|
-
"src/typed.integration.test.ts",
|
|
41
|
-
"src/typed.unit.test.ts",
|
|
42
|
-
"src/untyped.test.ts",
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
let root: string;
|
|
46
|
-
let cwd: string;
|
|
47
|
-
let originalTestType: string | undefined;
|
|
48
|
-
|
|
49
|
-
beforeEach(() => {
|
|
50
|
-
root = fs.mkdtempSync(path.join(os.tmpdir(), "prosopo-test-globs-"));
|
|
51
|
-
for (const file of FIXTURE_FILES) {
|
|
52
|
-
fs.mkdirSync(path.dirname(path.join(root, file)), { recursive: true });
|
|
53
|
-
fs.writeFileSync(path.join(root, file), "export {};\n");
|
|
54
|
-
}
|
|
55
|
-
fs.writeFileSync(path.join(root, "package.json"), "{}");
|
|
56
|
-
cwd = process.cwd();
|
|
57
|
-
process.chdir(root);
|
|
58
|
-
originalTestType = process.env.TEST_TYPE;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
afterEach(() => {
|
|
62
|
-
process.chdir(cwd);
|
|
63
|
-
if (originalTestType === undefined) {
|
|
64
|
-
// biome-ignore lint/performance/noDelete: restore absence, not ""
|
|
65
|
-
delete process.env.TEST_TYPE;
|
|
66
|
-
} else {
|
|
67
|
-
process.env.TEST_TYPE = originalTestType;
|
|
68
|
-
}
|
|
69
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
type ConfigFactory = () => ReturnType<typeof ViteTestConfig>;
|
|
73
|
-
|
|
74
|
-
/** Files vitest would collect for `TEST_TYPE=testType` under `factory`. */
|
|
75
|
-
const collected = async (
|
|
76
|
-
factory: ConfigFactory,
|
|
77
|
-
testType: string | undefined,
|
|
78
|
-
): Promise<string[]> => {
|
|
79
|
-
if (testType === undefined) {
|
|
80
|
-
// biome-ignore lint/performance/noDelete: the config reads presence, not value
|
|
81
|
-
delete process.env.TEST_TYPE;
|
|
82
|
-
} else {
|
|
83
|
-
process.env.TEST_TYPE = testType;
|
|
84
|
-
}
|
|
85
|
-
const config = factory();
|
|
86
|
-
const vitest = await createVitest(
|
|
87
|
-
"test",
|
|
88
|
-
{ config: false, root, watch: false },
|
|
89
|
-
{
|
|
90
|
-
test: {
|
|
91
|
-
include: config.test?.include,
|
|
92
|
-
exclude: config.test?.exclude,
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
);
|
|
96
|
-
try {
|
|
97
|
-
const specs = await vitest.globTestSpecifications();
|
|
98
|
-
return specs
|
|
99
|
-
.map((spec) =>
|
|
100
|
-
path.relative(root, spec.moduleId).split(path.sep).join("/"),
|
|
101
|
-
)
|
|
102
|
-
.sort();
|
|
103
|
-
} finally {
|
|
104
|
-
await vitest.close();
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const without = (excluded: string): string[] =>
|
|
109
|
-
ALL_RUNTIME_TESTS.filter((f) => f !== excluded);
|
|
110
|
-
|
|
111
|
-
describe.each([
|
|
112
|
-
["ViteTestConfig", (): ReturnType<typeof ViteTestConfig> => ViteTestConfig()],
|
|
113
|
-
[
|
|
114
|
-
"ViteThreadsTestConfig",
|
|
115
|
-
(): ReturnType<typeof ViteTestConfig> => ViteThreadsTestConfig(),
|
|
116
|
-
],
|
|
117
|
-
])("%s test file collection", (_name: string, factory: ConfigFactory) => {
|
|
118
|
-
it("collects every test file when TEST_TYPE is unset", async () => {
|
|
119
|
-
expect(await collected(factory, undefined)).toEqual(ALL_RUNTIME_TESTS);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it("treats an empty TEST_TYPE as unset", async () => {
|
|
123
|
-
expect(await collected(factory, "")).toEqual(ALL_RUNTIME_TESTS);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("TEST_TYPE=unit keeps untyped tests and drops integration tests", async () => {
|
|
127
|
-
expect(await collected(factory, "unit")).toEqual(
|
|
128
|
-
without("src/typed.integration.test.ts"),
|
|
129
|
-
);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it("TEST_TYPE=integration keeps untyped tests and drops unit tests", async () => {
|
|
133
|
-
expect(await collected(factory, "integration")).toEqual(
|
|
134
|
-
without("src/typed.unit.test.ts"),
|
|
135
|
-
);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("accepts a spaced, comma-separated list", async () => {
|
|
139
|
-
expect(await collected(factory, " unit , integration ")).toEqual(
|
|
140
|
-
ALL_RUNTIME_TESTS,
|
|
141
|
-
);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
describe("testFileGlobs", () => {
|
|
146
|
-
it("excludes nothing without a filter", () => {
|
|
147
|
-
expect(testFileGlobs(undefined).exclude).toEqual([]);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("excludes only the known types that were not selected", () => {
|
|
151
|
-
expect(testFileGlobs("unit").exclude).toEqual([
|
|
152
|
-
"src/**/*.@(integration).@(test|spec).@(mts|cts|mjs|cjs|js|ts|tsx|jsx)",
|
|
153
|
-
]);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it("parses the list, dropping blanks", () => {
|
|
157
|
-
expect(parseTestTypes(" unit, ,integration ")).toEqual([
|
|
158
|
-
"unit",
|
|
159
|
-
"integration",
|
|
160
|
-
]);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
@@ -1,57 +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
|
-
/** Test types a file can declare as `name.<type>.test.ts`. */
|
|
16
|
-
export const KNOWN_TEST_TYPES: readonly string[] = ["unit", "integration"];
|
|
17
|
-
|
|
18
|
-
const TEST_FILE_SUFFIX =
|
|
19
|
-
"@(test|spec).@(mts|cts|mjs|cjs|js|ts|tsx|jsx)" as const;
|
|
20
|
-
|
|
21
|
-
export interface TestFileGlobs {
|
|
22
|
-
include: string[];
|
|
23
|
-
exclude: string[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const parseTestTypes = (testTypeEnv: string | undefined): string[] =>
|
|
27
|
-
(testTypeEnv ?? "")
|
|
28
|
-
.split(",")
|
|
29
|
-
.map((t) => t.trim())
|
|
30
|
-
.filter((t) => t.length > 0);
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Globs selecting the test files for a `TEST_TYPE` filter.
|
|
34
|
-
*
|
|
35
|
-
* Filtering works by excluding the *other* known types rather than by
|
|
36
|
-
* including only the selected one. Files with no declared type
|
|
37
|
-
* (`foo.test.ts`) therefore run under every filter: we don't know what kind
|
|
38
|
-
* of test they are, and an include-only glob silently dropped them from
|
|
39
|
-
* packages whose `test` script sets `TEST_TYPE`.
|
|
40
|
-
*/
|
|
41
|
-
export const testFileGlobs = (
|
|
42
|
-
testTypeEnv: string | undefined,
|
|
43
|
-
): TestFileGlobs => {
|
|
44
|
-
const include = [`src/**/*.${TEST_FILE_SUFFIX}`];
|
|
45
|
-
const selected = parseTestTypes(testTypeEnv);
|
|
46
|
-
if (selected.length === 0) {
|
|
47
|
-
return { include, exclude: [] };
|
|
48
|
-
}
|
|
49
|
-
const excluded = KNOWN_TEST_TYPES.filter((t) => !selected.includes(t));
|
|
50
|
-
return {
|
|
51
|
-
include,
|
|
52
|
-
exclude:
|
|
53
|
-
excluded.length > 0
|
|
54
|
-
? [`src/**/*.@(${excluded.join("|")}).${TEST_FILE_SUFFIX}`]
|
|
55
|
-
: [],
|
|
56
|
-
};
|
|
57
|
-
};
|
|
@@ -1,164 +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 fs from "node:fs";
|
|
16
|
-
import os from "node:os";
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
import type { Rollup } from "vite";
|
|
19
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
20
|
-
import VitePluginRemoveUnusedTranslations from "./vite-plugin-remove-unused-translations.js";
|
|
21
|
-
|
|
22
|
-
let root: string;
|
|
23
|
-
let cwd: string;
|
|
24
|
-
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
root = fs.mkdtempSync(path.join(os.tmpdir(), "prosopo-translations-test-"));
|
|
27
|
-
cwd = process.cwd();
|
|
28
|
-
process.chdir(root);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
process.chdir(cwd);
|
|
33
|
-
fs.rmSync(root, { recursive: true, force: true });
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
/** Vite plugin hooks may be a bare function or an object with a `handler`. */
|
|
37
|
-
type Hook<A extends unknown[], R> =
|
|
38
|
-
| ((...args: A) => R)
|
|
39
|
-
| { handler: (...args: A) => R }
|
|
40
|
-
| undefined;
|
|
41
|
-
|
|
42
|
-
const callHook = <A extends unknown[], R>(hook: Hook<A, R>, ...args: A): R => {
|
|
43
|
-
if (!hook) {
|
|
44
|
-
throw new Error("plugin does not define the hook");
|
|
45
|
-
}
|
|
46
|
-
const handler = typeof hook === "function" ? hook : hook.handler;
|
|
47
|
-
return handler(...args);
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const writeJson = (name: string, data: unknown): string => {
|
|
51
|
-
const filePath = path.join(root, name);
|
|
52
|
-
fs.writeFileSync(filePath, JSON.stringify(data));
|
|
53
|
-
return filePath;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const readJson = (filePath: string): unknown =>
|
|
57
|
-
JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
58
|
-
|
|
59
|
-
const run = async (
|
|
60
|
-
keys: string[],
|
|
61
|
-
sources: string[],
|
|
62
|
-
pattern: string,
|
|
63
|
-
): Promise<void> => {
|
|
64
|
-
const plugin = VitePluginRemoveUnusedTranslations(keys, pattern);
|
|
65
|
-
for (const source of sources) {
|
|
66
|
-
callHook(plugin.transform, source, "id.ts");
|
|
67
|
-
}
|
|
68
|
-
await callHook(
|
|
69
|
-
plugin.writeBundle,
|
|
70
|
-
{} as Rollup.NormalizedOutputOptions,
|
|
71
|
-
{} as Rollup.OutputBundle,
|
|
72
|
-
);
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
describe("VitePluginRemoveUnusedTranslations", () => {
|
|
76
|
-
it("runs after the other plugins, once the code is final", () => {
|
|
77
|
-
expect(VitePluginRemoveUnusedTranslations([], "*.json").enforce).toBe(
|
|
78
|
-
"post",
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("returns the code it was given, unmodified", () => {
|
|
83
|
-
const plugin = VitePluginRemoveUnusedTranslations(["zz"], "*.json");
|
|
84
|
-
expect(callHook(plugin.transform, "uses zz", "id.ts")).toEqual({
|
|
85
|
-
code: "uses zz",
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// The set of used keys lives at module scope, shared by every plugin
|
|
90
|
-
// instance in the process, so each test below uses key names of its own.
|
|
91
|
-
|
|
92
|
-
it("keeps only the keys the bundle actually references", async () => {
|
|
93
|
-
const file = writeJson("en.json", { kept: "yes", dropped: "no" });
|
|
94
|
-
await run(["kept", "dropped"], ["t('kept')"], `${root}/*.json`);
|
|
95
|
-
expect(readJson(file)).toEqual({ kept: "yes" });
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("restores the nesting of the keys it keeps", async () => {
|
|
99
|
-
const file = writeJson("en.json", {
|
|
100
|
-
widget: { label: "Verify", hint: "Click" },
|
|
101
|
-
});
|
|
102
|
-
await run(
|
|
103
|
-
["widget.label", "widget.hint"],
|
|
104
|
-
["t('widget.label')"],
|
|
105
|
-
`${root}/*.json`,
|
|
106
|
-
);
|
|
107
|
-
expect(readJson(file)).toEqual({ widget: { label: "Verify" } });
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("empties a file whose keys are all unused", async () => {
|
|
111
|
-
const file = writeJson("en.json", { solo: "1" });
|
|
112
|
-
await run(["solo"], ["nothing here"], `${root}/*.json`);
|
|
113
|
-
expect(readJson(file)).toEqual({});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it("prunes every matching file", async () => {
|
|
117
|
-
const en = writeJson("en.json", { pa: "en", pb: "en" });
|
|
118
|
-
const fr = writeJson("fr.json", { pa: "fr", pb: "fr" });
|
|
119
|
-
await run(["pa", "pb"], ["t('pa')"], `${root}/*.json`);
|
|
120
|
-
expect(readJson(en)).toEqual({ pa: "en" });
|
|
121
|
-
expect(readJson(fr)).toEqual({ pa: "fr" });
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("does nothing when the pattern matches no file", async () => {
|
|
125
|
-
await expect(
|
|
126
|
-
run(["nk"], ["t('nk')"], `${root}/none/*.json`),
|
|
127
|
-
).resolves.toBeUndefined();
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it("leaves a malformed JSON file alone instead of failing the build", async () => {
|
|
131
|
-
// A translation file is not worth aborting a release for; the bundle is
|
|
132
|
-
// already written by the time this hook runs.
|
|
133
|
-
const broken = path.join(root, "en.json");
|
|
134
|
-
fs.writeFileSync(broken, "{ not json");
|
|
135
|
-
await expect(
|
|
136
|
-
run(["mk"], ["t('mk')"], `${root}/*.json`),
|
|
137
|
-
).resolves.toBeUndefined();
|
|
138
|
-
expect(fs.readFileSync(broken, "utf-8")).toBe("{ not json");
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it("declares no key used when the key list is empty", async () => {
|
|
142
|
-
const file = writeJson("en.json", { ek: "1" });
|
|
143
|
-
await run([], ["t('ek')"], `${root}/*.json`);
|
|
144
|
-
expect(readJson(file)).toEqual({});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("matches a key as a substring of the emitted code", async () => {
|
|
148
|
-
// The keys are looked for with `includes`, not as whole tokens, so a key
|
|
149
|
-
// that is a prefix of another is kept whenever the longer one is used.
|
|
150
|
-
const file = writeJson("en.json", { sa: "1", sab: "2" });
|
|
151
|
-
await run(["sa", "sab"], ["t('sab')"], `${root}/*.json`);
|
|
152
|
-
expect(readJson(file)).toEqual({ sa: "1", sab: "2" });
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("accumulates used keys across every transformed module", async () => {
|
|
156
|
-
const file = writeJson("en.json", { one: "1", two: "2", three: "3" });
|
|
157
|
-
await run(
|
|
158
|
-
["one", "two", "three"],
|
|
159
|
-
["t('one')", "t('two')"],
|
|
160
|
-
`${root}/*.json`,
|
|
161
|
-
);
|
|
162
|
-
expect(readJson(file)).toEqual({ one: "1", two: "2" });
|
|
163
|
-
});
|
|
164
|
-
});
|
package/src/vite/types.ts
DELETED
|
@@ -1,13 +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.
|
|
@@ -1,76 +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 fs from "node:fs";
|
|
16
|
-
import path from "node:path";
|
|
17
|
-
import type { Plugin } from "vite";
|
|
18
|
-
|
|
19
|
-
export interface ClosePluginOptions {
|
|
20
|
-
srcDir: string;
|
|
21
|
-
destDir: string[];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* description: Closes Vite after the bundle has been build. Optionally copies the bundle to a different directory.
|
|
26
|
-
* @param { ClosePluginOptions } options - The options object
|
|
27
|
-
**/
|
|
28
|
-
export default function VitePluginCloseAndCopy(
|
|
29
|
-
options?: ClosePluginOptions,
|
|
30
|
-
): Plugin {
|
|
31
|
-
const __dirname = path.resolve();
|
|
32
|
-
return {
|
|
33
|
-
name: "close-plugin", // required, will show up in warnings and errors
|
|
34
|
-
buildStart() {
|
|
35
|
-
console.info("Bundle build started");
|
|
36
|
-
},
|
|
37
|
-
buildEnd(error) {
|
|
38
|
-
console.info("Build end");
|
|
39
|
-
if (error) {
|
|
40
|
-
console.log(error);
|
|
41
|
-
console.error(error);
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
closeBundle() {
|
|
45
|
-
if (options) {
|
|
46
|
-
for (const destDir of options.destDir) {
|
|
47
|
-
clearOutputDirJS(__dirname, destDir);
|
|
48
|
-
console.info(`Bundle cleared from ${options.destDir}`);
|
|
49
|
-
copyBundle(__dirname, options.srcDir, destDir);
|
|
50
|
-
console.info(`Bundle copied to ${options.destDir}`);
|
|
51
|
-
}
|
|
52
|
-
console.info("Bundle closed");
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const clearOutputDirJS = (__dirname: string, destDir: string) =>
|
|
59
|
-
fs
|
|
60
|
-
.readdirSync(path.resolve(__dirname, destDir))
|
|
61
|
-
.filter((file) => file.endsWith("js"))
|
|
62
|
-
.map((file) => {
|
|
63
|
-
fs.rmSync(path.resolve(__dirname, destDir, file));
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const copyBundle = (__dirname: string, srcDir: string, destDir: string) => {
|
|
67
|
-
console.info(
|
|
68
|
-
"Copying",
|
|
69
|
-
path.resolve(__dirname, srcDir),
|
|
70
|
-
"to",
|
|
71
|
-
path.resolve(__dirname, destDir),
|
|
72
|
-
);
|
|
73
|
-
fs.cpSync(path.resolve(__dirname, srcDir), path.resolve(__dirname, destDir), {
|
|
74
|
-
recursive: true,
|
|
75
|
-
});
|
|
76
|
-
};
|
|
@@ -1,67 +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 fs from "node:fs";
|
|
16
|
-
import path from "node:path";
|
|
17
|
-
import fg from "fast-glob";
|
|
18
|
-
import type { Plugin } from "vite";
|
|
19
|
-
|
|
20
|
-
interface CopyPluginOptions {
|
|
21
|
-
srcDir: string;
|
|
22
|
-
destDir: string;
|
|
23
|
-
include?: string[]; // Optional: glob patterns for files to include
|
|
24
|
-
exclude?: string[]; // Optional: glob patterns for files to exclude
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function ensureDirExists(filePath: string) {
|
|
28
|
-
const dir = path.dirname(filePath);
|
|
29
|
-
if (!fs.existsSync(dir)) {
|
|
30
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export default function VitePluginCopy(options: CopyPluginOptions): Plugin {
|
|
35
|
-
const __dirname = path.resolve();
|
|
36
|
-
return {
|
|
37
|
-
name: "copy-plugin",
|
|
38
|
-
async closeBundle() {
|
|
39
|
-
const srcAbs = path.resolve(__dirname, options.srcDir);
|
|
40
|
-
const destAbs = path.resolve(__dirname, options.destDir);
|
|
41
|
-
const include =
|
|
42
|
-
options.include && options.include.length > 0
|
|
43
|
-
? options.include
|
|
44
|
-
: undefined;
|
|
45
|
-
const exclude = options.exclude || [];
|
|
46
|
-
if (!include) {
|
|
47
|
-
console.info(
|
|
48
|
-
"[copy-plugin] No include globs specified, nothing to copy.",
|
|
49
|
-
);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const files = await fg(include, {
|
|
53
|
-
cwd: srcAbs,
|
|
54
|
-
ignore: exclude,
|
|
55
|
-
onlyFiles: true,
|
|
56
|
-
absolute: false,
|
|
57
|
-
});
|
|
58
|
-
for (const relFile of files) {
|
|
59
|
-
const srcFile = path.join(srcAbs, relFile);
|
|
60
|
-
const destFile = path.join(destAbs, relFile);
|
|
61
|
-
ensureDirExists(destFile);
|
|
62
|
-
console.info(`[copy-plugin] copying ${srcFile} to ${destFile}`);
|
|
63
|
-
fs.copyFileSync(srcFile, destFile);
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
}
|
|
@@ -1,43 +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
|
-
import type { Plugin } from "vite";
|
|
15
|
-
|
|
16
|
-
// js-confuser's `deadCode` transform injects a fixed set of fake `require()`
|
|
17
|
-
// specifiers into obfuscated sources as unreachable dead code. Rollup (Vite 6)
|
|
18
|
-
// left unresolved imports external with a warning, so these harmless specifiers
|
|
19
|
-
// never broke the build. Rolldown (Vite 8) treats an unresolved import as a hard
|
|
20
|
-
// error, so we restore the old behaviour by marking exactly these known
|
|
21
|
-
// dead-code specifiers as external. They are never executed at runtime.
|
|
22
|
-
const OBFUSCATOR_DEADCODE_SPECIFIERS: ReadonlySet<string> = new Set([
|
|
23
|
-
"../../package",
|
|
24
|
-
"../redacted.js",
|
|
25
|
-
"../utils/isStandaloneExecutable",
|
|
26
|
-
"./resolve-local-redacted-path",
|
|
27
|
-
"@redacted/components/package",
|
|
28
|
-
"@redacted/enterprise-plugin",
|
|
29
|
-
"@redacted/enterprise-plugin/package",
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
|
-
export default function VitePluginExternalizeObfuscatorDeadCode(): Plugin {
|
|
33
|
-
return {
|
|
34
|
-
name: "externalize-obfuscator-deadcode",
|
|
35
|
-
enforce: "pre",
|
|
36
|
-
resolveId(source: string) {
|
|
37
|
-
if (OBFUSCATOR_DEADCODE_SPECIFIERS.has(source)) {
|
|
38
|
-
return { id: source, external: true };
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
}
|
|
@@ -1,40 +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
|
-
import { builtinModules } from "node:module";
|
|
15
|
-
import type { Plugin } from "vite";
|
|
16
|
-
|
|
17
|
-
export default function VitePluginFixAbsoluteImports(): Plugin {
|
|
18
|
-
return {
|
|
19
|
-
name: "fix-absolute-imports",
|
|
20
|
-
transform(code: string, id: string) {
|
|
21
|
-
for (const module of builtinModules) {
|
|
22
|
-
const moduleImportRegex = new RegExp(
|
|
23
|
-
`from "(${module}(/.*)*/.*.js)";`,
|
|
24
|
-
"g",
|
|
25
|
-
);
|
|
26
|
-
// if matches, replace match with _module
|
|
27
|
-
const matches = code.match(moduleImportRegex);
|
|
28
|
-
if (matches) {
|
|
29
|
-
for (const match of matches) {
|
|
30
|
-
code = code.replace(match, `from "${module}";`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
code,
|
|
36
|
-
};
|
|
37
|
-
},
|
|
38
|
-
enforce: "post",
|
|
39
|
-
};
|
|
40
|
-
}
|
|
@@ -1,64 +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
|
-
import type { Plugin } from "vite";
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Empties the generated `exports2.FILES` array in every emitted chunk so that
|
|
18
|
-
* bundled file listings are not leaked into the output.
|
|
19
|
-
*/
|
|
20
|
-
const ASSIGNMENT = "exports2.FILES = [";
|
|
21
|
-
const TERMINATOR = "];";
|
|
22
|
-
const REPLACEMENT = "exports2.FILES = [];\n";
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Blank every `exports2.FILES = [...]` assignment in a chunk.
|
|
26
|
-
*
|
|
27
|
-
* Done with indexOf rather than a regex: `\[[\s\S]*?\];` backtracks
|
|
28
|
-
* quadratically on a chunk holding many unterminated assignments, and chunk
|
|
29
|
-
* contents are whatever the bundled sources happened to contain. Scanning
|
|
30
|
-
* forward is linear regardless.
|
|
31
|
-
*/
|
|
32
|
-
export const emptyExportsFiles = (code: string): string => {
|
|
33
|
-
let out = "";
|
|
34
|
-
let cursor = 0;
|
|
35
|
-
for (;;) {
|
|
36
|
-
const start = code.indexOf(ASSIGNMENT, cursor);
|
|
37
|
-
if (start === -1) {
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
const end = code.indexOf(TERMINATOR, start + ASSIGNMENT.length);
|
|
41
|
-
if (end === -1) {
|
|
42
|
-
// Unterminated: leave it and everything after it alone rather than
|
|
43
|
-
// truncating the chunk.
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
out += code.slice(cursor, start) + REPLACEMENT;
|
|
47
|
-
cursor = end + TERMINATOR.length;
|
|
48
|
-
}
|
|
49
|
-
return out + code.slice(cursor);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export default function modifyExportsFilesPlugin(): Plugin {
|
|
53
|
-
return {
|
|
54
|
-
name: "modify-exports-files",
|
|
55
|
-
generateBundle(_options, bundle) {
|
|
56
|
-
for (const fileName in bundle) {
|
|
57
|
-
const chunk = bundle[fileName];
|
|
58
|
-
if (chunk && chunk.type === "chunk") {
|
|
59
|
-
chunk.code = emptyExportsFiles(chunk.code);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
}
|