ember.nvp 0.5.0 → 0.7.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/.github/workflows/ci.yml +17 -2
- package/.release-plan.json +84 -4
- package/CHANGELOG.md +68 -0
- package/README.md +29 -0
- package/package.json +4 -2
- package/packages/build-tooling-utils/README.md +37 -0
- package/packages/build-tooling-utils/index.ts +2 -0
- package/packages/build-tooling-utils/package.json +42 -0
- package/packages/build-tooling-utils/rolldown.config.js +18 -0
- package/packages/build-tooling-utils/src/extensions.ts +18 -0
- package/packages/build-tooling-utils/src/maybe-babel.ts +146 -0
- package/packages/rolldown/README.md +115 -0
- package/packages/rolldown/index.ts +56 -0
- package/packages/rolldown/package.json +59 -0
- package/packages/rolldown/rolldown.config.js +21 -0
- package/packages/rolldown/src/babel.ts +136 -0
- package/packages/rolldown/src/define-config.ts +32 -0
- package/packages/rolldown/src/externals.ts +83 -0
- package/packages/rolldown/src/isolated-declarations.ts +65 -0
- package/packages/rolldown/src/transform.ts +162 -0
- package/packages/vite/README.md +7 -21
- package/packages/vite/index.ts +1 -1
- package/packages/vite/package.json +4 -6
- package/packages/vite/src/ember.ts +129 -15
- package/packages/vite/src/test-html.ts +86 -0
- package/src/bases/minimal-app/files/app/router.ts +1 -0
- package/src/bases/minimal-app/files/tsconfig.json +1 -0
- package/src/bases/minimal-app/index.js +2 -2
- package/src/bases/minimal-library/files/README.md +41 -0
- package/src/bases/minimal-library/files/package.json +49 -0
- package/src/bases/minimal-library/files/tsconfig.json +10 -0
- package/src/bases/minimal-library/files/tsdown.config.js +6 -0
- package/src/bases/minimal-library/index.js +158 -2
- package/src/cli/args.js +7 -1
- package/src/cli/index.js +90 -16
- package/src/cli/questions/layers.js +5 -2
- package/src/cli/questions/project-type.js +0 -5
- package/src/cli/questions/write.js +169 -0
- package/src/index.js +1 -0
- package/src/layers/are-the-types-wrong/index.js +74 -0
- package/src/layers/git/files/gitignore +14 -1
- package/src/layers/git/index.js +6 -5
- package/src/layers/github-actions/index.js +12 -8
- package/src/layers/index.js +1 -1
- package/src/layers/inspector-support/index.js +101 -0
- package/src/layers/prettier/files/.prettierignore +4 -0
- package/src/layers/publint/index.js +68 -0
- package/src/layers/qunit/files/tests/unit/macros-test.ts +2 -2
- package/src/layers/qunit/index.js +107 -7
- package/src/layers/qunit/library-files/config/test/babel.config.js +41 -0
- package/src/layers/qunit/library-files/config/test/testem.cjs +26 -0
- package/src/layers/qunit/library-files/tests/test-helper.ts +36 -0
- package/src/layers/qunit/library-files/tests/unit/.gitkeep +0 -0
- package/src/layers/qunit/library-files/vite.config.mjs +6 -0
- package/src/layers/typescript/index.js +43 -7
- package/src/layers/vitest/files/vitest.config.mjs +11 -11
- package/src/layers/vitest/index.js +70 -32
- package/src/utils/babel.js +9 -6
- package/src/utils/fs.js +44 -3
- package/src/utils/inspector-support.js +196 -0
- package/src/utils/npm.js +21 -7
- package/src/utils/remove-types.js +5 -0
- package/src/utils/rewrite-imports.js +157 -0
- package/src/utils/stage.js +317 -0
- package/src/utils/tsdown-config.js +85 -0
- package/src/utils/types.ts +5 -1
- package/test/ember.nvp/base-library.test.ts +232 -0
- package/test/ember.nvp/generator-replace-or-update.test.ts +2 -3
- package/test/ember.nvp/inspector-support.test.ts +179 -0
- package/test/ember.nvp/layer-inspector-support.test.ts +69 -0
- package/test/ember.nvp/layer-publish-checks.test.ts +103 -0
- package/test/ember.nvp/layer-qunit.test.ts +376 -15
- package/test/ember.nvp/layer-vitest.test.ts +250 -0
- package/test/ember.nvp/layers.test.ts +16 -0
- package/test/ember.nvp/library-src-fixtures.ts +81 -0
- package/test/ember.nvp/permutations/app-1.test.ts +3 -0
- package/test/ember.nvp/permutations/app-2.test.ts +3 -0
- package/test/ember.nvp/permutations/library-1.test.ts +3 -0
- package/test/ember.nvp/permutations/library-2.test.ts +3 -0
- package/test/ember.nvp/permutations/shared.ts +239 -0
- package/test/ember.nvp/rewrite-imports.test.ts +235 -0
- package/test/ember.nvp/stage.test.ts +188 -0
- package/test/test-helpers/permutate.test.ts +17 -0
- package/test/test-helpers.ts +20 -7
- package/tsconfig.json +1 -0
- package/packages/vite/src/maybe-babel.ts +0 -219
- package/src/layers/qunit/files/run-tests.mjs +0 -30
- package/src/layers/vitest/files/tests/test-helper.ts +0 -5
- package/test/ember.nvp/permutations.test.ts +0 -200
- /package/src/{layers/vitest/files/tests/integration/.gitkeep → bases/minimal-library/files/src/index.ts} +0 -0
- /package/src/layers/{vitest/files/tests/unit → qunit/library-files/tests/rendering}/.gitkeep +0 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { execSync } from "node:child_process";
|
|
6
|
+
|
|
7
|
+
import { Stage } from "ember.nvp";
|
|
8
|
+
import { mktemp } from "#test-helpers";
|
|
9
|
+
|
|
10
|
+
async function makeTargetProject() {
|
|
11
|
+
const target = join(await mktemp("stage-target"), "my-app");
|
|
12
|
+
|
|
13
|
+
await mkdir(join(target, "app"), { recursive: true });
|
|
14
|
+
await mkdir(join(target, "node_modules/some-dep"), { recursive: true });
|
|
15
|
+
await writeFile(join(target, "package.json"), `{ "name": "my-app" }`);
|
|
16
|
+
await writeFile(join(target, "app/app.js"), `export default class App {}`);
|
|
17
|
+
await writeFile(join(target, "tsconfig.json"), `{}`);
|
|
18
|
+
await writeFile(join(target, "node_modules/some-dep/index.js"), `module.exports = 1;`);
|
|
19
|
+
|
|
20
|
+
return target;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("Stage", () => {
|
|
24
|
+
describe("a new project (target does not exist)", () => {
|
|
25
|
+
it("stages writes without touching the target, then commits them", async () => {
|
|
26
|
+
const target = join(await mktemp("stage-new"), "my-app");
|
|
27
|
+
const stage = await Stage.create(target);
|
|
28
|
+
|
|
29
|
+
expect(stage.isNew).toBe(true);
|
|
30
|
+
|
|
31
|
+
await mkdir(join(stage.directory, "app"), { recursive: true });
|
|
32
|
+
await writeFile(join(stage.directory, "package.json"), `{ "name": "my-app" }`);
|
|
33
|
+
await writeFile(join(stage.directory, "app/app.js"), `export default class App {}`);
|
|
34
|
+
|
|
35
|
+
expect(existsSync(target), "target is untouched while staged").toBe(false);
|
|
36
|
+
|
|
37
|
+
const changes = await stage.changes();
|
|
38
|
+
|
|
39
|
+
expect(changes).toEqual([
|
|
40
|
+
{ path: "app/app.js", status: "added" },
|
|
41
|
+
{ path: "package.json", status: "added" },
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
await stage.commit();
|
|
45
|
+
|
|
46
|
+
expect(await readFile(join(target, "package.json"), "utf-8")).toBe(`{ "name": "my-app" }`);
|
|
47
|
+
expect(existsSync(join(target, "app/app.js"))).toBe(true);
|
|
48
|
+
expect(existsSync(stage.directory), "stage is cleaned up after commit").toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("carries a git repo initialized in the stage over to the target", async () => {
|
|
52
|
+
const target = join(await mktemp("stage-git"), "my-app");
|
|
53
|
+
const stage = await Stage.create(target);
|
|
54
|
+
|
|
55
|
+
await writeFile(join(stage.directory, "readme.md"), `hi`);
|
|
56
|
+
execSync("git init --initial-branch=main", { cwd: stage.directory, stdio: "pipe" });
|
|
57
|
+
|
|
58
|
+
await stage.commit();
|
|
59
|
+
|
|
60
|
+
expect(existsSync(join(target, ".git"))).toBe(true);
|
|
61
|
+
expect(existsSync(join(target, "readme.md"))).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("an existing project (seeded stage)", () => {
|
|
66
|
+
it("seeds the target's files, excluding node_modules and .git", async () => {
|
|
67
|
+
const target = await makeTargetProject();
|
|
68
|
+
execSync("git init --initial-branch=main", { cwd: target, stdio: "pipe" });
|
|
69
|
+
|
|
70
|
+
const stage = await Stage.create(target);
|
|
71
|
+
|
|
72
|
+
expect(stage.isNew).toBe(false);
|
|
73
|
+
expect(existsSync(join(stage.directory, "package.json"))).toBe(true);
|
|
74
|
+
expect(existsSync(join(stage.directory, "app/app.js"))).toBe(true);
|
|
75
|
+
expect(existsSync(join(stage.directory, "node_modules"))).toBe(false);
|
|
76
|
+
expect(existsSync(join(stage.directory, ".git"))).toBe(false);
|
|
77
|
+
|
|
78
|
+
await stage.discard();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("detects added, modified, and deleted files", async () => {
|
|
82
|
+
const target = await makeTargetProject();
|
|
83
|
+
const stage = await Stage.create(target);
|
|
84
|
+
|
|
85
|
+
await writeFile(join(stage.directory, ".prettierrc.js"), `export default {};`);
|
|
86
|
+
await writeFile(join(stage.directory, "package.json"), `{ "name": "renamed" }`);
|
|
87
|
+
await rm(join(stage.directory, "tsconfig.json"));
|
|
88
|
+
|
|
89
|
+
const changes = await stage.changes();
|
|
90
|
+
|
|
91
|
+
expect(changes).toEqual([
|
|
92
|
+
{ path: ".prettierrc.js", status: "added" },
|
|
93
|
+
{ path: "package.json", status: "modified" },
|
|
94
|
+
{ path: "tsconfig.json", status: "deleted" },
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
await stage.discard();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("commit only touches changed paths, preserving node_modules and unrelated files", async () => {
|
|
101
|
+
const target = await makeTargetProject();
|
|
102
|
+
const stage = await Stage.create(target);
|
|
103
|
+
|
|
104
|
+
await writeFile(join(stage.directory, "package.json"), `{ "name": "renamed" }`);
|
|
105
|
+
await rm(join(stage.directory, "tsconfig.json"));
|
|
106
|
+
|
|
107
|
+
await stage.commit();
|
|
108
|
+
|
|
109
|
+
expect(await readFile(join(target, "package.json"), "utf-8")).toBe(`{ "name": "renamed" }`);
|
|
110
|
+
expect(
|
|
111
|
+
existsSync(join(target, "tsconfig.json")),
|
|
112
|
+
"deleted in stage -> deleted in target",
|
|
113
|
+
).toBe(false);
|
|
114
|
+
expect(existsSync(join(target, "app/app.js")), "unchanged files are untouched").toBe(true);
|
|
115
|
+
expect(
|
|
116
|
+
existsSync(join(target, "node_modules/some-dep/index.js")),
|
|
117
|
+
"node_modules survives commit",
|
|
118
|
+
).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("commit applies only the given subset of changes", async () => {
|
|
122
|
+
const target = await makeTargetProject();
|
|
123
|
+
const stage = await Stage.create(target);
|
|
124
|
+
|
|
125
|
+
await writeFile(join(stage.directory, ".prettierrc.js"), `export default {};`);
|
|
126
|
+
await writeFile(join(stage.directory, "package.json"), `{ "name": "renamed" }`);
|
|
127
|
+
await rm(join(stage.directory, "tsconfig.json"));
|
|
128
|
+
|
|
129
|
+
const changes = await stage.changes();
|
|
130
|
+
const accepted = changes.filter((change) => change.path !== "package.json");
|
|
131
|
+
|
|
132
|
+
await stage.commit(accepted);
|
|
133
|
+
|
|
134
|
+
expect(existsSync(join(target, ".prettierrc.js")), "accepted addition is written").toBe(true);
|
|
135
|
+
expect(existsSync(join(target, "tsconfig.json")), "accepted deletion is applied").toBe(false);
|
|
136
|
+
expect(
|
|
137
|
+
await readFile(join(target, "package.json"), "utf-8"),
|
|
138
|
+
"rejected change is not applied",
|
|
139
|
+
).toBe(`{ "name": "my-app" }`);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("discard leaves the target exactly as it was", async () => {
|
|
143
|
+
const target = await makeTargetProject();
|
|
144
|
+
const stage = await Stage.create(target);
|
|
145
|
+
|
|
146
|
+
await writeFile(join(stage.directory, "package.json"), `{ "name": "renamed" }`);
|
|
147
|
+
|
|
148
|
+
await stage.discard();
|
|
149
|
+
|
|
150
|
+
expect(await readFile(join(target, "package.json"), "utf-8")).toBe(`{ "name": "my-app" }`);
|
|
151
|
+
expect(existsSync(stage.directory)).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("reports no changes when nothing was modified", async () => {
|
|
155
|
+
const target = await makeTargetProject();
|
|
156
|
+
const stage = await Stage.create(target);
|
|
157
|
+
|
|
158
|
+
expect(await stage.changes()).toEqual([]);
|
|
159
|
+
|
|
160
|
+
await stage.discard();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe("diff", () => {
|
|
165
|
+
it("renders a unified diff for added, modified, and deleted files", async () => {
|
|
166
|
+
const target = await makeTargetProject();
|
|
167
|
+
const stage = await Stage.create(target);
|
|
168
|
+
|
|
169
|
+
await writeFile(join(stage.directory, ".prettierrc.js"), `export default {};`);
|
|
170
|
+
await writeFile(join(stage.directory, "package.json"), `{ "name": "renamed" }`);
|
|
171
|
+
await rm(join(stage.directory, "tsconfig.json"));
|
|
172
|
+
|
|
173
|
+
const diff = await stage.diff();
|
|
174
|
+
|
|
175
|
+
expect(diff).toContain(`+++ b/.prettierrc.js`);
|
|
176
|
+
expect(diff).toContain(`+export default {};`);
|
|
177
|
+
|
|
178
|
+
expect(diff).toContain(`--- a/package.json`);
|
|
179
|
+
expect(diff).toContain(`-{ "name": "my-app" }`);
|
|
180
|
+
expect(diff).toContain(`+{ "name": "renamed" }`);
|
|
181
|
+
|
|
182
|
+
expect(diff).toContain(`--- a/tsconfig.json`);
|
|
183
|
+
expect(diff).toContain(`+++ /dev/null`);
|
|
184
|
+
|
|
185
|
+
await stage.discard();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -51,6 +51,23 @@ describe("permutate", () => {
|
|
|
51
51
|
expect(hasOneEslint).toBe(true);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
+
it("enforces mutual exclusivity for testing layers", () => {
|
|
55
|
+
const result = permutate(["qunit", "vitest", "other"]);
|
|
56
|
+
|
|
57
|
+
for (const permutation of result) {
|
|
58
|
+
const testingCount = permutation.filter(
|
|
59
|
+
(item) => item === "qunit" || item === "vitest",
|
|
60
|
+
).length;
|
|
61
|
+
expect(testingCount).toBeLessThanOrEqual(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const hasQunit = result.some((perm) => perm.includes("qunit"));
|
|
65
|
+
const hasVitest = result.some((perm) => perm.includes("vitest"));
|
|
66
|
+
|
|
67
|
+
expect(hasQunit).toBe(true);
|
|
68
|
+
expect(hasVitest).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
54
71
|
it("generates valid permutations with mixed items", () => {
|
|
55
72
|
const result = permutate(["a", "eslint-foo", "eslint-bar", "b"]);
|
|
56
73
|
|
package/test/test-helpers.ts
CHANGED
|
@@ -16,10 +16,22 @@ export const bases = [minimalApp, minimalAddon];
|
|
|
16
16
|
|
|
17
17
|
export const layers = await discoverLayers();
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Layers in the same group are alternatives to each other (one eslint
|
|
21
|
+
* config, one test framework): selecting two of them would produce a
|
|
22
|
+
* broken project, so permutations never combine them.
|
|
23
|
+
*/
|
|
24
|
+
function exclusivityGroup(name: string): string | undefined {
|
|
25
|
+
if (name.startsWith("eslint-")) return "eslint";
|
|
26
|
+
if (name === "qunit" || name === "vitest") return "testing";
|
|
27
|
+
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
export function permutate(toPermutate: string[]): string[][] {
|
|
20
32
|
const out: string[][] = [];
|
|
21
33
|
|
|
22
|
-
function backtrack(startIndex: number, prefix: string[],
|
|
34
|
+
function backtrack(startIndex: number, prefix: string[], usedGroups: Set<string>) {
|
|
23
35
|
if (prefix.length > 0) out.push(prefix.slice());
|
|
24
36
|
|
|
25
37
|
for (let i = startIndex; i < toPermutate.length; i++) {
|
|
@@ -34,19 +46,20 @@ export function permutate(toPermutate: string[]): string[][] {
|
|
|
34
46
|
// (silly TS not understanding loop bounds)
|
|
35
47
|
if (!option) continue;
|
|
36
48
|
|
|
37
|
-
const
|
|
49
|
+
const group = exclusivityGroup(option);
|
|
38
50
|
|
|
39
|
-
// Skip this option if
|
|
40
|
-
|
|
41
|
-
if (isEslint && hasEslint) continue;
|
|
51
|
+
// Skip this option if we already have one from its exclusivity group
|
|
52
|
+
if (group && usedGroups.has(group)) continue;
|
|
42
53
|
|
|
54
|
+
if (group) usedGroups.add(group);
|
|
43
55
|
prefix.push(option);
|
|
44
|
-
backtrack(i + 1, prefix,
|
|
56
|
+
backtrack(i + 1, prefix, usedGroups);
|
|
45
57
|
prefix.pop();
|
|
58
|
+
if (group) usedGroups.delete(group);
|
|
46
59
|
}
|
|
47
60
|
}
|
|
48
61
|
|
|
49
|
-
backtrack(0, [],
|
|
62
|
+
backtrack(0, [], new Set());
|
|
50
63
|
return out;
|
|
51
64
|
}
|
|
52
65
|
|
package/tsconfig.json
CHANGED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reasons we have to have babel
|
|
3
|
-
* - decorators
|
|
4
|
-
* - ember-concurrency
|
|
5
|
-
* - scoped-css
|
|
6
|
-
* - template compilation optimization
|
|
7
|
-
*/
|
|
8
|
-
import { extensions } from "@embroider/vite";
|
|
9
|
-
import { babel } from "@rollup/plugin-babel";
|
|
10
|
-
import { join, resolve } from "node:path";
|
|
11
|
-
import { parse as oxcParse } from "oxc-parser";
|
|
12
|
-
import { transform } from "oxc-transform";
|
|
13
|
-
import { walk } from "zimmerframe";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* if a file imports any of these, it must be optimize
|
|
17
|
-
*/
|
|
18
|
-
const babelTemplateImports = new Set([
|
|
19
|
-
// Templates
|
|
20
|
-
"@ember/template-compiler",
|
|
21
|
-
"@ember/template-compilation",
|
|
22
|
-
"ember-cli-htmlbars",
|
|
23
|
-
"ember-cli-htmlbars-inline-precompile",
|
|
24
|
-
"htmlbars-inline-precompile",
|
|
25
|
-
]);
|
|
26
|
-
|
|
27
|
-
const babelMacroImports = new Set([
|
|
28
|
-
// Macros
|
|
29
|
-
"@embroider/macros",
|
|
30
|
-
"@glimmer/env",
|
|
31
|
-
"@ember/application/deprecations",
|
|
32
|
-
// Macros only needed in prod
|
|
33
|
-
"@ember/debug",
|
|
34
|
-
]); // Babel plugins required from libraries
|
|
35
|
-
const babelOtherImports = new Set([
|
|
36
|
-
"ember-concurrency",
|
|
37
|
-
"ember-scoped-css",
|
|
38
|
-
"ember-intl/helpers/format-message",
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const babelRequiredImports = [...babelTemplateImports, ...babelMacroImports, ...babelOtherImports];
|
|
42
|
-
|
|
43
|
-
const counts = {
|
|
44
|
-
total: 0,
|
|
45
|
-
babel: 0,
|
|
46
|
-
why: {
|
|
47
|
-
decorators: 0,
|
|
48
|
-
formatMessage: 0,
|
|
49
|
-
imports: {
|
|
50
|
-
templates: 0,
|
|
51
|
-
macros: 0,
|
|
52
|
-
other: 0,
|
|
53
|
-
},
|
|
54
|
-
initializeRuntimeMacrosConfig: 0,
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
export function maybeBabel(options: { parallel?: boolean; configFile: string; env: any }) {
|
|
58
|
-
const { env, parallel, ...restOptions } = options;
|
|
59
|
-
const original = (() => {
|
|
60
|
-
const babelPath = resolve(join(process.cwd(), "./babel.config.js"));
|
|
61
|
-
|
|
62
|
-
return babel({
|
|
63
|
-
babelHelpers: "runtime",
|
|
64
|
-
extensions,
|
|
65
|
-
skipPreflightCheck: true,
|
|
66
|
-
...restOptions,
|
|
67
|
-
configFile: babelPath,
|
|
68
|
-
parallel: parallel ?? true,
|
|
69
|
-
});
|
|
70
|
-
})();
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* In @rollup/plugin-babel v7+, the `transform` hook is the object form
|
|
74
|
-
* `{ filter, handler }` rather than a plain function. Normalize to the
|
|
75
|
-
* underlying handler so we can invoke it directly.
|
|
76
|
-
*/
|
|
77
|
-
const originalTransform = (
|
|
78
|
-
typeof original.transform === "function" ? original.transform : original.transform?.handler
|
|
79
|
-
)!;
|
|
80
|
-
|
|
81
|
-
const babelMacros = new Set(babelRequiredImports);
|
|
82
|
-
if (env.mode === "development") {
|
|
83
|
-
babelMacros.delete("@ember/debug");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async function doTransform(this: any, code: string, id: string) {
|
|
87
|
-
counts.total++;
|
|
88
|
-
|
|
89
|
-
const ext = id.split(".").at(-1);
|
|
90
|
-
const lang = (ext === "gjs" ? "js" : ext === "gts" ? "ts" : ext) as
|
|
91
|
-
| "js"
|
|
92
|
-
| "ts"
|
|
93
|
-
| "jsx"
|
|
94
|
-
| "tsx"
|
|
95
|
-
| "dts"
|
|
96
|
-
| undefined;
|
|
97
|
-
|
|
98
|
-
let needsBabel = false;
|
|
99
|
-
|
|
100
|
-
const estree = await oxcParse(id, code, { lang });
|
|
101
|
-
|
|
102
|
-
walk(
|
|
103
|
-
estree.program as any,
|
|
104
|
-
/* state */ {},
|
|
105
|
-
{
|
|
106
|
-
Decorator(_node: any, { stop }: any) {
|
|
107
|
-
needsBabel = true;
|
|
108
|
-
counts.why.decorators++;
|
|
109
|
-
stop();
|
|
110
|
-
},
|
|
111
|
-
MemberExpression(node: any, { stop }: any) {
|
|
112
|
-
if (node.property?.name === "formatMessage" && node.object?.name === "intl") {
|
|
113
|
-
needsBabel = true;
|
|
114
|
-
counts.why.formatMessage++;
|
|
115
|
-
stop();
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
ImportDeclaration(node: any, { stop }: any) {
|
|
119
|
-
const value = node.source.value;
|
|
120
|
-
if (babelMacros.has(value)) {
|
|
121
|
-
needsBabel = true;
|
|
122
|
-
|
|
123
|
-
if (babelTemplateImports.has(value)) {
|
|
124
|
-
counts.why.imports.templates++;
|
|
125
|
-
} else if (babelMacroImports.has(value)) {
|
|
126
|
-
counts.why.imports.macros++;
|
|
127
|
-
} else {
|
|
128
|
-
counts.why.imports.other++;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
stop();
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
if (!needsBabel && code.includes("initializeRuntimeMacrosConfig")) {
|
|
138
|
-
counts.why.initializeRuntimeMacrosConfig++;
|
|
139
|
-
needsBabel = true;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (needsBabel) {
|
|
143
|
-
counts.babel++;
|
|
144
|
-
|
|
145
|
-
const result = await originalTransform.call(this, code, id);
|
|
146
|
-
|
|
147
|
-
return result;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (ext === "json") {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (ext === "js" || ext === "gjs") {
|
|
155
|
-
// We don't need to process JS
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const result = await transform(id, code, {
|
|
160
|
-
lang,
|
|
161
|
-
typescript: {
|
|
162
|
-
onlyRemoveTypeImports: true,
|
|
163
|
-
/**
|
|
164
|
-
* We should work towards disabling this.
|
|
165
|
-
*/
|
|
166
|
-
allowNamespaces: true,
|
|
167
|
-
removeClassFieldsWithoutInitializer: false,
|
|
168
|
-
rewriteImportExtensions: false,
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
if (result.errors?.length) {
|
|
173
|
-
console.error(`Errors during oxc-transform of ${id}:`);
|
|
174
|
-
for (const err of result.errors) {
|
|
175
|
-
if (err.labels) {
|
|
176
|
-
console.error(err.labels);
|
|
177
|
-
}
|
|
178
|
-
console.error(err.codeframe || err.message);
|
|
179
|
-
}
|
|
180
|
-
throw result.errors;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return result;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
enforce: "pre",
|
|
188
|
-
buildEnd() {
|
|
189
|
-
if (process.env.INSPECT) {
|
|
190
|
-
console.debug(`Babel usage: ${counts.babel} / ${counts.total}`, counts.why);
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
...original,
|
|
194
|
-
name: "nullvoxpopuli:babel",
|
|
195
|
-
transform: {
|
|
196
|
-
filter: {
|
|
197
|
-
id: {
|
|
198
|
-
include: [/\.js/, /\.gjs/, /\.ts/, /\.gts/],
|
|
199
|
-
exclude: [/\.json/],
|
|
200
|
-
},
|
|
201
|
-
// Enabling this opts us out of template compilation
|
|
202
|
-
// it's an AND instead of OR
|
|
203
|
-
// code: {
|
|
204
|
-
// include: [/initializeRuntimeMacrosConfig/, /precompileTemplate/],
|
|
205
|
-
// },
|
|
206
|
-
},
|
|
207
|
-
handler(this: any, code: string, id: string) {
|
|
208
|
-
try {
|
|
209
|
-
return doTransform.call(this, code, id);
|
|
210
|
-
} catch (e) {
|
|
211
|
-
// Use VSCode JavaScript Debug Terminal
|
|
212
|
-
// eslint-disable-next-line no-debugger
|
|
213
|
-
debugger;
|
|
214
|
-
throw e;
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { chromium } from "playwright";
|
|
2
|
-
|
|
3
|
-
const browser = await chromium.launch();
|
|
4
|
-
const page = await browser.newPage();
|
|
5
|
-
|
|
6
|
-
page.on("console", (msg) => console.log(msg.text()));
|
|
7
|
-
|
|
8
|
-
await page.goto("http://localhost:4173/tests");
|
|
9
|
-
|
|
10
|
-
await page.waitForFunction(
|
|
11
|
-
() => {
|
|
12
|
-
const elem = document.getElementById("qunit-testresult");
|
|
13
|
-
return elem?.classList.contains("complete");
|
|
14
|
-
},
|
|
15
|
-
{ timeout: 30000 },
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const failed = await page.evaluate(() => {
|
|
19
|
-
const elem = document.getElementById("qunit-testresult");
|
|
20
|
-
return elem?.querySelector(".failed")?.textContent;
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
await browser.close();
|
|
24
|
-
|
|
25
|
-
if (failed && parseInt(failed) > 0) {
|
|
26
|
-
console.error(`❌ ${failed} test(s) failed`);
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
console.log("✅ All tests passed!");
|