ember.nvp 1.9.0 → 1.11.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/.release-plan.json +4 -4
- package/CHANGELOG.md +31 -0
- package/README.md +65 -4
- package/package.json +2 -1
- package/packages/rolldown/package.json +6 -2
- package/packages/rolldown/src/dts.test.ts +105 -1
- package/packages/rolldown/src/isolated-declarations.ts +67 -61
- package/packages/rolldown/src/transform.test.ts +212 -15
- package/packages/rolldown/src/transform.ts +106 -26
- package/src/cli/args.js +105 -15
- package/src/cli/generator.js +2 -1
- package/src/cli/help.js +76 -16
- package/src/cli/index.js +15 -0
- package/src/cli/questions/layer-options.js +130 -0
- package/src/cli/questions/validate-option.js +106 -0
- package/src/layers/eslint-bundled/app.test.ts +182 -0
- package/src/layers/eslint-bundled/index.js +172 -0
- package/src/layers/expect-type/index.js +11 -1
- package/src/layers/github-actions/app.test.ts +1 -1
- package/src/layers/typescript/app.test.ts +6 -0
- package/src/layers/typescript/index.js +48 -148
- package/src/layers/typescript/typescript-6.js +102 -0
- package/src/layers/typescript/typescript-7.js +177 -0
- package/src/utils/manifest.js +13 -0
- package/src/utils/npm.js +27 -0
- package/src/utils/project.js +23 -0
- package/src/utils/types.ts +52 -1
- package/src/utils/typescript.js +147 -0
- package/test/ember.nvp/base-library.test.ts +11 -0
- package/test/ember.nvp/cli.test.ts +90 -3
- package/test/ember.nvp/layer-options.test.ts +249 -0
- package/test/ember.nvp/layer-readme.test.ts +4 -2
- package/test/ember.nvp/layer-typescript.test.ts +302 -0
- package/test/ember.nvp/layers.test.ts +1 -2
- package/test/ember.nvp/permutations/shared.ts +3 -4
- package/test/ember.nvp/validate-option.test.ts +152 -0
- package/test/test-helpers/permutate.test.ts +2 -7
- package/test/test-helpers.ts +8 -1
- package/src/layers/eslint-bundled-ember/index.js +0 -91
- package/src/layers/eslint-bundled-nvp/app.test.ts +0 -91
- package/src/layers/eslint-bundled-nvp/index.js +0 -91
- /package/src/layers/{eslint-bundled-ember/files → eslint-bundled/files/ember}/eslint.config.js +0 -0
- /package/src/layers/{eslint-bundled-nvp/files → eslint-bundled/files/nvp}/eslint.config.js +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { validateOption } from "../../src/cli/questions/validate-option.js";
|
|
3
|
+
import type { LayerOptionSchema } from "../../src/utils/types.js";
|
|
4
|
+
|
|
5
|
+
describe("validateOption", () => {
|
|
6
|
+
describe("number validation", () => {
|
|
7
|
+
const schema: LayerOptionSchema = {
|
|
8
|
+
type: "number",
|
|
9
|
+
prompt: "Enter number",
|
|
10
|
+
default: 10,
|
|
11
|
+
validate: (val: number) => (val > 0 ? undefined : "Must be greater than 0"),
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
it("validates valid numbers", () => {
|
|
15
|
+
expect(validateOption(schema, 5)).toEqual({ ok: true, value: 5 });
|
|
16
|
+
expect(validateOption(schema, "42")).toEqual({ ok: true, value: 42 });
|
|
17
|
+
expect(validateOption(schema, " 2.5 ")).toEqual({ ok: true, value: 2.5 });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it.each(["", "abc", "0x10", "1e3"])("fails on '%s'", (input) => {
|
|
21
|
+
expect(validateOption(schema, input)).toEqual({
|
|
22
|
+
ok: false,
|
|
23
|
+
error: `'${input}' is not a number`,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("fails custom validate function", () => {
|
|
28
|
+
expect(validateOption(schema, -5)).toEqual({ ok: false, error: "Must be greater than 0" });
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("text validation", () => {
|
|
33
|
+
const schema: LayerOptionSchema = {
|
|
34
|
+
type: "text",
|
|
35
|
+
prompt: "Enter text",
|
|
36
|
+
default: "default-title",
|
|
37
|
+
validate: (val: string) => (val.length >= 3 ? undefined : "Minimum 3 chars"),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
it("validates valid text", () => {
|
|
41
|
+
expect(validateOption(schema, "hello")).toEqual({ ok: true, value: "hello" });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("fails custom validate function", () => {
|
|
45
|
+
expect(validateOption(schema, "hi")).toEqual({ ok: false, error: "Minimum 3 chars" });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("fails with the message of an Error", () => {
|
|
49
|
+
const strict: LayerOptionSchema = { ...schema, validate: () => new Error("Nope") };
|
|
50
|
+
|
|
51
|
+
expect(validateOption(strict, "hello")).toEqual({ ok: false, error: "Nope" });
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("confirm validation", () => {
|
|
56
|
+
const schema: LayerOptionSchema = {
|
|
57
|
+
type: "confirm",
|
|
58
|
+
prompt: "Confirm action",
|
|
59
|
+
default: true,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
it("validates booleans", () => {
|
|
63
|
+
expect(validateOption(schema, true)).toEqual({ ok: true, value: true });
|
|
64
|
+
expect(validateOption(schema, false)).toEqual({ ok: true, value: false });
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("fails on strings", () => {
|
|
68
|
+
expect(validateOption(schema, "yes")).toEqual({
|
|
69
|
+
ok: false,
|
|
70
|
+
error: "'yes' is not true or false",
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("select validation", () => {
|
|
76
|
+
const schema: LayerOptionSchema = {
|
|
77
|
+
type: "select",
|
|
78
|
+
prompt: "Select option",
|
|
79
|
+
default: "standard",
|
|
80
|
+
options: [
|
|
81
|
+
{ label: "Standard", value: "standard" },
|
|
82
|
+
{ label: "Deluxe", value: "deluxe" },
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
it("validates valid option choice", () => {
|
|
87
|
+
expect(validateOption(schema, "deluxe")).toEqual({ ok: true, value: "deluxe" });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("fails unlisted choice", () => {
|
|
91
|
+
expect(validateOption(schema, "ultra")).toEqual({
|
|
92
|
+
ok: false,
|
|
93
|
+
error: "Invalid option 'ultra'. Must be one of: standard, deluxe",
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("multiselect validation", () => {
|
|
99
|
+
const schema: LayerOptionSchema = {
|
|
100
|
+
type: "multiselect",
|
|
101
|
+
prompt: "Select options",
|
|
102
|
+
options: [
|
|
103
|
+
{ label: "A", value: "a" },
|
|
104
|
+
{ label: "B", value: "b" },
|
|
105
|
+
],
|
|
106
|
+
validate: (val: string[]) => (val.length > 0 ? undefined : "Select at least one"),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
it("validates listed choices", () => {
|
|
110
|
+
expect(validateOption(schema, ["a", "b"])).toEqual({ ok: true, value: ["a", "b"] });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("fails unlisted choice", () => {
|
|
114
|
+
expect(validateOption(schema, ["a", "c"])).toEqual({
|
|
115
|
+
ok: false,
|
|
116
|
+
error: "Invalid option 'c'. Must be one of: a, b",
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("fails custom validate function", () => {
|
|
121
|
+
expect(validateOption(schema, [])).toEqual({ ok: false, error: "Select at least one" });
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("Standard Schema validation", () => {
|
|
126
|
+
// A hand-written schema, so the test needs no schema library
|
|
127
|
+
const positive = {
|
|
128
|
+
"~standard": {
|
|
129
|
+
version: 1 as const,
|
|
130
|
+
vendor: "test",
|
|
131
|
+
validate: (value: unknown) =>
|
|
132
|
+
typeof value === "number" && value > 0
|
|
133
|
+
? { value }
|
|
134
|
+
: { issues: [{ message: "Must be positive" }] },
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const schema: LayerOptionSchema = {
|
|
139
|
+
type: "number",
|
|
140
|
+
prompt: "Enter number",
|
|
141
|
+
validate: positive,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
it("passes values the schema accepts", () => {
|
|
145
|
+
expect(validateOption(schema, "3")).toEqual({ ok: true, value: 3 });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("fails with the schema's first issue", () => {
|
|
149
|
+
expect(validateOption(schema, "-3")).toEqual({ ok: false, error: "Must be positive" });
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -25,12 +25,7 @@ describe("permutate", () => {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it("enforces mutual exclusivity for eslint-prefixed entries", () => {
|
|
28
|
-
const result = permutate([
|
|
29
|
-
"eslint-bundled-ember",
|
|
30
|
-
"eslint-bundled-nvp",
|
|
31
|
-
"eslint-ejected",
|
|
32
|
-
"other",
|
|
33
|
-
]);
|
|
28
|
+
const result = permutate(["eslint-bundled", "eslint-ejected", "other"]);
|
|
34
29
|
|
|
35
30
|
// Check that no permutation has more than one eslint-prefixed entry
|
|
36
31
|
for (const permutation of result) {
|
|
@@ -40,7 +35,7 @@ describe("permutate", () => {
|
|
|
40
35
|
});
|
|
41
36
|
|
|
42
37
|
it("allows permutations with 0 or 1 eslint entry", () => {
|
|
43
|
-
const result = permutate(["eslint-bundled
|
|
38
|
+
const result = permutate(["eslint-bundled", "eslint-ejected", "other"]);
|
|
44
39
|
|
|
45
40
|
const hasNoEslint = result.some((perm) => !perm.some((item) => item.startsWith("eslint-")));
|
|
46
41
|
const hasOneEslint = result.some(
|
package/test/test-helpers.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { mkdtemp, readdir } from "node:fs/promises";
|
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { generateProject, Project } from "ember.nvp";
|
|
8
8
|
import { discoverLayers } from "#layers";
|
|
9
|
-
import type { DiscoveredLayer, ProjectType } from "#types";
|
|
9
|
+
import type { Answers, DiscoveredLayer, ProjectType } from "#types";
|
|
10
10
|
import { expect } from "vitest";
|
|
11
11
|
|
|
12
12
|
const minimalApp = "minimal-app";
|
|
@@ -78,6 +78,7 @@ export async function reapply(project: Project, layers: string[]) {
|
|
|
78
78
|
name: project.name,
|
|
79
79
|
type: project.type,
|
|
80
80
|
packageManager: project.packageManager,
|
|
81
|
+
options: project.desires.options,
|
|
81
82
|
});
|
|
82
83
|
}
|
|
83
84
|
|
|
@@ -87,12 +88,17 @@ export async function generate({
|
|
|
87
88
|
type = "app",
|
|
88
89
|
packageManager = "pnpm",
|
|
89
90
|
directory,
|
|
91
|
+
options,
|
|
90
92
|
}: {
|
|
91
93
|
directory?: string;
|
|
92
94
|
layers?: string[];
|
|
93
95
|
name?: string;
|
|
94
96
|
type?: ProjectType;
|
|
95
97
|
packageManager?: "pnpm" | "npm";
|
|
98
|
+
/**
|
|
99
|
+
* Layer options, keyed by layer name
|
|
100
|
+
*/
|
|
101
|
+
options?: Answers["options"];
|
|
96
102
|
}): Promise<Project> {
|
|
97
103
|
const tempDir = directory ?? (await mktemp(name));
|
|
98
104
|
|
|
@@ -103,6 +109,7 @@ export async function generate({
|
|
|
103
109
|
path: tempDir,
|
|
104
110
|
layers: selectedLayers,
|
|
105
111
|
packageManager,
|
|
112
|
+
options,
|
|
106
113
|
});
|
|
107
114
|
|
|
108
115
|
await generateProject(project);
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { getLatest } from "#utils/npm.js";
|
|
2
|
-
import { files, packageJson } from "ember-apply";
|
|
3
|
-
import { formatLabel } from "#utils/cli.js";
|
|
4
|
-
import { maybeLintWithConcurrently } from "#consolidators/linting.js";
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
import { join } from "node:path";
|
|
7
|
-
import { hasDevDeps } from "#utils/manifest.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @type {import('#types').Layer}
|
|
11
|
-
*/
|
|
12
|
-
export default {
|
|
13
|
-
label: formatLabel("ESLint", "ember's encapsulated config"),
|
|
14
|
-
hint: `Minimal dependencies added to package.json. Not official, but follows the official configuration`,
|
|
15
|
-
|
|
16
|
-
async run(project) {
|
|
17
|
-
await files.applyFolder(join(import.meta.dirname, "files"), project.directory);
|
|
18
|
-
|
|
19
|
-
await packageJson.addDevDependencies(
|
|
20
|
-
await getLatest({
|
|
21
|
-
"ember-eslint": "^1.0.0",
|
|
22
|
-
eslint: "^10.9.1",
|
|
23
|
-
}),
|
|
24
|
-
project.directory,
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
await packageJson.addScripts(
|
|
28
|
-
{
|
|
29
|
-
"lint:eslint": "eslint . --cache",
|
|
30
|
-
"lint:eslint:fix": "eslint . --fix",
|
|
31
|
-
},
|
|
32
|
-
project.directory,
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
await maybeLintWithConcurrently(project);
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @overload
|
|
40
|
-
* @param {import('#utils/project.js').Project} project
|
|
41
|
-
* @param {true} explain
|
|
42
|
-
* @returns {Promise<{ isSetup: boolean; reasons: string[] }>}
|
|
43
|
-
*/
|
|
44
|
-
/**
|
|
45
|
-
* @overload
|
|
46
|
-
* @param {import('#utils/project.js').Project} project
|
|
47
|
-
* @param {boolean | undefined} [explain]
|
|
48
|
-
* @returns {Promise<boolean>}
|
|
49
|
-
*/
|
|
50
|
-
async isSetup(project, explain) {
|
|
51
|
-
const reasons = [];
|
|
52
|
-
|
|
53
|
-
if (!existsSync(join(project.directory, "eslint.config.js"))) {
|
|
54
|
-
reasons.push("eslint.config.js is missing");
|
|
55
|
-
|
|
56
|
-
if (!explain) return false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let manifest = await packageJson.read(project.directory);
|
|
60
|
-
|
|
61
|
-
if (!hasDevDeps(manifest, ["ember-eslint", "eslint"])) {
|
|
62
|
-
reasons.push("missing required dependencies: ember-eslint, eslint");
|
|
63
|
-
|
|
64
|
-
if (!explain) return false;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let scripts = Object.values(manifest.scripts ?? {}).filter((script) =>
|
|
68
|
-
script.includes("eslint"),
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
if (!scripts.some((script) => script.includes("--cache"))) {
|
|
72
|
-
reasons.push("missing eslint script with --cache flag");
|
|
73
|
-
|
|
74
|
-
if (!explain) return false;
|
|
75
|
-
}
|
|
76
|
-
if (!scripts.some((script) => script.includes("--fix"))) {
|
|
77
|
-
reasons.push("missing eslint script with --fix flag");
|
|
78
|
-
|
|
79
|
-
if (!explain) return false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (explain) {
|
|
83
|
-
return {
|
|
84
|
-
isSetup: reasons.length === 0,
|
|
85
|
-
reasons,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return reasons.length === 0;
|
|
90
|
-
},
|
|
91
|
-
};
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { beforeAll, describe, it, expect as hardExpect, afterAll } from "vitest";
|
|
2
|
-
import { expectIsSetup, generate, layers, reapply } from "#test-helpers";
|
|
3
|
-
|
|
4
|
-
import type { Project } from "ember.nvp";
|
|
5
|
-
import { rm } from "node:fs/promises";
|
|
6
|
-
|
|
7
|
-
const expect = hardExpect.soft;
|
|
8
|
-
|
|
9
|
-
let layer = layers.find((layer) => layer.name === "eslint-bundled-nvp")!;
|
|
10
|
-
|
|
11
|
-
describe("starting without eslint-bundled-nvp", () => {
|
|
12
|
-
let project: Project;
|
|
13
|
-
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
project = await generate({
|
|
16
|
-
type: "app",
|
|
17
|
-
packageManager: "pnpm",
|
|
18
|
-
layers: ["git"],
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterAll(async () => {
|
|
23
|
-
await rm(project.directory, { recursive: true, force: true });
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("applying eslint-bundled-nvp", async () => {
|
|
27
|
-
await reapply(project, ["eslint-bundled-nvp"]);
|
|
28
|
-
|
|
29
|
-
await expectIsSetup(project, layer);
|
|
30
|
-
expect(await project.gitHasDiff()).toBe(false);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe("starting with eslint-bundled-nvp", () => {
|
|
35
|
-
let project: Project;
|
|
36
|
-
|
|
37
|
-
beforeAll(async () => {
|
|
38
|
-
project = await generate({
|
|
39
|
-
type: "app",
|
|
40
|
-
packageManager: "pnpm",
|
|
41
|
-
layers: ["eslint-bundled-nvp", "git"],
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
afterAll(async () => {
|
|
46
|
-
await rm(project.directory, { recursive: true, force: true });
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("reapplying eslint-bundled-nvp causes no changes", async () => {
|
|
50
|
-
await reapply(project, ["eslint-bundled-nvp"]);
|
|
51
|
-
|
|
52
|
-
await expectIsSetup(project, layer);
|
|
53
|
-
expect(await project.gitHasDiff()).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
describe("package.json scripts", () => {
|
|
58
|
-
let project: Project;
|
|
59
|
-
|
|
60
|
-
beforeAll(async () => {
|
|
61
|
-
project = await generate({
|
|
62
|
-
type: "app",
|
|
63
|
-
packageManager: "pnpm",
|
|
64
|
-
layers: ["eslint-bundled-nvp", "git"],
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
let { exitCode } = await project.run("pnpm install");
|
|
68
|
-
|
|
69
|
-
hardExpect(exitCode).toBe(0);
|
|
70
|
-
|
|
71
|
-
await expectIsSetup(project, layer);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
afterAll(async () => {
|
|
75
|
-
await rm(project.directory, { recursive: true, force: true });
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("linting and fixing works", async () => {
|
|
79
|
-
{
|
|
80
|
-
let { exitCode } = await project.run("pnpm lint:eslint --fix");
|
|
81
|
-
|
|
82
|
-
expect(exitCode).toBe(0);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
let { exitCode } = await project.run("pnpm lint:eslint");
|
|
87
|
-
|
|
88
|
-
expect(exitCode).toBe(0);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
});
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { getLatest } from "#utils/npm.js";
|
|
2
|
-
import { files, packageJson } from "ember-apply";
|
|
3
|
-
import { formatLabel } from "#utils/cli.js";
|
|
4
|
-
import { maybeLintWithConcurrently } from "#consolidators/linting.js";
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
import { join } from "node:path";
|
|
7
|
-
import { hasDevDeps } from "#utils/manifest.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @type {import('#types').Layer}
|
|
11
|
-
*/
|
|
12
|
-
export default {
|
|
13
|
-
label: formatLabel("ESLint", "NullVoxPopuli's encapsulated config"),
|
|
14
|
-
hint: `Minimal dependencies added to package.json`,
|
|
15
|
-
|
|
16
|
-
async run(project) {
|
|
17
|
-
await files.applyFolder(join(import.meta.dirname, "files"), project.directory);
|
|
18
|
-
|
|
19
|
-
await packageJson.addDevDependencies(
|
|
20
|
-
await getLatest({
|
|
21
|
-
"@nullvoxpopuli/eslint-configs": "^7.0.0",
|
|
22
|
-
eslint: "^10.9.1",
|
|
23
|
-
}),
|
|
24
|
-
project.directory,
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
await packageJson.addScripts(
|
|
28
|
-
{
|
|
29
|
-
"lint:eslint": "eslint . --cache",
|
|
30
|
-
"lint:eslint:fix": "eslint . --fix",
|
|
31
|
-
},
|
|
32
|
-
project.directory,
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
await maybeLintWithConcurrently(project);
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @overload
|
|
40
|
-
* @param {import('#utils/project.js').Project} project
|
|
41
|
-
* @param {true} explain
|
|
42
|
-
* @returns {Promise<{ isSetup: boolean; reasons: string[] }>}
|
|
43
|
-
*/
|
|
44
|
-
/**
|
|
45
|
-
* @overload
|
|
46
|
-
* @param {import('#utils/project.js').Project} project
|
|
47
|
-
* @param {boolean | undefined} [explain]
|
|
48
|
-
* @returns {Promise<boolean>}
|
|
49
|
-
*/
|
|
50
|
-
async isSetup(project, explain) {
|
|
51
|
-
const reasons = [];
|
|
52
|
-
|
|
53
|
-
if (!existsSync(join(project.directory, "eslint.config.js"))) {
|
|
54
|
-
reasons.push("eslint.config.js is missing");
|
|
55
|
-
|
|
56
|
-
if (!explain) return false;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
let manifest = await packageJson.read(project.directory);
|
|
60
|
-
|
|
61
|
-
if (!hasDevDeps(manifest, ["@nullvoxpopuli/eslint-configs", "eslint"])) {
|
|
62
|
-
reasons.push("missing required dependencies: @nullvoxpopuli/eslint-configs, eslint");
|
|
63
|
-
|
|
64
|
-
if (!explain) return false;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let scripts = Object.values(manifest.scripts ?? {}).filter((script) =>
|
|
68
|
-
script.includes("eslint"),
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
if (!scripts.some((script) => script.includes("--cache"))) {
|
|
72
|
-
reasons.push("missing eslint script with --cache flag");
|
|
73
|
-
|
|
74
|
-
if (!explain) return false;
|
|
75
|
-
}
|
|
76
|
-
if (!scripts.some((script) => script.includes("--fix"))) {
|
|
77
|
-
reasons.push("missing eslint script with --fix flag");
|
|
78
|
-
|
|
79
|
-
if (!explain) return false;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (explain) {
|
|
83
|
-
return {
|
|
84
|
-
isSetup: reasons.length === 0,
|
|
85
|
-
reasons,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return reasons.length === 0;
|
|
90
|
-
},
|
|
91
|
-
};
|
/package/src/layers/{eslint-bundled-ember/files → eslint-bundled/files/ember}/eslint.config.js
RENAMED
|
File without changes
|
|
File without changes
|