@tyyyho/treg 0.1.2 → 0.1.6
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/README.md +52 -45
- package/dist/init-project/cli.js +228 -0
- package/dist/init-project/frameworks/index.js +39 -0
- package/dist/init-project/frameworks/next/index.js +9 -0
- package/dist/init-project/frameworks/node/index.js +8 -0
- package/dist/init-project/frameworks/nuxt/index.js +9 -0
- package/dist/init-project/frameworks/react/index.js +27 -0
- package/dist/init-project/frameworks/react/v18/index.js +6 -0
- package/dist/init-project/frameworks/react/v19/index.js +6 -0
- package/dist/init-project/frameworks/svelte/index.js +9 -0
- package/dist/init-project/frameworks/vue/index.js +9 -0
- package/dist/init-project/index.js +65 -0
- package/dist/init-project/mrm-core.js +3 -0
- package/dist/init-project/mrm-rules/ai-skills.js +200 -0
- package/dist/init-project/mrm-rules/format.js +44 -0
- package/dist/init-project/mrm-rules/husky.js +61 -0
- package/dist/init-project/mrm-rules/index.js +33 -0
- package/dist/init-project/mrm-rules/lint.js +16 -0
- package/dist/init-project/mrm-rules/shared.js +91 -0
- package/dist/init-project/mrm-rules/test-jest.js +48 -0
- package/dist/init-project/mrm-rules/test-vitest.js +46 -0
- package/dist/init-project/mrm-rules/typescript.js +40 -0
- package/dist/init-project/package-manager.js +57 -0
- package/dist/init-project/types.js +1 -0
- package/dist/init-project/utils.js +9 -0
- package/dist/init-project.js +6 -0
- package/dist/package.json +3 -0
- package/package.json +10 -5
- package/scripts/init-project/cli.mjs +0 -173
- package/scripts/init-project/cli.test.mjs +0 -116
- package/scripts/init-project/frameworks/index.mjs +0 -48
- package/scripts/init-project/frameworks/next/index.mjs +0 -10
- package/scripts/init-project/frameworks/node/index.mjs +0 -8
- package/scripts/init-project/frameworks/nuxt/index.mjs +0 -10
- package/scripts/init-project/frameworks/react/index.mjs +0 -35
- package/scripts/init-project/frameworks/react/v18/index.mjs +0 -6
- package/scripts/init-project/frameworks/react/v19/index.mjs +0 -6
- package/scripts/init-project/frameworks/svelte/index.mjs +0 -10
- package/scripts/init-project/frameworks/vue/index.mjs +0 -10
- package/scripts/init-project/frameworks.test.mjs +0 -63
- package/scripts/init-project/index.mjs +0 -89
- package/scripts/init-project/mrm-core.mjs +0 -5
- package/scripts/init-project/mrm-rules/ai-skills.mjs +0 -220
- package/scripts/init-project/mrm-rules/ai-skills.test.mjs +0 -91
- package/scripts/init-project/mrm-rules/format.mjs +0 -55
- package/scripts/init-project/mrm-rules/husky.mjs +0 -78
- package/scripts/init-project/mrm-rules/index.mjs +0 -35
- package/scripts/init-project/mrm-rules/lint.mjs +0 -18
- package/scripts/init-project/mrm-rules/shared.mjs +0 -61
- package/scripts/init-project/mrm-rules/test-jest.mjs +0 -75
- package/scripts/init-project/mrm-rules/test-vitest.mjs +0 -64
- package/scripts/init-project/mrm-rules/typescript.mjs +0 -44
- package/scripts/init-project/package-manager.mjs +0 -68
- package/scripts/init-project/package-manager.test.mjs +0 -21
- package/scripts/init-project/utils.mjs +0 -12
- package/scripts/init-project/utils.test.mjs +0 -22
- package/scripts/init-project.mjs +0 -7
package/README.md
CHANGED
|
@@ -1,20 +1,46 @@
|
|
|
1
1
|
# @tyyyho/treg
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`treg` is a CLI for quickly setting up project tooling conventions in an existing repository.
|
|
4
|
+
It applies infra setup such as lint, format, TypeScript, test, husky, and AI skill guidance.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## Quick Start
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
```bash
|
|
9
|
+
pnpm dlx @tyyyho/treg init --framework react
|
|
10
|
+
# or
|
|
11
|
+
npx @tyyyho/treg init --framework react
|
|
12
|
+
```
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
`init` requires `--framework`.
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
10
17
|
|
|
11
18
|
```bash
|
|
12
|
-
|
|
13
|
-
# or
|
|
14
|
-
npx @tyyyho/treg init <project-dir> --framework react
|
|
19
|
+
npx @tyyyho/treg <command> [options]
|
|
15
20
|
```
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
- `init`: Initialize infra rules (requires `--framework`)
|
|
23
|
+
- `add`: Add selected infra features to an existing project
|
|
24
|
+
- `list`: List supported frameworks, features, and test runners
|
|
25
|
+
|
|
26
|
+
## Options
|
|
27
|
+
|
|
28
|
+
- `--framework <node|react|next|vue|svelte|nuxt>`: Target framework
|
|
29
|
+
- `--framework-version <major>`: Optional major version hint (react only)
|
|
30
|
+
- `--features <lint,format,typescript,test,husky>`: Features to install (defaults to all)
|
|
31
|
+
- `--dir <path>`: Target directory (defaults to current directory)
|
|
32
|
+
- `--test-runner <jest|vitest>`: Test runner when test feature is enabled
|
|
33
|
+
- `--pm <pnpm|npm|yarn|auto>`: Package manager (auto-detected by default)
|
|
34
|
+
- `--force`: Overwrite existing config files
|
|
35
|
+
- `--dry-run`: Print full plan without writing files
|
|
36
|
+
- `--skip-husky-install`: Skip husky install command
|
|
37
|
+
- `--skills`: Update existing `AGENTS.md`/`CLAUDE.md` with skill guidance (enabled by default)
|
|
38
|
+
- `--no-skills`: Disable skill guidance updates
|
|
39
|
+
- `--help`: Show help
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
Default feature set:
|
|
18
44
|
|
|
19
45
|
- `husky`
|
|
20
46
|
- `typescript`
|
|
@@ -22,71 +48,52 @@ By default, all features are applied:
|
|
|
22
48
|
- `format`
|
|
23
49
|
- `test`
|
|
24
50
|
|
|
25
|
-
## Options
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npx @tyyyho/treg <command> [projectDir] [options]
|
|
29
|
-
|
|
30
|
-
init Initialize infra rules (requires --framework)
|
|
31
|
-
add Add selected infra features
|
|
32
|
-
list List supported targets
|
|
33
|
-
|
|
34
|
-
--framework <node|react|next|vue|svelte|nuxt>
|
|
35
|
-
Target framework
|
|
36
|
-
--framework-version <major> Optional major version hint (currently react only)
|
|
37
|
-
--pm <pnpm|npm|yarn|auto> Package manager (auto-detected by default)
|
|
38
|
-
--features <lint,format,typescript,test,husky>
|
|
39
|
-
Features to install (all selected by default)
|
|
40
|
-
--test-runner <jest|vitest> Test runner when test feature is enabled
|
|
41
|
-
--force Overwrite existing config files
|
|
42
|
-
--dry-run Show planned changes without writing files
|
|
43
|
-
--skip-husky-install Do not run husky install
|
|
44
|
-
--skills Update AGENTS.md/CLAUDE.md with feature skill guidance
|
|
45
|
-
--help Show help
|
|
46
|
-
```
|
|
47
|
-
|
|
48
51
|
## Examples
|
|
49
52
|
|
|
50
53
|
Initialize a React project:
|
|
51
54
|
|
|
52
55
|
```bash
|
|
53
|
-
npx @tyyyho/treg init
|
|
56
|
+
npx @tyyyho/treg init --framework react
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
Add only lint
|
|
59
|
+
Add only lint + format:
|
|
57
60
|
|
|
58
61
|
```bash
|
|
59
|
-
npx @tyyyho/treg add
|
|
62
|
+
npx @tyyyho/treg add --features lint,format
|
|
60
63
|
```
|
|
61
64
|
|
|
62
|
-
Use Vitest:
|
|
65
|
+
Use Vitest for test feature:
|
|
63
66
|
|
|
64
67
|
```bash
|
|
65
|
-
npx @tyyyho/treg init
|
|
68
|
+
npx @tyyyho/treg init --framework node --features test --test-runner vitest
|
|
66
69
|
```
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
Use react major version variant:
|
|
69
72
|
|
|
70
73
|
```bash
|
|
71
|
-
npx @tyyyho/treg init
|
|
74
|
+
npx @tyyyho/treg init --framework react --framework-version 18
|
|
72
75
|
```
|
|
73
76
|
|
|
74
77
|
Preview changes only:
|
|
75
78
|
|
|
76
79
|
```bash
|
|
77
|
-
npx @tyyyho/treg init
|
|
80
|
+
npx @tyyyho/treg init --framework react --dry-run
|
|
78
81
|
```
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
Update AI skill guidance:
|
|
81
84
|
|
|
82
85
|
```bash
|
|
83
|
-
npx @tyyyho/treg add
|
|
86
|
+
npx @tyyyho/treg add --features lint,format,husky
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
Target a different directory explicitly:
|
|
87
90
|
|
|
88
91
|
```bash
|
|
89
|
-
|
|
90
|
-
pnpm run prepublishOnly
|
|
91
|
-
npm publish --access public
|
|
92
|
+
npx @tyyyho/treg init --framework react --dir ./packages/web
|
|
92
93
|
```
|
|
94
|
+
|
|
95
|
+
## Notes
|
|
96
|
+
|
|
97
|
+
- `init` requires `--framework`.
|
|
98
|
+
- `add` lets you install only the features you specify.
|
|
99
|
+
- `--dry-run` prints the full plan and does not write files.
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
const ALLOWED_COMMANDS = ["init", "add", "list"];
|
|
2
|
+
const ALLOWED_PACKAGE_MANAGERS = [
|
|
3
|
+
"pnpm",
|
|
4
|
+
"npm",
|
|
5
|
+
"yarn",
|
|
6
|
+
"auto",
|
|
7
|
+
];
|
|
8
|
+
const ALLOWED_FRAMEWORKS = [
|
|
9
|
+
"node",
|
|
10
|
+
"react",
|
|
11
|
+
"next",
|
|
12
|
+
"vue",
|
|
13
|
+
"svelte",
|
|
14
|
+
"nuxt",
|
|
15
|
+
];
|
|
16
|
+
const ALLOWED_FEATURES = [
|
|
17
|
+
"lint",
|
|
18
|
+
"format",
|
|
19
|
+
"typescript",
|
|
20
|
+
"test",
|
|
21
|
+
"husky",
|
|
22
|
+
];
|
|
23
|
+
const ALLOWED_TEST_RUNNERS = ["jest", "vitest"];
|
|
24
|
+
export const USAGE = `Usage: treg <command> [options]
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
init Initialize infra rules in a project (requires --framework)
|
|
28
|
+
add Add selected infra features to an existing project
|
|
29
|
+
list List supported frameworks, features, and test runners
|
|
30
|
+
|
|
31
|
+
Options:
|
|
32
|
+
--framework <node|react|next|vue|svelte|nuxt>
|
|
33
|
+
Target framework
|
|
34
|
+
--framework-version <major> Optional framework major version hint
|
|
35
|
+
--features <lint,format,typescript,test,husky>
|
|
36
|
+
Features to install (all selected by default)
|
|
37
|
+
--dir <path> Target directory (defaults to current directory)
|
|
38
|
+
--test-runner <jest|vitest> Test runner when test feature is enabled
|
|
39
|
+
--pm <pnpm|npm|yarn|auto> Package manager (auto-detected if omitted)
|
|
40
|
+
--force Overwrite existing config files
|
|
41
|
+
--dry-run Print planned changes without writing files
|
|
42
|
+
--skip-husky-install Do not run husky install
|
|
43
|
+
--skills Update AGENTS.md/CLAUDE.md with feature skill guidance (default: enabled)
|
|
44
|
+
--no-skills Disable AGENTS.md/CLAUDE.md skill guidance updates
|
|
45
|
+
-h, --help Show help
|
|
46
|
+
`;
|
|
47
|
+
function includes(allowed, value) {
|
|
48
|
+
return allowed.includes(value);
|
|
49
|
+
}
|
|
50
|
+
function isCommandName(value) {
|
|
51
|
+
return includes(ALLOWED_COMMANDS, value);
|
|
52
|
+
}
|
|
53
|
+
function isPackageManagerOption(value) {
|
|
54
|
+
return includes(ALLOWED_PACKAGE_MANAGERS, value);
|
|
55
|
+
}
|
|
56
|
+
function isFrameworkId(value) {
|
|
57
|
+
return includes(ALLOWED_FRAMEWORKS, value);
|
|
58
|
+
}
|
|
59
|
+
function isFeatureName(value) {
|
|
60
|
+
return includes(ALLOWED_FEATURES, value);
|
|
61
|
+
}
|
|
62
|
+
function isTestRunner(value) {
|
|
63
|
+
return includes(ALLOWED_TEST_RUNNERS, value);
|
|
64
|
+
}
|
|
65
|
+
export function parseArgs(argv) {
|
|
66
|
+
const options = {
|
|
67
|
+
command: "init",
|
|
68
|
+
projectDir: null,
|
|
69
|
+
framework: null,
|
|
70
|
+
frameworkVersion: null,
|
|
71
|
+
features: [],
|
|
72
|
+
testRunner: "jest",
|
|
73
|
+
pm: null,
|
|
74
|
+
force: false,
|
|
75
|
+
dryRun: false,
|
|
76
|
+
skipHuskyInstall: false,
|
|
77
|
+
skills: true,
|
|
78
|
+
help: false,
|
|
79
|
+
};
|
|
80
|
+
let cursor = 0;
|
|
81
|
+
const firstArg = argv[0];
|
|
82
|
+
if (firstArg && isCommandName(firstArg)) {
|
|
83
|
+
options.command = firstArg;
|
|
84
|
+
cursor = 1;
|
|
85
|
+
}
|
|
86
|
+
for (let i = cursor; i < argv.length; i += 1) {
|
|
87
|
+
const arg = argv[i];
|
|
88
|
+
if (!arg) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (arg === "-h" || arg === "--help") {
|
|
92
|
+
options.help = true;
|
|
93
|
+
}
|
|
94
|
+
else if (arg === "--framework") {
|
|
95
|
+
options.framework = readFlagValue(argv, i, "--framework");
|
|
96
|
+
i += 1;
|
|
97
|
+
}
|
|
98
|
+
else if (arg.startsWith("--framework=")) {
|
|
99
|
+
options.framework = readInlineFlagValue(arg, "--framework");
|
|
100
|
+
}
|
|
101
|
+
else if (arg === "--framework-version") {
|
|
102
|
+
options.frameworkVersion = readFlagValue(argv, i, "--framework-version");
|
|
103
|
+
i += 1;
|
|
104
|
+
}
|
|
105
|
+
else if (arg.startsWith("--framework-version=")) {
|
|
106
|
+
options.frameworkVersion = readInlineFlagValue(arg, "--framework-version");
|
|
107
|
+
}
|
|
108
|
+
else if (arg === "--features") {
|
|
109
|
+
options.features.push(...parseCsvValue(argv[i + 1], "--features"));
|
|
110
|
+
i += 1;
|
|
111
|
+
}
|
|
112
|
+
else if (arg.startsWith("--features=")) {
|
|
113
|
+
options.features.push(...parseCsvValue(readInlineFlagValue(arg, "--features"), "--features"));
|
|
114
|
+
}
|
|
115
|
+
else if (arg === "--dir") {
|
|
116
|
+
options.projectDir = readFlagValue(argv, i, "--dir");
|
|
117
|
+
i += 1;
|
|
118
|
+
}
|
|
119
|
+
else if (arg.startsWith("--dir=")) {
|
|
120
|
+
options.projectDir = readInlineFlagValue(arg, "--dir");
|
|
121
|
+
}
|
|
122
|
+
else if (arg === "--test-runner") {
|
|
123
|
+
options.testRunner = readFlagValue(argv, i, "--test-runner");
|
|
124
|
+
i += 1;
|
|
125
|
+
}
|
|
126
|
+
else if (arg.startsWith("--test-runner=")) {
|
|
127
|
+
options.testRunner = readInlineFlagValue(arg, "--test-runner");
|
|
128
|
+
}
|
|
129
|
+
else if (arg === "--pm") {
|
|
130
|
+
options.pm = readFlagValue(argv, i, "--pm");
|
|
131
|
+
i += 1;
|
|
132
|
+
}
|
|
133
|
+
else if (arg.startsWith("--pm=")) {
|
|
134
|
+
options.pm = readInlineFlagValue(arg, "--pm");
|
|
135
|
+
}
|
|
136
|
+
else if (arg === "--force") {
|
|
137
|
+
options.force = true;
|
|
138
|
+
}
|
|
139
|
+
else if (arg === "--dry-run") {
|
|
140
|
+
options.dryRun = true;
|
|
141
|
+
}
|
|
142
|
+
else if (arg === "--skip-husky-install") {
|
|
143
|
+
options.skipHuskyInstall = true;
|
|
144
|
+
}
|
|
145
|
+
else if (arg === "--skills") {
|
|
146
|
+
options.skills = true;
|
|
147
|
+
}
|
|
148
|
+
else if (arg === "--no-skills") {
|
|
149
|
+
options.skills = false;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
validateParsedOptions(options);
|
|
156
|
+
return options;
|
|
157
|
+
}
|
|
158
|
+
function readFlagValue(argv, index, flagName) {
|
|
159
|
+
const value = argv[index + 1];
|
|
160
|
+
if (!value) {
|
|
161
|
+
throw new Error(`Missing value for ${flagName}`);
|
|
162
|
+
}
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
function readInlineFlagValue(arg, flagName) {
|
|
166
|
+
const [, rawValue] = arg.split("=", 2);
|
|
167
|
+
if (!rawValue) {
|
|
168
|
+
throw new Error(`Missing value for ${flagName}`);
|
|
169
|
+
}
|
|
170
|
+
return rawValue;
|
|
171
|
+
}
|
|
172
|
+
function parseCsvValue(rawValue, flagName) {
|
|
173
|
+
if (!rawValue) {
|
|
174
|
+
throw new Error(`Missing value for ${flagName}`);
|
|
175
|
+
}
|
|
176
|
+
return rawValue
|
|
177
|
+
.split(",")
|
|
178
|
+
.map(item => item.trim())
|
|
179
|
+
.filter(Boolean);
|
|
180
|
+
}
|
|
181
|
+
function validateParsedOptions(options) {
|
|
182
|
+
if (!isCommandName(options.command)) {
|
|
183
|
+
throw new Error(`Unsupported command: ${options.command}`);
|
|
184
|
+
}
|
|
185
|
+
if (options.projectDir === "") {
|
|
186
|
+
throw new Error("Missing value for --dir");
|
|
187
|
+
}
|
|
188
|
+
if (options.pm && !isPackageManagerOption(options.pm)) {
|
|
189
|
+
throw new Error(`Unsupported package manager: ${options.pm}`);
|
|
190
|
+
}
|
|
191
|
+
if (options.framework && !isFrameworkId(options.framework)) {
|
|
192
|
+
throw new Error(`Unsupported framework: ${options.framework}`);
|
|
193
|
+
}
|
|
194
|
+
if (options.frameworkVersion && !/^\d+$/.test(options.frameworkVersion)) {
|
|
195
|
+
throw new Error("Invalid --framework-version: major version must be numeric");
|
|
196
|
+
}
|
|
197
|
+
if (options.frameworkVersion &&
|
|
198
|
+
options.framework &&
|
|
199
|
+
options.framework !== "react") {
|
|
200
|
+
throw new Error(`Unsupported --framework-version for framework: ${options.framework}`);
|
|
201
|
+
}
|
|
202
|
+
if (!isTestRunner(options.testRunner)) {
|
|
203
|
+
throw new Error(`Unsupported test runner: ${options.testRunner}`);
|
|
204
|
+
}
|
|
205
|
+
for (const feature of options.features) {
|
|
206
|
+
if (!isFeatureName(feature)) {
|
|
207
|
+
throw new Error(`Unsupported feature in --features: ${feature}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (options.command === "init" && !options.help && !options.framework) {
|
|
211
|
+
throw new Error("Missing required option: --framework");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
export function resolveFeatures(options) {
|
|
215
|
+
const selected = new Set(options.features.length > 0 ? options.features : ALLOWED_FEATURES);
|
|
216
|
+
return {
|
|
217
|
+
lint: selected.has("lint"),
|
|
218
|
+
format: selected.has("format"),
|
|
219
|
+
typescript: selected.has("typescript"),
|
|
220
|
+
test: selected.has("test"),
|
|
221
|
+
husky: selected.has("husky"),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
export function printSupportedTargets() {
|
|
225
|
+
console.log("Frameworks: node, react, next, vue, svelte, nuxt");
|
|
226
|
+
console.log("Features: lint, format, typescript, test, husky");
|
|
227
|
+
console.log("Test runners: jest, vitest");
|
|
228
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { nextFramework } from "./next/index.js";
|
|
2
|
+
import { nodeFramework } from "./node/index.js";
|
|
3
|
+
import { nuxtFramework } from "./nuxt/index.js";
|
|
4
|
+
import { reactFramework, resolveReactFramework } from "./react/index.js";
|
|
5
|
+
import { svelteFramework } from "./svelte/index.js";
|
|
6
|
+
import { vueFramework } from "./vue/index.js";
|
|
7
|
+
const FRAMEWORK_REGISTRY = {
|
|
8
|
+
next: nextFramework,
|
|
9
|
+
node: nodeFramework,
|
|
10
|
+
nuxt: nuxtFramework,
|
|
11
|
+
react: reactFramework,
|
|
12
|
+
svelte: svelteFramework,
|
|
13
|
+
vue: vueFramework,
|
|
14
|
+
};
|
|
15
|
+
const FRAMEWORK_DETECT_ORDER = [
|
|
16
|
+
nuxtFramework,
|
|
17
|
+
nextFramework,
|
|
18
|
+
reactFramework,
|
|
19
|
+
vueFramework,
|
|
20
|
+
svelteFramework,
|
|
21
|
+
nodeFramework,
|
|
22
|
+
];
|
|
23
|
+
export function resolveFramework(frameworkArg, frameworkVersion, packageJson) {
|
|
24
|
+
if (frameworkArg === "react") {
|
|
25
|
+
return resolveReactFramework(packageJson, frameworkVersion);
|
|
26
|
+
}
|
|
27
|
+
if (frameworkArg) {
|
|
28
|
+
return FRAMEWORK_REGISTRY[frameworkArg];
|
|
29
|
+
}
|
|
30
|
+
const detected = detectFramework(packageJson);
|
|
31
|
+
if (detected.id === "react") {
|
|
32
|
+
return resolveReactFramework(packageJson, frameworkVersion);
|
|
33
|
+
}
|
|
34
|
+
return detected;
|
|
35
|
+
}
|
|
36
|
+
export function detectFramework(packageJson) {
|
|
37
|
+
const matched = FRAMEWORK_DETECT_ORDER.find(framework => framework.matches(packageJson));
|
|
38
|
+
return matched ?? nodeFramework;
|
|
39
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { hasPackage } from "../../utils.js";
|
|
2
|
+
export const nextFramework = {
|
|
3
|
+
id: "next",
|
|
4
|
+
testEnvironment: "jsdom",
|
|
5
|
+
tsRequiredExcludes: [".next", "dist", "coverage", "jest.config.js", "public"],
|
|
6
|
+
matches(packageJson) {
|
|
7
|
+
return hasPackage(packageJson, "next");
|
|
8
|
+
},
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { hasPackage } from "../../utils.js";
|
|
2
|
+
export const nuxtFramework = {
|
|
3
|
+
id: "nuxt",
|
|
4
|
+
testEnvironment: "jsdom",
|
|
5
|
+
tsRequiredExcludes: [".nuxt", ".output", "dist", "coverage", "public"],
|
|
6
|
+
matches(packageJson) {
|
|
7
|
+
return hasPackage(packageJson, "nuxt");
|
|
8
|
+
},
|
|
9
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { hasPackage } from "../../utils.js";
|
|
2
|
+
import { reactV18Framework } from "./v18/index.js";
|
|
3
|
+
import { reactV19Framework } from "./v19/index.js";
|
|
4
|
+
export const reactFramework = {
|
|
5
|
+
id: "react",
|
|
6
|
+
variant: "v19",
|
|
7
|
+
testEnvironment: "jsdom",
|
|
8
|
+
tsRequiredExcludes: ["dist", "coverage", "jest.config.js", "public"],
|
|
9
|
+
matches(packageJson) {
|
|
10
|
+
return (hasPackage(packageJson, "react") || hasPackage(packageJson, "react-dom"));
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
const REACT_VARIANTS = {
|
|
14
|
+
"18": reactV18Framework,
|
|
15
|
+
"19": reactV19Framework,
|
|
16
|
+
};
|
|
17
|
+
export function resolveReactFramework(packageJson, frameworkVersion) {
|
|
18
|
+
if (frameworkVersion && REACT_VARIANTS[frameworkVersion]) {
|
|
19
|
+
return REACT_VARIANTS[frameworkVersion];
|
|
20
|
+
}
|
|
21
|
+
const detected = packageJson?.dependencies?.react ?? packageJson?.devDependencies?.react;
|
|
22
|
+
const major = typeof detected === "string" ? detected.match(/\d+/)?.[0] : null;
|
|
23
|
+
if (major && REACT_VARIANTS[major]) {
|
|
24
|
+
return REACT_VARIANTS[major];
|
|
25
|
+
}
|
|
26
|
+
return reactFramework;
|
|
27
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { parseArgs, printSupportedTargets, resolveFeatures, USAGE, } from "./cli.js";
|
|
5
|
+
import { resolveFramework } from "./frameworks/index.js";
|
|
6
|
+
import { runFeatureRules } from "./mrm-rules/index.js";
|
|
7
|
+
import { detectPackageManager, runScript } from "./package-manager.js";
|
|
8
|
+
import { formatStep } from "./utils.js";
|
|
9
|
+
const TOTAL_STEPS = 3;
|
|
10
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
11
|
+
let options;
|
|
12
|
+
try {
|
|
13
|
+
options = parseArgs(argv);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error(error.message ?? error);
|
|
17
|
+
console.log(USAGE);
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (options.help) {
|
|
22
|
+
console.log(USAGE);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (options.command === "list") {
|
|
26
|
+
printSupportedTargets();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const projectDir = path.resolve(options.projectDir ?? process.cwd());
|
|
30
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
31
|
+
if (!existsSync(packageJsonPath)) {
|
|
32
|
+
console.error(`package.json not found in ${projectDir}`);
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
|
|
37
|
+
const pm = !options.pm || options.pm === "auto"
|
|
38
|
+
? detectPackageManager(projectDir)
|
|
39
|
+
: options.pm;
|
|
40
|
+
const framework = resolveFramework(options.framework, options.frameworkVersion, packageJson);
|
|
41
|
+
if (options.frameworkVersion && framework.id !== "react") {
|
|
42
|
+
console.error(`Unsupported --framework-version for framework: ${framework.id}`);
|
|
43
|
+
process.exitCode = 1;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const enabledFeatures = resolveFeatures(options);
|
|
47
|
+
const context = {
|
|
48
|
+
...options,
|
|
49
|
+
projectDir,
|
|
50
|
+
pm,
|
|
51
|
+
framework,
|
|
52
|
+
enabledFeatures,
|
|
53
|
+
};
|
|
54
|
+
console.log(formatStep(1, TOTAL_STEPS, "Resolve plan", options.dryRun));
|
|
55
|
+
console.log(`${options.dryRun ? "[dry-run] " : ""}Framework=${framework.id}${framework.variant ? `/${framework.variant}` : ""}, features=${Object.entries(enabledFeatures)
|
|
56
|
+
.filter(([, enabled]) => enabled)
|
|
57
|
+
.map(([name]) => name)
|
|
58
|
+
.join(", ")}, testRunner=${options.testRunner}`);
|
|
59
|
+
console.log(formatStep(2, TOTAL_STEPS, "Run mrm rules", options.dryRun));
|
|
60
|
+
await runFeatureRules(context);
|
|
61
|
+
console.log(formatStep(3, TOTAL_STEPS, "Finalize", options.dryRun));
|
|
62
|
+
if (enabledFeatures.format) {
|
|
63
|
+
runScript(pm, "format", projectDir, options.dryRun);
|
|
64
|
+
}
|
|
65
|
+
}
|