ember.nvp 0.0.0 → 0.1.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.
Files changed (43) hide show
  1. package/.github/workflows/plan-release.yml +61 -0
  2. package/.github/workflows/publish.yml +41 -0
  3. package/.nvmrc +1 -0
  4. package/.prettierignore +2 -0
  5. package/.release-plan.json +22 -0
  6. package/CHANGELOG.md +17 -0
  7. package/README.md +222 -1
  8. package/RELEASE.md +27 -0
  9. package/package.json +28 -3
  10. package/src/cli/generator.js +19 -0
  11. package/src/cli/index.js +48 -0
  12. package/src/cli/questions/layers.js +75 -0
  13. package/src/cli/questions/name.js +22 -0
  14. package/src/cli/questions/package-manager.js +21 -0
  15. package/src/layers/eslint/files/eslint.config.mjs +37 -0
  16. package/src/layers/eslint/index.js +42 -0
  17. package/src/layers/minimal/files/app/app.ts +10 -0
  18. package/src/layers/minimal/files/app/config.ts +18 -0
  19. package/src/layers/minimal/files/app/router.ts +9 -0
  20. package/src/layers/minimal/files/app/routes/.gitkeep +0 -0
  21. package/src/layers/minimal/files/app/templates/application.gts +7 -0
  22. package/src/layers/minimal/files/index.html +19 -0
  23. package/src/layers/minimal/files/tsconfig.json +18 -0
  24. package/src/layers/minimal/files/vite.config.mjs +13 -0
  25. package/src/layers/minimal/files-js/babel.config.js +38 -0
  26. package/src/layers/minimal/files-ts/babel.config.js +46 -0
  27. package/src/layers/minimal/index.js +89 -0
  28. package/src/layers/prettier/files/.prettierignore +18 -0
  29. package/src/layers/prettier/files/.prettierrc.cjs +15 -0
  30. package/src/layers/prettier/index.js +38 -0
  31. package/src/layers/qunit/files/run-tests.mjs +30 -0
  32. package/src/layers/qunit/files/tests/index.html +21 -0
  33. package/src/layers/qunit/files/tests/integration/.gitkeep +0 -0
  34. package/src/layers/qunit/files/tests/test-helper.ts +12 -0
  35. package/src/layers/qunit/files/tests/unit/.gitkeep +0 -0
  36. package/src/layers/qunit/index.js +53 -0
  37. package/src/layers/typescript/index.js +0 -0
  38. package/src/layers/vitest/files/tests/integration/.gitkeep +0 -0
  39. package/src/layers/vitest/files/tests/test-helper.ts +5 -0
  40. package/src/layers/vitest/files/tests/unit/.gitkeep +0 -0
  41. package/src/layers/vitest/files/vitest.config.mjs +22 -0
  42. package/src/layers/vitest/index.js +49 -0
  43. package/tsconfig.json +7 -0
