ember.nvp 0.1.0 → 0.2.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 +41 -0
- package/.github/workflows/plan-release.yml +2 -2
- package/.github/workflows/publish.yml +2 -2
- package/.prettierignore +2 -1
- package/.prettierrc.js +10 -0
- package/.release-plan.json +11 -3
- package/CHANGELOG.md +37 -0
- package/README.md +79 -142
- package/package.json +28 -5
- package/pnpm-workspace.yaml +3 -0
- package/src/bases/README.md +5 -0
- package/src/bases/minimal-app/app.test.ts +203 -0
- package/src/bases/minimal-app/files/.env.development +8 -0
- package/src/bases/minimal-app/files/app/app.ts +21 -0
- package/src/bases/minimal-app/files/app/config.ts +30 -0
- package/src/bases/minimal-app/files/app/router.ts +51 -0
- package/src/bases/minimal-app/files/app/templates/application.gts +5 -0
- package/src/{layers/minimal/files-ts → bases/minimal-app/files}/babel.config.js +1 -4
- package/src/{layers/minimal → bases/minimal-app}/files/index.html +3 -5
- package/src/bases/minimal-app/files/package.json +57 -0
- package/src/{layers/minimal → bases/minimal-app}/files/tsconfig.json +0 -6
- package/src/bases/minimal-app/index.js +111 -0
- package/src/bases/minimal-library/index.js +10 -0
- package/src/cli/args.js +57 -0
- package/src/cli/generator.js +66 -11
- package/src/cli/index.js +44 -13
- package/src/cli/questions/layers.js +39 -50
- package/src/cli/questions/name.js +22 -6
- package/src/cli/questions/ok.js +38 -0
- package/src/cli/questions/package-manager.js +23 -2
- package/src/cli/questions/path.js +59 -0
- package/src/cli/questions/project-type.js +55 -0
- package/src/consolidators/linting.js +51 -0
- package/src/index.js +2 -0
- package/src/layers/eslint-bundled-ember/files/eslint.config.js +14 -0
- package/src/layers/eslint-bundled-ember/index.js +91 -0
- package/src/layers/eslint-bundled-nvp/app.test.ts +91 -0
- package/src/layers/eslint-bundled-nvp/files/eslint.config.js +16 -0
- package/src/layers/eslint-bundled-nvp/index.js +91 -0
- package/src/layers/eslint-ejected/index.js +95 -0
- package/src/layers/git/index.js +33 -0
- package/src/layers/github-actions/app.test.ts +73 -0
- package/src/layers/github-actions/index.js +200 -0
- package/src/layers/index.js +47 -0
- package/src/layers/prettier/files/.prettierrc.js +4 -0
- package/src/layers/prettier/index.js +45 -18
- package/src/layers/qunit/app.test.ts +90 -0
- package/src/layers/qunit/files/testem.cjs +26 -0
- package/src/layers/qunit/files/tests/index.html +16 -7
- package/src/layers/qunit/files/tests/test-helper.ts +61 -7
- package/src/layers/qunit/index.js +83 -34
- package/src/layers/release-plan/index.js +5 -0
- package/src/layers/renovate/files/app.json5 +14 -0
- package/src/layers/renovate/files/library.json5 +16 -0
- package/src/layers/renovate/index.js +68 -0
- package/src/layers/typescript/app.test.ts +93 -0
- package/src/layers/typescript/index.js +145 -0
- package/src/layers/vitest/files/vitest.config.mjs +1 -5
- package/src/layers/vitest/index.js +43 -26
- package/src/utils/babel.js +76 -0
- package/src/utils/buffer.js +15 -0
- package/src/utils/cli.js +45 -0
- package/src/utils/cwd.js +1 -0
- package/src/utils/fs.js +85 -0
- package/src/utils/git.js +41 -0
- package/src/utils/git.test.ts +36 -0
- package/src/utils/manifest.js +9 -0
- package/src/utils/npm.js +29 -0
- package/src/utils/object.js +10 -0
- package/src/utils/project.js +249 -0
- package/src/utils/remove-types.js +90 -0
- package/src/utils/types.ts +48 -0
- package/test/ember.nvp/cli.test.ts +12 -0
- package/test/ember.nvp/layers.test.ts +35 -0
- package/test/ember.nvp/permutations.test.ts +200 -0
- package/test/manual.sh +11 -0
- package/test/test-helpers/permutate.test.ts +70 -0
- package/test/test-helpers.ts +175 -0
- package/tsconfig.json +10 -2
- package/vitest.config.js +9 -0
- package/src/layers/eslint/index.js +0 -42
- package/src/layers/minimal/files/app/app.ts +0 -10
- package/src/layers/minimal/files/app/config.ts +0 -18
- package/src/layers/minimal/files/app/router.ts +0 -9
- package/src/layers/minimal/files/app/templates/application.gts +0 -7
- package/src/layers/minimal/files-js/babel.config.js +0 -38
- package/src/layers/minimal/index.js +0 -89
- package/src/layers/prettier/files/.prettierrc.cjs +0 -15
- /package/src/{layers/minimal → bases/minimal-app}/files/vite.config.mjs +0 -0
- /package/src/layers/{eslint/files/eslint.config.mjs → eslint-ejected/files/eslint.config.js} +0 -0
- /package/src/layers/{minimal/files/app/routes → qunit/files/tests/application}/.gitkeep +0 -0
- /package/src/layers/qunit/files/tests/{integration → rendering}/.gitkeep +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { beforeAll, describe, it, expect as hardExpect, afterAll } from "vitest";
|
|
2
|
+
import { generate, build, reapply } from "#test-helpers";
|
|
3
|
+
import { packageJson } from "ember-apply";
|
|
4
|
+
|
|
5
|
+
import type { Project } from "ember.nvp";
|
|
6
|
+
import { rm } from "node:fs/promises";
|
|
7
|
+
import { globSync } from "node:fs";
|
|
8
|
+
|
|
9
|
+
const expect = hardExpect.soft;
|
|
10
|
+
|
|
11
|
+
describe("typescript", () => {
|
|
12
|
+
let project: Project;
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
project = await generate({
|
|
15
|
+
type: "app",
|
|
16
|
+
layers: ["typescript"],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
let { exitCode } = await project.install();
|
|
20
|
+
|
|
21
|
+
hardExpect(exitCode, "Install succeeds").toBe(0);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterAll(async () => {
|
|
25
|
+
await rm(project.directory, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("project check", () => {
|
|
29
|
+
expect(project.desires.layers.map((layer) => layer.name)).toMatchInlineSnapshot(`
|
|
30
|
+
[
|
|
31
|
+
"typescript",
|
|
32
|
+
]
|
|
33
|
+
`);
|
|
34
|
+
expect(project.wantsTypeScript).toBe(true);
|
|
35
|
+
expect(project.type).toBe("app");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("has the typescript babel plugin", async () => {
|
|
39
|
+
let content = await project.read("babel.config.js");
|
|
40
|
+
|
|
41
|
+
expect(content).toContain("@babel/plugin-transform-typescript");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("build for development (testing, etc)", async () => {
|
|
45
|
+
let { exitCode } = await build(project);
|
|
46
|
+
|
|
47
|
+
expect(exitCode).toBe(0);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("build for production", async () => {
|
|
51
|
+
let { exitCode } = await build(project, "production");
|
|
52
|
+
|
|
53
|
+
expect(exitCode).toBe(0);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("has no JS files", async () => {
|
|
57
|
+
let results = globSync("app/**/*", {
|
|
58
|
+
exclude: ["node_modules", "dist"],
|
|
59
|
+
cwd: project.directory,
|
|
60
|
+
});
|
|
61
|
+
expect(results).toMatchInlineSnapshot(`
|
|
62
|
+
[
|
|
63
|
+
"app/app.ts",
|
|
64
|
+
"app/config.ts",
|
|
65
|
+
"app/router.ts",
|
|
66
|
+
"app/templates",
|
|
67
|
+
"app/templates/application.gts",
|
|
68
|
+
]
|
|
69
|
+
`);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("when re-applying, it no-ops correctly", async () => {
|
|
73
|
+
let files = new Set(
|
|
74
|
+
globSync("**/*", { cwd: project.directory, exclude: ["node_modules", "dist"] }),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
await reapply(project, []);
|
|
78
|
+
|
|
79
|
+
let filesAfter = new Set(
|
|
80
|
+
globSync("**/*", { cwd: project.directory, exclude: ["node_modules", "dist"] }),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
expect(filesAfter).toEqual(files);
|
|
84
|
+
expect(files).toMatchInlineSnapshot(`
|
|
85
|
+
Set {
|
|
86
|
+
"app",
|
|
87
|
+
"babel.config.js",
|
|
88
|
+
"index.html",
|
|
89
|
+
"package.json",
|
|
90
|
+
"pnpm-lock.yaml",
|
|
91
|
+
"tsconfig.json",
|
|
92
|
+
"vite.config.mjs",
|
|
93
|
+
"app/app.ts",
|
|
94
|
+
"app/config.ts",
|
|
95
|
+
"app/router.ts",
|
|
96
|
+
"app/templates",
|
|
97
|
+
"app/templates/application.gts",
|
|
98
|
+
}
|
|
99
|
+
`);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("javascript", () => {
|
|
104
|
+
let project: Project;
|
|
105
|
+
beforeAll(async () => {
|
|
106
|
+
project = await generate({
|
|
107
|
+
type: "app",
|
|
108
|
+
layers: [],
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
let { exitCode } = await project.install();
|
|
112
|
+
|
|
113
|
+
hardExpect(exitCode, "Install succeeds").toBe(0);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
afterAll(async () => {
|
|
117
|
+
await rm(project.directory, { recursive: true, force: true });
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("project check", () => {
|
|
121
|
+
expect(project.desires.layers.map((layer) => layer.name)).toMatchInlineSnapshot(`[]`);
|
|
122
|
+
expect(project.wantsTypeScript).toBe(false);
|
|
123
|
+
expect(project.type).toBe("app");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("does not have the typescript babel plugin", async () => {
|
|
127
|
+
let content = await project.read("babel.config.js");
|
|
128
|
+
|
|
129
|
+
expect(content).not.toContain("@babel/plugin-transform-typescript");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("updated the sub-path imports to not have ts extensions", async () => {
|
|
133
|
+
let manifest = await packageJson.read(project.directory);
|
|
134
|
+
|
|
135
|
+
expect(manifest.imports).toMatchInlineSnapshot(`
|
|
136
|
+
{
|
|
137
|
+
"#app/*": "./app/*",
|
|
138
|
+
"#components/*": "./app/components/*",
|
|
139
|
+
"#config": "./app/config.js",
|
|
140
|
+
"#services/*": "./app/services/*",
|
|
141
|
+
"#test-helpers/*": "./tests/helpers/*",
|
|
142
|
+
"#utils/*": "./app/utils/*",
|
|
143
|
+
}
|
|
144
|
+
`);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("build for development (testing, etc)", async () => {
|
|
148
|
+
let { exitCode } = await build(project);
|
|
149
|
+
|
|
150
|
+
expect(exitCode).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("build for production", async () => {
|
|
154
|
+
let { exitCode } = await build(project, "production");
|
|
155
|
+
|
|
156
|
+
expect(exitCode).toBe(0);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("has no TS files", async () => {
|
|
160
|
+
let results = globSync("app/**/*", {
|
|
161
|
+
exclude: ["node_modules", "dist"],
|
|
162
|
+
cwd: project.directory,
|
|
163
|
+
});
|
|
164
|
+
expect(results).toMatchInlineSnapshot(`
|
|
165
|
+
[
|
|
166
|
+
"app/app.js",
|
|
167
|
+
"app/config.js",
|
|
168
|
+
"app/router.js",
|
|
169
|
+
"app/templates",
|
|
170
|
+
"app/templates/application.gjs",
|
|
171
|
+
]
|
|
172
|
+
`);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("when re-applying, it no-ops correctly", async () => {
|
|
176
|
+
let files = new Set(
|
|
177
|
+
globSync("**/*", { cwd: project.directory, exclude: ["node_modules", "dist"] }),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
await reapply(project, []);
|
|
181
|
+
|
|
182
|
+
let filesAfter = new Set(
|
|
183
|
+
globSync("**/*", { cwd: project.directory, exclude: ["node_modules", "dist"] }),
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
expect(filesAfter).toEqual(files);
|
|
187
|
+
expect(files).toMatchInlineSnapshot(`
|
|
188
|
+
Set {
|
|
189
|
+
"app",
|
|
190
|
+
"babel.config.js",
|
|
191
|
+
"index.html",
|
|
192
|
+
"package.json",
|
|
193
|
+
"pnpm-lock.yaml",
|
|
194
|
+
"vite.config.mjs",
|
|
195
|
+
"app/app.js",
|
|
196
|
+
"app/config.js",
|
|
197
|
+
"app/router.js",
|
|
198
|
+
"app/templates",
|
|
199
|
+
"app/templates/application.gjs",
|
|
200
|
+
}
|
|
201
|
+
`);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# This file is committed to git and should not contain any secrets.
|
|
2
|
+
#
|
|
3
|
+
# Vite recommends using .env.local or .env.[mode].local if you need to manage secrets
|
|
4
|
+
# SEE: https://vite.dev/guide/env-and-mode.html#env-files for more information.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Default NODE_ENV with vite build --mode=test is production
|
|
8
|
+
NODE_ENV=development
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Looking for services that come from addons?
|
|
3
|
+
*
|
|
4
|
+
* See: https://github.com/embroider-build/embroider/issues/2659
|
|
5
|
+
*
|
|
6
|
+
* We currently don't support app-tree merging from libraries.
|
|
7
|
+
*
|
|
8
|
+
* For services, I highly recommend looking in to either of
|
|
9
|
+
* - https://github.com/chancancode/ember-polaris-service-
|
|
10
|
+
* - https://ember-primitives.pages.dev/6-utils/createService.md
|
|
11
|
+
* - https://ember-primitives.pages.dev/6-utils/createAsyncService.md
|
|
12
|
+
*/
|
|
13
|
+
import Application from "ember-strict-application-resolver";
|
|
14
|
+
|
|
15
|
+
export default class App extends Application {
|
|
16
|
+
modules = {
|
|
17
|
+
...import.meta.glob("./router.*", { eager: true }),
|
|
18
|
+
...import.meta.glob("./templates/**/*", { eager: true }),
|
|
19
|
+
...import.meta.glob("./services/**/*", { eager: true }),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
interface Config {
|
|
2
|
+
environment: "development" | "production";
|
|
3
|
+
locationType: "history" | "hash" | "none" | "auto";
|
|
4
|
+
rootURL: string;
|
|
5
|
+
EmberENV?: Record<string, unknown>;
|
|
6
|
+
APP: Record<string, unknown> & { rootElement?: string; autoboot?: boolean };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const ENV: Config = {
|
|
10
|
+
environment: import.meta.env.DEV ? "development" : "production",
|
|
11
|
+
rootURL: "/",
|
|
12
|
+
locationType: "history",
|
|
13
|
+
EmberENV: {},
|
|
14
|
+
APP: {},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default ENV;
|
|
18
|
+
|
|
19
|
+
// @ts-expect-error: Ignoreing private API
|
|
20
|
+
import { getGlobalConfig } from "@embroider/macros/src/addon/runtime";
|
|
21
|
+
|
|
22
|
+
export function enterTestMode() {
|
|
23
|
+
ENV.locationType = "none";
|
|
24
|
+
ENV.APP.rootElement = "#ember-testing";
|
|
25
|
+
ENV.APP.autoboot = false;
|
|
26
|
+
|
|
27
|
+
const theMacrosGlobal = getGlobalConfig();
|
|
28
|
+
theMacrosGlobal["@embroider/macros"] ||= {};
|
|
29
|
+
theMacrosGlobal["@embroider/macros"].isTesting ||= true;
|
|
30
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import EmbroiderRouter from "@embroider/router";
|
|
2
|
+
import config from "#config";
|
|
3
|
+
|
|
4
|
+
export default class Router extends EmbroiderRouter {
|
|
5
|
+
location = config.locationType;
|
|
6
|
+
rootURL = config.rootURL;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
Router.map(function () {});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Caveat:
|
|
13
|
+
* - https://github.com/embroider-build/embroider/issues/2521
|
|
14
|
+
* We don't yet have a way to do this in a nice way
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
// function bundle(name: string, loader: () => Promise<{ default: unknown }>[]) {
|
|
18
|
+
// return {
|
|
19
|
+
// names: [name],
|
|
20
|
+
// load: async () => {
|
|
21
|
+
// const [template, route, controller] = await Promise.all(loader());
|
|
22
|
+
// let slashName = name.replaceAll(".", "/");
|
|
23
|
+
// let results: Record<string, unknown> = {};
|
|
24
|
+
|
|
25
|
+
// if (template) results[`./templates/${slashName}`] = template.default;
|
|
26
|
+
// if (route) results[`./routes/${slashName}`] = route.default;
|
|
27
|
+
// if (controller) results[`./controllers/${slashName}`] = controller.default;
|
|
28
|
+
|
|
29
|
+
// return {
|
|
30
|
+
// default: results,
|
|
31
|
+
// };
|
|
32
|
+
// },
|
|
33
|
+
// };
|
|
34
|
+
// }
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Examples from:
|
|
38
|
+
* - https://github.com/NullVoxPopuli/limber/blob/67e2f54bbe224052e38f9a9e566d704411e65e86/apps/repl/app/router.ts#L35
|
|
39
|
+
*/
|
|
40
|
+
// (window as any)._embroiderRouteBundles_ = [
|
|
41
|
+
// bundle("docs", () => [import("./templates/docs.gts")]),
|
|
42
|
+
// bundle("docs.repl-sdk", () => [import("./templates/docs/repl-sdk.gts")]),
|
|
43
|
+
// bundle("docs.ember-repl", () => [import("./templates/docs/ember-repl.gts")]),
|
|
44
|
+
// bundle("docs.embedding", () => [import("./templates/docs/embedding.gts")]),
|
|
45
|
+
// bundle("docs.editor", () => [import("./templates/docs/editor.gts")]),
|
|
46
|
+
// bundle("docs.whatever", () => [
|
|
47
|
+
// import("./the/template.gts"),
|
|
48
|
+
// import("./the/route.ts"),
|
|
49
|
+
// import("./the/controller.ts"),
|
|
50
|
+
// ]),
|
|
51
|
+
// ];
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { dirname } from "node:path";
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
1
|
import { buildMacros } from "@embroider/macros/babel";
|
|
4
2
|
|
|
5
3
|
const macros = buildMacros();
|
|
@@ -17,7 +15,6 @@ export default {
|
|
|
17
15
|
[
|
|
18
16
|
"babel-plugin-ember-template-compilation",
|
|
19
17
|
{
|
|
20
|
-
compilerPath: "ember-source/dist/ember-template-compiler.js",
|
|
21
18
|
transforms: [...macros.templateMacros],
|
|
22
19
|
},
|
|
23
20
|
],
|
|
@@ -32,7 +29,7 @@ export default {
|
|
|
32
29
|
[
|
|
33
30
|
"@babel/plugin-transform-runtime",
|
|
34
31
|
{
|
|
35
|
-
absoluteRuntime:
|
|
32
|
+
absoluteRuntime: import.meta.dirname,
|
|
36
33
|
useESModules: true,
|
|
37
34
|
regenerator: false,
|
|
38
35
|
},
|
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
|
-
<title
|
|
5
|
+
<title>Minimal App</title>
|
|
6
6
|
<meta name="description" content="" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
8
|
-
|
|
9
|
-
<link rel="stylesheet" href="/app/styles/app.css" />
|
|
10
8
|
</head>
|
|
11
9
|
<body>
|
|
12
10
|
<script type="module">
|
|
13
|
-
import Application from "
|
|
14
|
-
import environment from "
|
|
11
|
+
import Application from "#app/app";
|
|
12
|
+
import environment from "#config";
|
|
15
13
|
|
|
16
14
|
Application.create(environment.APP);
|
|
17
15
|
</script>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "minimal-app",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Your Ember App's description here",
|
|
6
|
+
"repository": "",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"imports": {
|
|
11
|
+
"#app/*": "./app/*",
|
|
12
|
+
"#config": "./app/config.ts",
|
|
13
|
+
"#components/*": "./app/components/*",
|
|
14
|
+
"#services/*": "./app/services/*",
|
|
15
|
+
"#test-helpers/*": "./tests/helpers/*",
|
|
16
|
+
"#utils/*": "./app/utils/*"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
"./tests/*": "./tests/*",
|
|
20
|
+
"./*": "./app/*"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "vite build",
|
|
24
|
+
"dev": "vite",
|
|
25
|
+
"start": "vite"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@embroider/macros": "^1.19.6",
|
|
29
|
+
"@embroider/router": "^3.0.6",
|
|
30
|
+
"@glimmer/component": "^2.0.0",
|
|
31
|
+
"decorator-transforms": "^2.3.1",
|
|
32
|
+
"ember-source": "~6.10.0",
|
|
33
|
+
"ember-strict-application-resolver": "^0.1.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@babel/core": "^7.28.5",
|
|
37
|
+
"@babel/plugin-transform-runtime": "^7.28.5",
|
|
38
|
+
"@babel/plugin-transform-typescript": "^7.28.5",
|
|
39
|
+
"@babel/runtime": "^7.28.4",
|
|
40
|
+
"@ember/app-tsconfig": "^2.0.0",
|
|
41
|
+
"@embroider/core": "^4.4.2",
|
|
42
|
+
"@embroider/vite": "^1.5.0",
|
|
43
|
+
"@glint/ember-tsc": "^1.0.8",
|
|
44
|
+
"@glint/template": "^1.7.3",
|
|
45
|
+
"@glint/tsserver-plugin": "^2.0.8",
|
|
46
|
+
"@rollup/plugin-babel": "^6.1.0",
|
|
47
|
+
"babel-plugin-ember-template-compilation": "^4.0.0",
|
|
48
|
+
"typescript": "^5.9.3",
|
|
49
|
+
"vite": "^7.3.0"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">= 24"
|
|
53
|
+
},
|
|
54
|
+
"ember": {
|
|
55
|
+
"edition": "octane"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "@ember/app-tsconfig",
|
|
3
|
-
"include": ["app", "tests", "types"],
|
|
4
3
|
"compilerOptions": {
|
|
5
4
|
"allowJs": true,
|
|
6
|
-
"paths": {
|
|
7
|
-
"<%= name %>/tests/*": ["./tests/*"],
|
|
8
|
-
"<%= name %>/*": ["./app/*"],
|
|
9
|
-
"*": ["./types/*"]
|
|
10
|
-
},
|
|
11
5
|
"types": [
|
|
12
6
|
"ember-source/types",
|
|
13
7
|
"@embroider/core/virtual",
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { packageJson, js } from "ember-apply";
|
|
2
|
+
import { getLatest } from "#utils/npm.js";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { applyFolderTo } from "#utils/fs.js";
|
|
5
|
+
import { removeConfiguredPlugin } from "#utils/babel.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Minimal Layer
|
|
9
|
+
*
|
|
10
|
+
* Provides the absolute bare minimum for an Ember app:
|
|
11
|
+
* - type: "module" in package.json
|
|
12
|
+
* - No @embroider/compat (no-compat mode)
|
|
13
|
+
* - No testing framework
|
|
14
|
+
* - No linting or formatting
|
|
15
|
+
* - No ember-welcome-page
|
|
16
|
+
* - No warp-drive (opt-in if needed)
|
|
17
|
+
*/
|
|
18
|
+
export default {
|
|
19
|
+
label: "Minimal App Base",
|
|
20
|
+
description: "Bare minimum Ember app structure",
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 1. Apply files
|
|
24
|
+
* a. Remove TS if needed
|
|
25
|
+
* 2. Remove TS deps/files if needed
|
|
26
|
+
* 3. Update name(s)
|
|
27
|
+
*
|
|
28
|
+
* @param {import('#utils/project.js').Project} project
|
|
29
|
+
*/
|
|
30
|
+
async run(project) {
|
|
31
|
+
await applyFiles(project);
|
|
32
|
+
await updateName(project);
|
|
33
|
+
await makeJavaScript(project);
|
|
34
|
+
await upgradeDependencies(project);
|
|
35
|
+
await updateBabelConfig(project);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {import('#utils/project.js').Project} project
|
|
41
|
+
*/
|
|
42
|
+
async function updateBabelConfig(project) {
|
|
43
|
+
if (await project.hasOrWantsLayer("typescript")) return;
|
|
44
|
+
|
|
45
|
+
await removeConfiguredPlugin(project, "@babel/plugin-transform-typescript");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {import('#utils/project.js').Project} project
|
|
50
|
+
*/
|
|
51
|
+
async function applyFiles(project) {
|
|
52
|
+
let filePath = fileURLToPath(new URL("files", import.meta.url));
|
|
53
|
+
|
|
54
|
+
await applyFolderTo(filePath, project);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Operates on known files where the name matters
|
|
59
|
+
*
|
|
60
|
+
* @param {import('#utils/project.js').Project} project
|
|
61
|
+
*/
|
|
62
|
+
async function updateName(project) {
|
|
63
|
+
await packageJson.modify((json) => {
|
|
64
|
+
json.name = project.desires.name;
|
|
65
|
+
}, project.directory);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param {import('#utils/project.js').Project} project
|
|
70
|
+
*/
|
|
71
|
+
async function makeJavaScript(project) {
|
|
72
|
+
if (await project.hasOrWantsLayer("typescript")) return;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* We don't actually remove anything, because we want intellisense for JS
|
|
76
|
+
*
|
|
77
|
+
* But perhaps for the sake of minimal, we do remoev it.
|
|
78
|
+
* And we add a layer later for JSDoc ased TS or something
|
|
79
|
+
*/
|
|
80
|
+
await packageJson.removeDevDependencies(
|
|
81
|
+
[
|
|
82
|
+
"@ember/app-tsconfig",
|
|
83
|
+
"@glint/ember-tsc",
|
|
84
|
+
"@glint/template",
|
|
85
|
+
"@glint/tsserver-plugin",
|
|
86
|
+
"typescript",
|
|
87
|
+
],
|
|
88
|
+
project.directory,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
await project.removeFile("tsconfig.json");
|
|
92
|
+
|
|
93
|
+
await packageJson.modify((json) => {
|
|
94
|
+
json.imports["#config"] = "./app/config.js";
|
|
95
|
+
}, project.directory);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Bumps in-range only.
|
|
100
|
+
* Majors will need to go through PR to this repo.
|
|
101
|
+
*
|
|
102
|
+
* @param {import('#utils/project.js').Project} project
|
|
103
|
+
*/
|
|
104
|
+
async function upgradeDependencies(project) {
|
|
105
|
+
let existing = await packageJson.read(project.directory);
|
|
106
|
+
|
|
107
|
+
await packageJson.modify(async (json) => {
|
|
108
|
+
Object.assign(json.dependencies, await getLatest(existing.dependencies));
|
|
109
|
+
Object.assign(json.devDependencies, await getLatest(existing.devDependencies));
|
|
110
|
+
}, project.directory);
|
|
111
|
+
}
|
package/src/cli/args.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import { styleText, parseArgs } from "node:util";
|
|
3
|
+
|
|
4
|
+
const { values } = parseArgs({
|
|
5
|
+
options: {
|
|
6
|
+
name: {
|
|
7
|
+
type: "string",
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
path: {
|
|
11
|
+
type: "string",
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
type: {
|
|
15
|
+
type: "string",
|
|
16
|
+
choices: ["app", "addon", "library"],
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
confirm: {
|
|
20
|
+
type: "string",
|
|
21
|
+
choices: ["yes", "no"],
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
layers: {
|
|
25
|
+
type: "string",
|
|
26
|
+
multiple: true,
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
packageManager: {
|
|
30
|
+
type: "string",
|
|
31
|
+
choices: ["npm", "pnpm"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const { name, type, layers = [], packageManager, path, confirm } = values;
|
|
37
|
+
|
|
38
|
+
export const answers = {
|
|
39
|
+
name,
|
|
40
|
+
type,
|
|
41
|
+
layers,
|
|
42
|
+
packageManager,
|
|
43
|
+
path,
|
|
44
|
+
confirm,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param {string} label
|
|
50
|
+
* @param {string} value
|
|
51
|
+
*/
|
|
52
|
+
export function printArgInUse(label, value) {
|
|
53
|
+
let l = styleText(["gray", "bold"], label);
|
|
54
|
+
let v = styleText(["yellow", "italic"], value);
|
|
55
|
+
let u = styleText("dim", "using");
|
|
56
|
+
p.log.info(`${u} ${l}: ${v}`);
|
|
57
|
+
}
|