ember.nvp 0.3.0 → 0.5.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 +5 -19
- package/CHANGELOG.md +99 -9
- package/package.json +3 -2
- package/packages/vite/README.md +6 -0
- package/packages/vite/package.json +15 -2
- package/packages/vite/rolldown.config.js +18 -0
- package/src/bases/minimal-app/index.js +7 -2
- package/src/cli/args.js +7 -1
- package/src/cli/generator.js +7 -2
- package/src/cli/index.js +3 -1
- package/src/cli/questions/name.js +5 -6
- package/src/cli/questions/path.js +5 -6
- package/src/cli/questions/replace-or-update.js +56 -0
- package/src/layers/git/files/gitignore +1 -0
- package/src/layers/git/index.js +6 -2
- package/src/layers/qunit/files/tests/test-helper.ts +1 -15
- package/src/utils/npm.js +4 -0
- package/test/ember.nvp/generator-replace-or-update.test.ts +92 -0
- package/test/ember.nvp/layer-qunit.test.ts +34 -0
- package/packages/vite/node_modules/.bin/tsc +0 -21
- package/packages/vite/node_modules/.bin/tsserver +0 -21
- package/packages/vite/node_modules/.bin/vite +0 -21
package/.release-plan.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"solution": {
|
|
3
3
|
"ember.nvp": {
|
|
4
4
|
"impact": "minor",
|
|
5
|
-
"oldVersion": "0.
|
|
6
|
-
"newVersion": "0.
|
|
5
|
+
"oldVersion": "0.4.0",
|
|
6
|
+
"newVersion": "0.5.0",
|
|
7
7
|
"tagName": "latest",
|
|
8
8
|
"constraints": [
|
|
9
9
|
{
|
|
@@ -12,28 +12,14 @@
|
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"impact": "patch",
|
|
15
|
-
"reason": "Appears in changelog section :
|
|
15
|
+
"reason": "Appears in changelog section :house: Internal"
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
18
|
"pkgJSONPath": "./package.json"
|
|
19
19
|
},
|
|
20
20
|
"@nullvoxpopuli/ember-vite": {
|
|
21
|
-
"
|
|
22
|
-
"oldVersion": "1.0.0",
|
|
23
|
-
"newVersion": "1.1.0",
|
|
24
|
-
"tagName": "latest",
|
|
25
|
-
"constraints": [
|
|
26
|
-
{
|
|
27
|
-
"impact": "minor",
|
|
28
|
-
"reason": "Appears in changelog section :rocket: Enhancement"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"impact": "patch",
|
|
32
|
-
"reason": "Appears in changelog section :bug: Bug Fix"
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
|
-
"pkgJSONPath": "./packages/vite/package.json"
|
|
21
|
+
"oldVersion": "1.0.3"
|
|
36
22
|
}
|
|
37
23
|
},
|
|
38
|
-
"description": "## Release (2026-06-
|
|
24
|
+
"description": "## Release (2026-06-29)\n\n* ember.nvp 0.5.0 (minor)\n\n#### :rocket: Enhancement\n* `ember.nvp`\n * [#55](https://github.com/NullVoxPopuli/ember.nvp/pull/55) Upgrade @clack/prompts ([@tcjr](https://github.com/tcjr))\n\n#### :house: Internal\n* `ember.nvp`\n * [#53](https://github.com/NullVoxPopuli/ember.nvp/pull/53) Add typescript to root ([@tcjr](https://github.com/tcjr))\n\n#### Committers: 1\n- Tom Carter ([@tcjr](https://github.com/tcjr))\n"
|
|
39
25
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,23 +1,113 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## Release (2026-06-
|
|
3
|
+
## Release (2026-06-29)
|
|
4
|
+
|
|
5
|
+
* ember.nvp 0.5.0 (minor)
|
|
6
|
+
|
|
7
|
+
#### :rocket: Enhancement
|
|
8
|
+
* `ember.nvp`
|
|
9
|
+
* [#55](https://github.com/NullVoxPopuli/ember.nvp/pull/55) Upgrade @clack/prompts ([@tcjr](https://github.com/tcjr))
|
|
10
|
+
|
|
11
|
+
#### :house: Internal
|
|
12
|
+
* `ember.nvp`
|
|
13
|
+
* [#53](https://github.com/NullVoxPopuli/ember.nvp/pull/53) Add typescript to root ([@tcjr](https://github.com/tcjr))
|
|
14
|
+
|
|
15
|
+
#### Committers: 1
|
|
16
|
+
- Tom Carter ([@tcjr](https://github.com/tcjr))
|
|
17
|
+
|
|
18
|
+
## Release (2026-06-23)
|
|
19
|
+
|
|
20
|
+
* ember.nvp 0.4.0 (minor)
|
|
21
|
+
|
|
22
|
+
#### :rocket: Enhancement
|
|
23
|
+
* `ember.nvp`
|
|
24
|
+
* [#48](https://github.com/NullVoxPopuli/ember.nvp/pull/48) replaceOrUpdate ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
25
|
+
|
|
26
|
+
#### :bug: Bug Fix
|
|
27
|
+
* `ember.nvp`
|
|
28
|
+
* [#52](https://github.com/NullVoxPopuli/ember.nvp/pull/52) Fix test-helper ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
29
|
+
|
|
30
|
+
#### :house: Internal
|
|
31
|
+
* `ember.nvp`
|
|
32
|
+
* [#50](https://github.com/NullVoxPopuli/ember.nvp/pull/50) Tests for qunit ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
33
|
+
* [#49](https://github.com/NullVoxPopuli/ember.nvp/pull/49) Prepare Release ([@github-actions[bot]](https://github.com/apps/github-actions))
|
|
34
|
+
|
|
35
|
+
#### Committers: 2
|
|
36
|
+
- GitHub Actions [Bot] ([@github-actions](https://github.com/apps/github-actions))
|
|
37
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
38
|
+
|
|
39
|
+
## Release (2026-06-22)
|
|
4
40
|
|
|
5
41
|
* ember.nvp 0.3.0 (minor)
|
|
6
|
-
* @nullvoxpopuli/ember-vite 1.1.0 (minor)
|
|
7
42
|
|
|
8
43
|
#### :rocket: Enhancement
|
|
9
|
-
* `ember.nvp`, `@nullvoxpopuli/ember-vite`
|
|
10
|
-
* [#32](https://github.com/NullVoxPopuli/ember.nvp/pull/32) Add fast vite plugin ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
11
44
|
* `ember.nvp`
|
|
12
|
-
* [#
|
|
45
|
+
* [#48](https://github.com/NullVoxPopuli/ember.nvp/pull/48) replaceOrUpdate ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
46
|
+
|
|
47
|
+
#### Committers: 1
|
|
48
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
49
|
+
|
|
50
|
+
## Release (2026-06-22)
|
|
51
|
+
|
|
52
|
+
* ember.nvp 0.2.6 (patch)
|
|
53
|
+
* @nullvoxpopuli/ember-vite 1.0.3 (patch)
|
|
13
54
|
|
|
14
55
|
#### :bug: Bug Fix
|
|
15
56
|
* `@nullvoxpopuli/ember-vite`, `ember.nvp`
|
|
16
|
-
* [#
|
|
57
|
+
* [#46](https://github.com/NullVoxPopuli/ember.nvp/pull/46) compile ts authored packages ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
17
58
|
|
|
18
|
-
#### Committers:
|
|
19
|
-
-
|
|
20
|
-
|
|
59
|
+
#### Committers: 1
|
|
60
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
61
|
+
|
|
62
|
+
## Release (2026-06-22)
|
|
63
|
+
|
|
64
|
+
* ember.nvp 0.2.5 (patch)
|
|
65
|
+
|
|
66
|
+
#### :bug: Bug Fix
|
|
67
|
+
* `ember.nvp`
|
|
68
|
+
* [#44](https://github.com/NullVoxPopuli/ember.nvp/pull/44) Fix new git ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
69
|
+
|
|
70
|
+
#### Committers: 1
|
|
71
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
72
|
+
|
|
73
|
+
## Release (2026-06-22)
|
|
74
|
+
|
|
75
|
+
* ember.nvp 0.2.4 (patch)
|
|
76
|
+
|
|
77
|
+
#### :bug: Bug Fix
|
|
78
|
+
* `ember.nvp`
|
|
79
|
+
* [#42](https://github.com/NullVoxPopuli/ember.nvp/pull/42) fix falsey depndencies ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
80
|
+
|
|
81
|
+
#### Committers: 1
|
|
82
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
83
|
+
|
|
84
|
+
## Release (2026-06-22)
|
|
85
|
+
|
|
86
|
+
* ember.nvp 0.2.3 (patch)
|
|
87
|
+
* @nullvoxpopuli/ember-vite 1.0.2 (patch)
|
|
88
|
+
|
|
89
|
+
#### :bug: Bug Fix
|
|
90
|
+
* `@nullvoxpopuli/ember-vite`, `ember.nvp`
|
|
91
|
+
* [#41](https://github.com/NullVoxPopuli/ember.nvp/pull/41) Fix version range usage ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
92
|
+
* `ember.nvp`
|
|
93
|
+
* [#40](https://github.com/NullVoxPopuli/ember.nvp/pull/40) Ensure imports exist ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
94
|
+
|
|
95
|
+
#### Committers: 1
|
|
96
|
+
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
97
|
+
|
|
98
|
+
## Release (2026-06-01)
|
|
99
|
+
|
|
100
|
+
* ember.nvp 0.2.2 (patch)
|
|
101
|
+
* @nullvoxpopuli/ember-vite 1.0.1 (patch)
|
|
102
|
+
|
|
103
|
+
#### :house: Internal
|
|
104
|
+
* `@nullvoxpopuli/ember-vite`
|
|
105
|
+
* [#36](https://github.com/NullVoxPopuli/ember.nvp/pull/36) Fix npm provenance failure for @nullvoxpopuli/ember-vite publish ([@Copilot](https://github.com/apps/copilot-swe-agent))
|
|
106
|
+
* `ember.nvp`, `@nullvoxpopuli/ember-vite`
|
|
107
|
+
* [#37](https://github.com/NullVoxPopuli/ember.nvp/pull/37) Revert "Prepare Release" ([@NullVoxPopuli](https://github.com/NullVoxPopuli))
|
|
108
|
+
|
|
109
|
+
#### Committers: 2
|
|
110
|
+
- Copilot [Bot] ([@copilot-swe-agent](https://github.com/apps/copilot-swe-agent))
|
|
21
111
|
- [@NullVoxPopuli](https://github.com/NullVoxPopuli)
|
|
22
112
|
|
|
23
113
|
## Release (2026-05-15)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember.nvp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "ember project generator, alternative to the official blueprints, but more modern -- hopefully one day to upstream back in to ember-cli / official blueprints",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"exports": "./src/index.js",
|
|
20
20
|
"bin": "./src/cli/index.js",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@clack/prompts": "^
|
|
22
|
+
"@clack/prompts": "^1.6.0",
|
|
23
23
|
"babel-remove-types": "^2.0.0",
|
|
24
24
|
"content-tag": "^4.2.0",
|
|
25
25
|
"ember-apply": "^2.17.0",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"prettier-plugin-ember-template-tag": "^2.1.6",
|
|
40
40
|
"release-plan": "^0.18.0",
|
|
41
41
|
"rimraf": "^6.1.3",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
42
43
|
"vite": "^8.0.14",
|
|
43
44
|
"vitest": "^4.1.7"
|
|
44
45
|
},
|
package/packages/vite/README.md
CHANGED
|
@@ -31,6 +31,12 @@ Then delete from your package.json: `@rollup/plugin-babel`, `@embroider/core`, `
|
|
|
31
31
|
> [!NOTE]
|
|
32
32
|
> babel related deps are still needed for linting, so don't delete those
|
|
33
33
|
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
- `type=module` in your ember app
|
|
37
|
+
- babel config must be named `babel.config.js`
|
|
38
|
+
- `@embroider/vite` is up to date~ish
|
|
39
|
+
|
|
34
40
|
## Configuration
|
|
35
41
|
|
|
36
42
|
The `ember()` plugin takes the following options:
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nullvoxpopuli/ember-vite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Meta plugin for ember projects focusing on speed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"main": "dist/index.js"
|
|
9
|
+
},
|
|
7
10
|
"keywords": [
|
|
8
11
|
"vite",
|
|
9
12
|
"ember",
|
|
@@ -11,9 +14,18 @@
|
|
|
11
14
|
],
|
|
12
15
|
"author": "NullVoxPopuli",
|
|
13
16
|
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/NullVoxPopuli/ember.nvp",
|
|
20
|
+
"directory": "packages/vite"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "rolldown --config",
|
|
24
|
+
"prepack": "pnpm build"
|
|
25
|
+
},
|
|
14
26
|
"packageManager": "pnpm@10.28.0",
|
|
15
27
|
"dependencies": {
|
|
16
|
-
"@babel/core": "^7.28.
|
|
28
|
+
"@babel/core": "^7.28.10",
|
|
17
29
|
"@embroider/core": "^4.4.2",
|
|
18
30
|
"@embroider/vite": "^1.5.0",
|
|
19
31
|
"@rollup/plugin-babel": "^7.1.0",
|
|
@@ -25,6 +37,7 @@
|
|
|
25
37
|
"node": ">= 24"
|
|
26
38
|
},
|
|
27
39
|
"devDependencies": {
|
|
40
|
+
"rolldown": "^1.1.2",
|
|
28
41
|
"typescript": "^5.9.3",
|
|
29
42
|
"vite": "^8.0.14"
|
|
30
43
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from "rolldown";
|
|
2
|
+
|
|
3
|
+
import manifest from "./package.json" with { type: "json" };
|
|
4
|
+
|
|
5
|
+
const deps = Object.keys(manifest.dependencies || {});
|
|
6
|
+
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
input: "index.ts",
|
|
9
|
+
output: {
|
|
10
|
+
format: "esm",
|
|
11
|
+
file: "dist/index.js",
|
|
12
|
+
codeSplitting: false,
|
|
13
|
+
},
|
|
14
|
+
external(id) {
|
|
15
|
+
if (id.startsWith("node:")) return true;
|
|
16
|
+
if (deps.some((dep) => id.startsWith(dep))) return true;
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -91,6 +91,7 @@ async function makeJavaScript(project) {
|
|
|
91
91
|
await project.removeFile("tsconfig.json");
|
|
92
92
|
|
|
93
93
|
await packageJson.modify((json) => {
|
|
94
|
+
json.imports ||= {};
|
|
94
95
|
json.imports["#config"] = "./app/config.js";
|
|
95
96
|
}, project.directory);
|
|
96
97
|
}
|
|
@@ -105,7 +106,11 @@ async function upgradeDependencies(project) {
|
|
|
105
106
|
let existing = await packageJson.read(project.directory);
|
|
106
107
|
|
|
107
108
|
await packageJson.modify(async (json) => {
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
if (json.dependencies) {
|
|
110
|
+
Object.assign(json.dependencies, await getLatest(existing.dependencies));
|
|
111
|
+
}
|
|
112
|
+
if (json.devDependencies) {
|
|
113
|
+
Object.assign(json.devDependencies, await getLatest(existing.devDependencies));
|
|
114
|
+
}
|
|
110
115
|
}, project.directory);
|
|
111
116
|
}
|
package/src/cli/args.js
CHANGED
|
@@ -30,10 +30,15 @@ const { values } = parseArgs({
|
|
|
30
30
|
type: "string",
|
|
31
31
|
choices: ["npm", "pnpm"],
|
|
32
32
|
},
|
|
33
|
+
|
|
34
|
+
replaceOrUpdate: {
|
|
35
|
+
type: "string",
|
|
36
|
+
choices: ["replace", "update"],
|
|
37
|
+
},
|
|
33
38
|
},
|
|
34
39
|
});
|
|
35
40
|
|
|
36
|
-
const { name, type, layers = [], packageManager, path, confirm } = values;
|
|
41
|
+
const { replaceOrUpdate, name, type, layers = [], packageManager, path, confirm } = values;
|
|
37
42
|
|
|
38
43
|
export const answers = {
|
|
39
44
|
name,
|
|
@@ -42,6 +47,7 @@ export const answers = {
|
|
|
42
47
|
packageManager,
|
|
43
48
|
path,
|
|
44
49
|
confirm,
|
|
50
|
+
replaceOrUpdate,
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
/**
|
package/src/cli/generator.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir } from "node:fs/promises";
|
|
1
|
+
import { mkdir, rm } from "node:fs/promises";
|
|
2
2
|
|
|
3
3
|
import baseApp from "#bases/minimal-app";
|
|
4
4
|
import baseLibrary from "#bases/minimal-library";
|
|
@@ -8,8 +8,13 @@ import { hasGit } from "#utils/git.js";
|
|
|
8
8
|
* Generate project files by running layer functions
|
|
9
9
|
*
|
|
10
10
|
* @param {import('#utils/project.js').Project} project
|
|
11
|
+
* @param {string} [replaceOrUpdate]
|
|
11
12
|
*/
|
|
12
|
-
export async function generateProject(project) {
|
|
13
|
+
export async function generateProject(project, replaceOrUpdate) {
|
|
14
|
+
if (replaceOrUpdate === "replace") {
|
|
15
|
+
await rm(project.directory, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
await mkdir(project.directory, { recursive: true });
|
|
14
19
|
|
|
15
20
|
switch (project.desires.type) {
|
package/src/cli/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { askPath } from "./questions/path.js";
|
|
|
10
10
|
import { askIfOK } from "./questions/ok.js";
|
|
11
11
|
import { styleText } from "node:util";
|
|
12
12
|
import { Project } from "#utils/project.js";
|
|
13
|
+
import { askReplaceOrUpdate } from "./questions/replace-or-update.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* This whole file's primary purpose is to be an interactive CLI
|
|
@@ -25,6 +26,7 @@ async function main() {
|
|
|
25
26
|
|
|
26
27
|
const projectName = await askName();
|
|
27
28
|
const projectPath = await askPath(projectName);
|
|
29
|
+
const replaceOrUpdate = await askReplaceOrUpdate(projectPath);
|
|
28
30
|
const projectType = await askProjectType();
|
|
29
31
|
const selectedLayers = await askLayers();
|
|
30
32
|
const packageManager = await askPackageManager();
|
|
@@ -44,7 +46,7 @@ async function main() {
|
|
|
44
46
|
|
|
45
47
|
try {
|
|
46
48
|
// Generate the project
|
|
47
|
-
await generateProject(project);
|
|
49
|
+
await generateProject(project, replaceOrUpdate);
|
|
48
50
|
|
|
49
51
|
s.stop("Project created!");
|
|
50
52
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { cancel, isCancel, text } from "@clack/prompts";
|
|
3
2
|
import packageNameRegex from "package-name-regex";
|
|
4
3
|
import { answers, printArgInUse } from "#args";
|
|
5
4
|
|
|
@@ -14,12 +13,12 @@ export async function askName() {
|
|
|
14
13
|
return answers.name;
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
|
-
const projectName = await
|
|
16
|
+
const projectName = await text({
|
|
18
17
|
message: "What is your project name?",
|
|
19
18
|
placeholder: DEFAULT,
|
|
20
19
|
defaultValue: DEFAULT,
|
|
21
20
|
validate(value) {
|
|
22
|
-
if (value.length === 0) return;
|
|
21
|
+
if (!value || value.length === 0) return;
|
|
23
22
|
|
|
24
23
|
let isValid = packageNameRegex.test(value);
|
|
25
24
|
|
|
@@ -29,8 +28,8 @@ export async function askName() {
|
|
|
29
28
|
},
|
|
30
29
|
});
|
|
31
30
|
|
|
32
|
-
if (
|
|
33
|
-
|
|
31
|
+
if (isCancel(projectName)) {
|
|
32
|
+
cancel("Operation cancelled");
|
|
34
33
|
return process.exit(0);
|
|
35
34
|
}
|
|
36
35
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { cancel, isCancel, text } from "@clack/prompts";
|
|
3
2
|
import { join } from "node:path";
|
|
4
3
|
import { answers, printArgInUse } from "#args";
|
|
5
4
|
import { cwd } from "#utils/cwd.js";
|
|
@@ -29,12 +28,12 @@ export async function askPath(name) {
|
|
|
29
28
|
|
|
30
29
|
const defaultValue = join(cwd, name);
|
|
31
30
|
|
|
32
|
-
const answer = await
|
|
31
|
+
const answer = await text({
|
|
33
32
|
message: "Where would you like to place your project?",
|
|
34
33
|
placeholder: defaultValue.replace(cwd, "."),
|
|
35
34
|
defaultValue: defaultValue,
|
|
36
35
|
validate(value) {
|
|
37
|
-
if (value.length === 0) return;
|
|
36
|
+
if (!value || value.length === 0) return;
|
|
38
37
|
|
|
39
38
|
if (!isValid(value)) {
|
|
40
39
|
return `Path must start with a '.' or '/' (be either a relative or absolute path)`;
|
|
@@ -42,8 +41,8 @@ export async function askPath(name) {
|
|
|
42
41
|
},
|
|
43
42
|
});
|
|
44
43
|
|
|
45
|
-
if (
|
|
46
|
-
|
|
44
|
+
if (isCancel(answer)) {
|
|
45
|
+
cancel("Operation cancelled");
|
|
47
46
|
return process.exit(0);
|
|
48
47
|
}
|
|
49
48
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
|
|
3
|
+
import { answers, printArgInUse } from "#args";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {string | undefined} value
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
function isValid(value) {
|
|
12
|
+
if (!value) return false;
|
|
13
|
+
|
|
14
|
+
return value === "replace" || value === "update";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} projectPath -- the path the project will be generated in
|
|
19
|
+
*/
|
|
20
|
+
export async function askReplaceOrUpdate(projectPath) {
|
|
21
|
+
if (!existsSync(projectPath)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (answers.replaceOrUpdate) {
|
|
26
|
+
if (isValid(answers.replaceOrUpdate)) {
|
|
27
|
+
printArgInUse("replaceOrUpdate", answers.replaceOrUpdate);
|
|
28
|
+
|
|
29
|
+
return answers.replaceOrUpdate;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const answer = await p.select({
|
|
34
|
+
message: "Replace or update at the selected path",
|
|
35
|
+
initialValue: "update",
|
|
36
|
+
options: [
|
|
37
|
+
{
|
|
38
|
+
value: "update",
|
|
39
|
+
label: "update",
|
|
40
|
+
hint: "Updates the project in the target directory, if one exists",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: "replace",
|
|
44
|
+
label: "replace",
|
|
45
|
+
hint: "Deletes the target directory and generates a new project",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (p.isCancel(answer)) {
|
|
51
|
+
p.cancel("Operation cancelled");
|
|
52
|
+
return process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return answer;
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node_modules
|
package/src/layers/git/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { files } from "ember-apply";
|
|
2
1
|
import { hasGit, initGit, isInGit } from "#utils/git.js";
|
|
3
2
|
import { formatLabel } from "#utils/cli.js";
|
|
4
3
|
import { join } from "node:path";
|
|
4
|
+
import { cp } from "node:fs/promises";
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
7
|
label: formatLabel("git init"),
|
|
@@ -24,8 +24,12 @@ export default {
|
|
|
24
24
|
|
|
25
25
|
let initOk = initGit(project.directory);
|
|
26
26
|
if (initOk) {
|
|
27
|
-
|
|
27
|
+
let gitIgnorePath = join(import.meta.dirname, "files/gitignore");
|
|
28
|
+
let targetPath = join(project.directory, ".gitignore");
|
|
29
|
+
|
|
30
|
+
await cp(gitIgnorePath, targetPath, { force: true });
|
|
28
31
|
}
|
|
32
|
+
|
|
29
33
|
return initOk;
|
|
30
34
|
},
|
|
31
35
|
|
|
@@ -12,9 +12,6 @@ import * as QUnit from "qunit";
|
|
|
12
12
|
import { setup } from "qunit-dom";
|
|
13
13
|
import { setupEmberOnerrorValidation, start as qunitStart } from "ember-qunit";
|
|
14
14
|
import { setTesting } from "@embroider/macros";
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
16
|
-
// @ts-expect-error
|
|
17
|
-
import { getGlobalConfig } from "@embroider/macros/src/addon/runtime";
|
|
18
15
|
|
|
19
16
|
import Application from "#app/app";
|
|
20
17
|
import config from "#config";
|
|
@@ -43,19 +40,8 @@ export function start() {
|
|
|
43
40
|
config.locationType = "none";
|
|
44
41
|
config.APP.rootElement = "#ember-testing";
|
|
45
42
|
config.APP.autoboot = false;
|
|
46
|
-
setTesting(true);
|
|
47
|
-
|
|
48
|
-
const theMacrosGlobal = getGlobalConfig();
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Caveats:
|
|
52
|
-
* - https://github.com/embroider-build/embroider/issues/2660
|
|
53
|
-
* - https://github.com/embroider-build/embroider/issues/1998
|
|
54
|
-
*
|
|
55
|
-
*/
|
|
56
|
-
theMacrosGlobal["@embroider/macros"] ||= {};
|
|
57
|
-
theMacrosGlobal["@embroider/macros"].isTesting ||= true;
|
|
58
43
|
|
|
44
|
+
setTesting(true);
|
|
59
45
|
setApplication(Application.create(config.APP));
|
|
60
46
|
setup(QUnit.assert);
|
|
61
47
|
setupEmberOnerrorValidation();
|
package/src/utils/npm.js
CHANGED
|
@@ -16,6 +16,7 @@ export async function getLatest(deps) {
|
|
|
16
16
|
let results = await Promise.all(
|
|
17
17
|
Object.entries(deps).map(async ([dep, range]) => {
|
|
18
18
|
let existing = CACHE[dep]?.[range];
|
|
19
|
+
|
|
19
20
|
if (existing) {
|
|
20
21
|
return [dep, existing];
|
|
21
22
|
}
|
|
@@ -37,6 +38,9 @@ export async function getLatest(deps) {
|
|
|
37
38
|
if (needsLocalLink && dep === "@nullvoxpopuli/ember-vite") {
|
|
38
39
|
version = "link:" + resolve(join(import.meta.dirname, "../../packages/vite"));
|
|
39
40
|
} else {
|
|
41
|
+
if (range == "workspace:*") {
|
|
42
|
+
range = "latest";
|
|
43
|
+
}
|
|
40
44
|
version = await latestVersion(dep, { version: range });
|
|
41
45
|
}
|
|
42
46
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, it, expect, afterAll } from "vitest";
|
|
2
|
+
import { generate, layers, expectIsSetup } from "#test-helpers";
|
|
3
|
+
import { generateProject } from "ember.nvp";
|
|
4
|
+
import { writeFile } from "node:fs/promises";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { rimraf } from "rimraf";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The replace-or-update question only matters when a project already exists
|
|
11
|
+
* at the target path. These tests generate a project, assert the baseline
|
|
12
|
+
* state, then regenerate over it the way the CLI does once the user has
|
|
13
|
+
* answered the question, and assert the resulting project output is correct
|
|
14
|
+
* for each answer.
|
|
15
|
+
*/
|
|
16
|
+
describe("generating over an existing project", () => {
|
|
17
|
+
const prettier = layers.find((layer) => layer.name === "prettier")!;
|
|
18
|
+
const dirs: string[] = [];
|
|
19
|
+
|
|
20
|
+
afterAll(async () => {
|
|
21
|
+
if (process.env.CI) return;
|
|
22
|
+
|
|
23
|
+
for (const dir of dirs) {
|
|
24
|
+
await rimraf(dir, { maxRetries: 3, retryDelay: 100 });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("'update' regenerates in place, keeping unrelated files", async () => {
|
|
29
|
+
const project = await generate({ type: "app", layers: ["prettier"] });
|
|
30
|
+
dirs.push(project.directory);
|
|
31
|
+
|
|
32
|
+
const userFile = join(project.directory, "my-untracked-file.txt");
|
|
33
|
+
await writeFile(userFile, "the user added this");
|
|
34
|
+
|
|
35
|
+
// Baseline: a valid project exists, with the desired layer and the
|
|
36
|
+
// user's own file present.
|
|
37
|
+
expect(existsSync(join(project.directory, "package.json")), "baseline package.json").toBe(true);
|
|
38
|
+
expect(existsSync(userFile), "baseline user file").toBe(true);
|
|
39
|
+
await expectIsSetup(project, prettier);
|
|
40
|
+
|
|
41
|
+
await generateProject(project, "update");
|
|
42
|
+
|
|
43
|
+
// After update: the pre-existing project and the user's file are
|
|
44
|
+
// preserved, and it is still a valid, fully-set-up project.
|
|
45
|
+
expect(existsSync(userFile), "unrelated file preserved by update").toBe(true);
|
|
46
|
+
expect(existsSync(join(project.directory, "package.json"))).toBe(true);
|
|
47
|
+
await expectIsSetup(project, prettier);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("'replace' wipes the directory and produces a fresh project", async () => {
|
|
51
|
+
const project = await generate({ type: "app", layers: ["prettier"] });
|
|
52
|
+
dirs.push(project.directory);
|
|
53
|
+
|
|
54
|
+
const userFile = join(project.directory, "my-untracked-file.txt");
|
|
55
|
+
await writeFile(userFile, "the user added this");
|
|
56
|
+
|
|
57
|
+
// Baseline: a valid project exists, with the desired layer and the
|
|
58
|
+
// user's own file present.
|
|
59
|
+
expect(existsSync(join(project.directory, "package.json")), "baseline package.json").toBe(true);
|
|
60
|
+
expect(existsSync(userFile), "baseline user file").toBe(true);
|
|
61
|
+
await expectIsSetup(project, prettier);
|
|
62
|
+
|
|
63
|
+
await generateProject(project, "replace");
|
|
64
|
+
|
|
65
|
+
// After replace: everything that was there before is gone, replaced by a
|
|
66
|
+
// freshly generated, valid project with the desired layers.
|
|
67
|
+
expect(existsSync(userFile), "stale file removed by replace").toBe(false);
|
|
68
|
+
expect(existsSync(join(project.directory, "package.json"))).toBe(true);
|
|
69
|
+
await expectIsSetup(project, prettier);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("defaults to a non-destructive update when no answer is given", async () => {
|
|
73
|
+
const project = await generate({ type: "app", layers: ["prettier"] });
|
|
74
|
+
dirs.push(project.directory);
|
|
75
|
+
|
|
76
|
+
const userFile = join(project.directory, "my-untracked-file.txt");
|
|
77
|
+
await writeFile(userFile, "the user added this");
|
|
78
|
+
|
|
79
|
+
// Baseline: a valid project exists, with the desired layer and the
|
|
80
|
+
// user's own file present.
|
|
81
|
+
expect(existsSync(join(project.directory, "package.json")), "baseline package.json").toBe(true);
|
|
82
|
+
expect(existsSync(userFile), "baseline user file").toBe(true);
|
|
83
|
+
await expectIsSetup(project, prettier);
|
|
84
|
+
|
|
85
|
+
await generateProject(project);
|
|
86
|
+
|
|
87
|
+
// After a no-arg regenerate: nothing is destroyed.
|
|
88
|
+
expect(existsSync(userFile), "unrelated file preserved by default").toBe(true);
|
|
89
|
+
expect(existsSync(join(project.directory, "package.json"))).toBe(true);
|
|
90
|
+
await expectIsSetup(project, prettier);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, it, afterAll, expect } from "vitest";
|
|
2
|
+
import { generate } from "#test-helpers";
|
|
3
|
+
import { rimraf } from "rimraf";
|
|
4
|
+
import { execa } from "execa";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The replace-or-update question only matters when a project already exists
|
|
8
|
+
* at the target path. These tests generate a project, assert the baseline
|
|
9
|
+
* state, then regenerate over it the way the CLI does once the user has
|
|
10
|
+
* answered the question, and assert the resulting project output is correct
|
|
11
|
+
* for each answer.
|
|
12
|
+
*/
|
|
13
|
+
describe("layer: qunit", () => {
|
|
14
|
+
const dirs: string[] = [];
|
|
15
|
+
|
|
16
|
+
afterAll(async () => {
|
|
17
|
+
if (process.env.CI) return;
|
|
18
|
+
|
|
19
|
+
for (const dir of dirs) {
|
|
20
|
+
await rimraf(dir, { maxRetries: 3, retryDelay: 100 });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("it boots and run tests", async () => {
|
|
25
|
+
const project = await generate({ type: "app", layers: ["qunit"] });
|
|
26
|
+
dirs.push(project.directory);
|
|
27
|
+
|
|
28
|
+
let install = await execa("pnpm install", { cwd: project.directory, shell: true });
|
|
29
|
+
expect(install.exitCode).toBe(0);
|
|
30
|
+
|
|
31
|
+
let test = await execa("pnpm test", { cwd: project.directory, shell: true });
|
|
32
|
+
expect(test.exitCode).toBe(0);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
21
|
-
fi
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
-
|
|
4
|
-
case `uname` in
|
|
5
|
-
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
-
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
-
basedir=`cygpath -w "$basedir"`
|
|
8
|
-
fi
|
|
9
|
-
;;
|
|
10
|
-
esac
|
|
11
|
-
|
|
12
|
-
if [ -z "$NODE_PATH" ]; then
|
|
13
|
-
export NODE_PATH="/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/vite@8.0.14_@types+node@25.0.8_esbuild@0.27.2_jiti@2.6.1_terser@5.46.0/node_modules/vite/bin/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/vite@8.0.14_@types+node@25.0.8_esbuild@0.27.2_jiti@2.6.1_terser@5.46.0/node_modules/vite/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/vite@8.0.14_@types+node@25.0.8_esbuild@0.27.2_jiti@2.6.1_terser@5.46.0/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/node_modules"
|
|
14
|
-
else
|
|
15
|
-
export NODE_PATH="/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/vite@8.0.14_@types+node@25.0.8_esbuild@0.27.2_jiti@2.6.1_terser@5.46.0/node_modules/vite/bin/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/vite@8.0.14_@types+node@25.0.8_esbuild@0.27.2_jiti@2.6.1_terser@5.46.0/node_modules/vite/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/vite@8.0.14_@types+node@25.0.8_esbuild@0.27.2_jiti@2.6.1_terser@5.46.0/node_modules:/home/runner/work/ember.nvp/ember.nvp/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
-
fi
|
|
17
|
-
if [ -x "$basedir/node" ]; then
|
|
18
|
-
exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@"
|
|
19
|
-
else
|
|
20
|
-
exec node "$basedir/../vite/bin/vite.js" "$@"
|
|
21
|
-
fi
|