@@ -0,0 +1,42 @@
1
+ import { packageJson, files } from "ember-apply";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+
7
+ /**
8
+ * ESLint Layer
9
+ *
10
+ * Adds ESLint support with modern configuration
11
+ */
12
+ export default {
13
+ label: "ESLint",
14
+ description: "Code linting with ESLint",
15
+
16
+ async run({ targetDir }) {
17
+ // Apply config files
18
+ await files.applyFolder(join(__dirname, "files"), targetDir);
19
+
20
+ // Add devDependencies
21
+ await packageJson.addDevDependencies(
22
+ {
23
+ eslint: "^9.18.0",
24
+ "@typescript-eslint/eslint-plugin": "^8.19.1",
25
+ "@typescript-eslint/parser": "^8.19.1",
26
+ "eslint-config-prettier": "^10.0.1",
27
+ "eslint-plugin-ember": "^12.2.1",
28
+ globals: "^15.14.0",
29
+ },
30
+ targetDir,
31
+ );
32
+
33
+ // Add scripts
34
+ await packageJson.addScripts(
35
+ {
36
+ lint: "eslint . --cache",
37
+ "lint:fix": "eslint . --fix",
38
+ },
39
+ targetDir,
40
+ );
41
+ },
42
+ };
@@ -0,0 +1,10 @@
1
+ import Application from "@ember/application";
2
+ import compatModules from "@embroider/virtual/compat-modules";
3
+ import Resolver from "ember-resolver";
4
+ import config from "./config.ts";
5
+
6
+ export default class App extends Application {
7
+ modulePrefix = config.modulePrefix;
8
+ podModulePrefix = config.podModulePrefix;
9
+ Resolver = Resolver.withModules(compatModules);
10
+ }
@@ -0,0 +1,18 @@
1
+ const ENV = {
2
+ modulePrefix: "__PROJECT_NAME__",
3
+ environment: import.meta.env.DEV ? "development" : "production",
4
+ rootURL: "/",
5
+ locationType: "history",
6
+ EmberENV: {},
7
+ APP: {},
8
+ } as {
9
+ environment: string;
10
+ modulePrefix: string;
11
+ podModulePrefix?: string;
12
+ rootURL: string;
13
+ locationType: "history" | "hash";
14
+ EmberENV: Record<string, unknown>;
15
+ APP: Record<string, unknown>;
16
+ };
17
+
18
+ export default ENV;
@@ -0,0 +1,9 @@
1
+ import EmberRouter from "@ember/routing/router";
2
+ import config from "#app/config.ts";
3
+
4
+ export default class Router extends EmberRouter {
5
+ location = config.locationType;
6
+ rootURL = config.rootURL;
7
+ }
8
+
9
+ Router.map(function () {});
File without changes
@@ -0,0 +1,7 @@
1
+ import { pageTitle } from 'ember-page-title';
2
+
3
+ <template>
4
+ {{pageTitle "__PROJECT_NAME__"}}
5
+
6
+ {{outlet}}
7
+ </template>
@@ -0,0 +1,19 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title><%= namespace %></title>
6
+ <meta name="description" content="" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+
9
+ <link rel="stylesheet" href="/app/styles/app.css" />
10
+ </head>
11
+ <body>
12
+ <script type="module">
13
+ import Application from "./app/app";
14
+ import environment from "./app/config/environment";
15
+
16
+ Application.create(environment.APP);
17
+ </script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": "@ember/app-tsconfig",
3
+ "include": ["app", "tests", "types"],
4
+ "compilerOptions": {
5
+ "allowJs": true,
6
+ "paths": {
7
+ "<%= name %>/tests/*": ["./tests/*"],
8
+ "<%= name %>/*": ["./app/*"],
9
+ "*": ["./types/*"]
10
+ },
11
+ "types": [
12
+ "ember-source/types",
13
+ "@embroider/core/virtual",
14
+ "vite/client",
15
+ "@glint/ember-tsc/types"
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from "vite";
2
+ import { extensions, ember } from "@embroider/vite";
3
+ import { babel } from "@rollup/plugin-babel";
4
+
5
+ export default defineConfig({
6
+ plugins: [
7
+ ember(),
8
+ babel({
9
+ babelHelpers: "runtime",
10
+ extensions,
11
+ }),
12
+ ],
13
+ });
@@ -0,0 +1,38 @@
1
+ import { dirname } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { buildMacros } from "@embroider/macros/babel";
4
+
5
+ const macros = buildMacros();
6
+
7
+ export default {
8
+ plugins: [
9
+ [
10
+ "babel-plugin-ember-template-compilation",
11
+ {
12
+ compilerPath: "ember-source/dist/ember-template-compiler.js",
13
+ transforms: [...macros.templateMacros],
14
+ },
15
+ ],
16
+ [
17
+ "module:decorator-transforms",
18
+ {
19
+ runtime: {
20
+ import: import.meta.resolve("decorator-transforms/runtime-esm"),
21
+ },
22
+ },
23
+ ],
24
+ [
25
+ "@babel/plugin-transform-runtime",
26
+ {
27
+ absoluteRuntime: dirname(fileURLToPath(import.meta.url)),
28
+ useESModules: true,
29
+ regenerator: false,
30
+ },
31
+ ],
32
+ ...macros.babelMacros,
33
+ ],
34
+
35
+ generatorOpts: {
36
+ compact: false,
37
+ },
38
+ };
@@ -0,0 +1,46 @@
1
+ import { dirname } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { buildMacros } from "@embroider/macros/babel";
4
+
5
+ const macros = buildMacros();
6
+
7
+ export default {
8
+ plugins: [
9
+ [
10
+ "@babel/plugin-transform-typescript",
11
+ {
12
+ allExtensions: true,
13
+ onlyRemoveTypeImports: true,
14
+ allowDeclareFields: true,
15
+ },
16
+ ],
17
+ [
18
+ "babel-plugin-ember-template-compilation",
19
+ {
20
+ compilerPath: "ember-source/dist/ember-template-compiler.js",
21
+ transforms: [...macros.templateMacros],
22
+ },
23
+ ],
24
+ [
25
+ "module:decorator-transforms",
26
+ {
27
+ runtime: {
28
+ import: import.meta.resolve("decorator-transforms/runtime-esm"),
29
+ },
30
+ },
31
+ ],
32
+ [
33
+ "@babel/plugin-transform-runtime",
34
+ {
35
+ absoluteRuntime: dirname(fileURLToPath(import.meta.url)),
36
+ useESModules: true,
37
+ regenerator: false,
38
+ },
39
+ ],
40
+ ...macros.babelMacros,
41
+ ],
42
+
43
+ generatorOpts: {
44
+ compact: false,
45
+ },
46
+ };
@@ -0,0 +1,89 @@
1
+ import { packageJson, files, js } from "ember-apply";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { readFile } from "node:fs/promises";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+
8
+ /**
9
+ * Minimal Layer
10
+ *
11
+ * Provides the absolute bare minimum for an Ember app:
12
+ * - type: "module" in package.json
13
+ * - No @embroider/compat (no-compat mode)
14
+ * - No testing framework
15
+ * - No linting or formatting
16
+ * - No ember-welcome-page
17
+ * - No warp-drive (opt-in if needed)
18
+ */
19
+ export default {
20
+ label: "Minimal Base",
21
+ description: "Bare minimum Ember app structure",
22
+
23
+ async run({ targetDir, projectName }) {
24
+ // Apply all files from the files directory
25
+ await files.applyFolder(join(__dirname, "files"), targetDir);
26
+
27
+ // Replace __PROJECT_NAME__ placeholders in specific files
28
+ const filesToUpdate = [
29
+ join(targetDir, "app", "config.ts"),
30
+ join(targetDir, "app", "templates", "application.gts"),
31
+ join(targetDir, "index.html"),
32
+ ];
33
+
34
+ for (const filePath of filesToUpdate) {
35
+ const content = await readFile(filePath, "utf-8");
36
+ const updated = content.replaceAll("__PROJECT_NAME__", projectName);
37
+ await files.copyFileTo(filePath, { content: updated });
38
+ }
39
+
40
+ // Add dependencies
41
+ await packageJson.addDependencies(
42
+ {
43
+ "@glimmer/component": "^1.1.2",
44
+ "@glimmer/tracking": "^1.1.2",
45
+ "@embroider/core": "^3.4.16",
46
+ "@embroider/macros": "^1.16.7",
47
+ "@embroider/router": "^2.1.8",
48
+ "@embroider/vite": "^6.0.2",
49
+ "@embroider/virtual": "^3.4.16",
50
+ "ember-page-title": "^8.2.4",
51
+ "ember-resolver": "^14.0.0",
52
+ "ember-source": "^6.0.1",
53
+ vite: "^6.0.3",
54
+ },
55
+ targetDir,
56
+ );
57
+
58
+ // Add devDependencies
59
+ await packageJson.addDevDependencies(
60
+ {
61
+ "@babel/core": "^7.26.0",
62
+ "@babel/plugin-transform-typescript": "^7.26.3",
63
+ "@rollup/plugin-babel": "^6.0.4",
64
+ "@tsconfig/ember": "^3.0.8",
65
+ typescript: "^5.7.3",
66
+ },
67
+ targetDir,
68
+ );
69
+
70
+ // Add scripts
71
+ await packageJson.addScripts(
72
+ {
73
+ start: "vite",
74
+ build: "vite build",
75
+ preview: "vite preview",
76
+ },
77
+ targetDir,
78
+ );
79
+
80
+ // Update package.json to set type: "module" and other metadata
81
+ await packageJson.modify((json) => {
82
+ json.name = projectName;
83
+ json.version = "0.0.0";
84
+ json.private = true;
85
+ json.type = "module";
86
+ return json;
87
+ }, targetDir);
88
+ },
89
+ };
@@ -0,0 +1,18 @@
1
+ # unconventionally formatted files
2
+ /.changeset
3
+
4
+ # compiled output
5
+ /dist/
6
+ /tmp/
7
+
8
+ # dependencies
9
+ /node_modules/
10
+
11
+ # misc
12
+ /.env*
13
+ /.vite/
14
+ /.pnp*
15
+ .pnp.*
16
+
17
+ # ember-try
18
+ /.node_modules.ember-try/
@@ -0,0 +1,15 @@
1
+ module.exports = {
2
+ singleQuote: true,
3
+ trailingComma: 'es5',
4
+ printWidth: 100,
5
+ semi: true,
6
+ plugins: ['prettier-plugin-ember-template-tag'],
7
+ overrides: [
8
+ {
9
+ files: '*.{gjs,gts}',
10
+ options: {
11
+ parser: 'ember-template-tag',
12
+ },
13
+ },
14
+ ],
15
+ };
@@ -0,0 +1,38 @@
1
+ import { packageJson, files } from "ember-apply";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+
7
+ /**
8
+ * Prettier Layer
9
+ *
10
+ * Adds Prettier for code formatting
11
+ */
12
+ export default {
13
+ label: "Prettier",
14
+ description: "Code formatting with Prettier",
15
+
16
+ async run({ targetDir }) {
17
+ // Apply config files
18
+ await files.applyFolder(join(__dirname, "files"), targetDir);
19
+
20
+ // Add devDependencies
21
+ await packageJson.addDevDependencies(
22
+ {
23
+ prettier: "^3.4.2",
24
+ "prettier-plugin-ember-template-tag": "^2.0.2",
25
+ },
26
+ targetDir,
27
+ );
28
+
29
+ // Add scripts
30
+ await packageJson.addScripts(
31
+ {
32
+ format: "prettier --write .",
33
+ "format:check": "prettier --check .",
34
+ },
35
+ targetDir,
36
+ );
37
+ },
38
+ };
@@ -0,0 +1,30 @@
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!");
@@ -0,0 +1,21 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>__PROJECT_NAME__ Tests</title>
6
+ <meta name="description" content="" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+
9
+ <link rel="stylesheet" href="https://unpkg.com/qunit@2/qunit/qunit.css" />
10
+
11
+ <script type="module" src="/@embroider/virtual/test-support.js"></script>
12
+ </head>
13
+ <body>
14
+ <div id="qunit"></div>
15
+ <div id="qunit-fixture">
16
+ <div id="ember-testing-container">
17
+ <div id="ember-testing"></div>
18
+ </div>
19
+ </div>
20
+ </body>
21
+ </html>
@@ -0,0 +1,12 @@
1
+ import Application from "#app/app.ts";
2
+ import config from "#app/config.ts";
3
+ import * as QUnit from "qunit";
4
+ import { setApplication } from "@ember/test-helpers";
5
+ import { setup } from "qunit-dom";
6
+ import { start } from "ember-qunit";
7
+
8
+ setApplication(Application.create(config));
9
+
10
+ setup(QUnit.assert);
11
+
12
+ start();
File without changes
@@ -0,0 +1,53 @@
1
+ import { packageJson, files } from "ember-apply";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { readFile } from "node:fs/promises";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+
8
+ /**
9
+ * QUnit Layer
10
+ *
11
+ * Adds QUnit testing support (Ember's traditional testing framework)
12
+ */
13
+ export default {
14
+ label: "QUnit",
15
+ description: "Testing with QUnit",
16
+
17
+ async run({ targetDir, projectName }) {
18
+ // Apply test files
19
+ await files.applyFolder(join(__dirname, "files"), targetDir);
20
+
21
+ // Replace __PROJECT_NAME__ in tests/index.html
22
+ const testHtmlPath = join(targetDir, "tests", "index.html");
23
+ const content = await readFile(testHtmlPath, "utf-8");
24
+ const updated = content.replaceAll("__PROJECT_NAME__", projectName);
25
+ await files.copyFileTo(testHtmlPath, { content: updated });
26
+
27
+ // Add dependencies
28
+ await packageJson.addDependencies(
29
+ {
30
+ "@ember/test-helpers": "^4.0.4",
31
+ },
32
+ targetDir,
33
+ );
34
+
35
+ // Add devDependencies
36
+ await packageJson.addDevDependencies(
37
+ {
38
+ qunit: "^2.22.0",
39
+ "@ember/test-waiters": "^3.1.0",
40
+ playwright: "^1.49.1",
41
+ },
42
+ targetDir,
43
+ );
44
+
45
+ // Add scripts
46
+ await packageJson.addScripts(
47
+ {
48
+ test: "vite build && node ./run-tests.mjs",
49
+ },
50
+ targetDir,
51
+ );
52
+ },
53
+ };
File without changes
@@ -0,0 +1,5 @@
1
+ import Application from "#app/app.ts";
2
+ import config from "#app/config.ts";
3
+ import { setApplication } from "@ember/test-helpers";
4
+
5
+ setApplication(Application.create(config));
File without changes
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import { extensions, ember } from "@embroider/vite";
3
+ import { babel } from "@rollup/plugin-babel";
4
+
5
+ export default defineConfig({
6
+ plugins: [
7
+ ember(),
8
+ babel({
9
+ babelHelpers: "runtime",
10
+ extensions: extensions.flatMap((extension) => [
11
+ extension,
12
+ ".gts",
13
+ ".gjs",
14
+ ]),
15
+ }),
16
+ ],
17
+ test: {
18
+ environment: "happy-dom",
19
+ setupFiles: ["./tests/test-helper.ts"],
20
+ include: ["tests/**/*-test.{js,ts,gjs,gts}"],
21
+ },
22
+ });
@@ -0,0 +1,49 @@
1
+ import { packageJson, files } from "ember-apply";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+
7
+ /**
8
+ * Vitest Layer
9
+ *
10
+ * Adds Vitest testing support (modern, fast alternative to QUnit)
11
+ */
12
+ export default {
13
+ label: "Vitest",
14
+ description: "Testing with Vitest (modern & fast)",
15
+
16
+ async run({ targetDir }) {
17
+ // Apply test files
18
+ await files.applyFolder(join(__dirname, "files"), targetDir);
19
+
20
+ // Add dependencies
21
+ await packageJson.addDependencies(
22
+ {
23
+ "@ember/test-helpers": "^4.0.4",
24
+ },
25
+ targetDir,
26
+ );
27
+
28
+ // Add devDependencies
29
+ await packageJson.addDevDependencies(
30
+ {
31
+ vitest: "^2.1.8",
32
+ "@vitest/ui": "^2.1.8",
33
+ "happy-dom": "^15.11.7",
34
+ "@ember/test-waiters": "^3.1.0",
35
+ },
36
+ targetDir,
37
+ );
38
+
39
+ // Add scripts
40
+ await packageJson.addScripts(
41
+ {
42
+ test: "vitest run",
43
+ "test:watch": "vitest",
44
+ "test:ui": "vitest --ui",
45
+ },
46
+ targetDir,
47
+ );
48
+ },
49
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@ember/library-tsconfig",
3
+ "compilerOptions": {
4
+ "allowJs": true
5
+ },
6
+ "types": ["ember-source/types", "@glint/ember-tsc/types"]
7
+ }