crdncli 1.0.3 → 1.0.5
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/commands/addFeature.js +69 -7
- package/lib/cli.js +7 -1
- package/package.json +38 -35
package/commands/addFeature.js
CHANGED
|
@@ -4,14 +4,18 @@ const chalk = require("chalk");
|
|
|
4
4
|
const readline = require("readline");
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* crdn add-feature <name>
|
|
7
|
+
* crdn add-feature <name> [--preset]
|
|
8
8
|
*
|
|
9
9
|
* - Must be run from the root of a CRDN Next.js app (the app created by `create-crdn-app`)
|
|
10
10
|
* - Copies the template feature from `crdn/templates/feature` into `src/features/<name>`
|
|
11
11
|
* - Performs simple text replacements so you can base new features on the auth example
|
|
12
|
+
* - Optional: `--preset` includes both API and hooks; when omitted, those layers
|
|
13
|
+
* are stripped from generated files and removed from disk.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
|
-
function run(featureName) {
|
|
16
|
+
function run(featureName, options = {}) {
|
|
17
|
+
const { preset } = options;
|
|
18
|
+
|
|
15
19
|
const appRoot = process.cwd();
|
|
16
20
|
|
|
17
21
|
const srcDir = path.join(appRoot, "src");
|
|
@@ -58,7 +62,7 @@ function run(featureName) {
|
|
|
58
62
|
const featureNamePascal =
|
|
59
63
|
featureName.charAt(0).toUpperCase() + featureName.slice(1);
|
|
60
64
|
|
|
61
|
-
const replaceInFile = (filePath) => {
|
|
65
|
+
const replaceInFile = (filePath, options) => {
|
|
62
66
|
if (!fs.existsSync(filePath)) return;
|
|
63
67
|
|
|
64
68
|
let content = fs.readFileSync(filePath, "utf8");
|
|
@@ -91,6 +95,37 @@ function run(featureName) {
|
|
|
91
95
|
.replace(/\bfeatureApi\b/g, `${featureNameCamel}Api`)
|
|
92
96
|
.replace(/\buseFeature\b/g, `use${featureNamePascal}`);
|
|
93
97
|
|
|
98
|
+
// Without preset, strip API re-exports and related imports from generated sources.
|
|
99
|
+
if (!options.preset) {
|
|
100
|
+
content = content.replace(
|
|
101
|
+
/export\s+\*\s+as\s+\w+\s+from\s+["']\.\/api\/.*["'];?\n?/g,
|
|
102
|
+
""
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
content = content.replace(
|
|
106
|
+
new RegExp(`import .*${featureNameCamel}Api.*\\n`, "g"),
|
|
107
|
+
""
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Without preset, strip hooks re-exports and related imports from generated sources.
|
|
112
|
+
// Match only a multiline `export {\n ... } from "./hooks/..."` block so we do not merge
|
|
113
|
+
// with the single-line component export `export { X } from "./components/..."`.
|
|
114
|
+
if (!options.preset) {
|
|
115
|
+
content = content.replace(
|
|
116
|
+
/export\s*\{\s*\n[\s\S]*?\}\s*from\s*["']\.\/hooks\/[^"']+["'];?\s*\n?/g,
|
|
117
|
+
""
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
content = content.replace(
|
|
121
|
+
new RegExp(`import .*use${featureNamePascal}.*\\n`, "g"),
|
|
122
|
+
""
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Collapse runs of blank lines left after removals.
|
|
127
|
+
content = content.replace(/\n{3,}/g, "\n\n");
|
|
128
|
+
|
|
94
129
|
fs.writeFileSync(filePath, content, "utf8");
|
|
95
130
|
};
|
|
96
131
|
|
|
@@ -128,7 +163,7 @@ function run(featureName) {
|
|
|
128
163
|
fullPath = newPath;
|
|
129
164
|
}
|
|
130
165
|
|
|
131
|
-
replaceInFile(fullPath);
|
|
166
|
+
replaceInFile(fullPath, options);
|
|
132
167
|
}
|
|
133
168
|
}
|
|
134
169
|
};
|
|
@@ -162,6 +197,27 @@ function run(featureName) {
|
|
|
162
197
|
walk(appTestsFeatureDir);
|
|
163
198
|
}
|
|
164
199
|
|
|
200
|
+
// Remove optional api/hooks files when those modes were not requested.
|
|
201
|
+
const apiFilePath = path.join(
|
|
202
|
+
targetFeatureDir,
|
|
203
|
+
"api",
|
|
204
|
+
`${featureNameCamel}Api.ts`
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const hooksFilePath = path.join(
|
|
208
|
+
targetFeatureDir,
|
|
209
|
+
"hooks",
|
|
210
|
+
`use${featureNamePascal}.ts`
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
if (!preset && fs.existsSync(apiFilePath)) {
|
|
214
|
+
fs.removeSync(apiFilePath);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!preset && fs.existsSync(hooksFilePath)) {
|
|
218
|
+
fs.removeSync(hooksFilePath);
|
|
219
|
+
}
|
|
220
|
+
|
|
165
221
|
console.log(
|
|
166
222
|
chalk.green(
|
|
167
223
|
`Feature \`${featureName}\` created at src/features/${featureName}.`
|
|
@@ -169,9 +225,15 @@ function run(featureName) {
|
|
|
169
225
|
);
|
|
170
226
|
}
|
|
171
227
|
|
|
172
|
-
module.exports = function addFeature(featureName) {
|
|
228
|
+
module.exports = function addFeature(featureName, commanderOpts = {}) {
|
|
229
|
+
const args = process.argv.slice(2);
|
|
230
|
+
|
|
231
|
+
const options = {
|
|
232
|
+
preset: commanderOpts.preset ?? args.includes("--preset"),
|
|
233
|
+
};
|
|
234
|
+
|
|
173
235
|
if (featureName) {
|
|
174
|
-
run(featureName);
|
|
236
|
+
run(featureName, options);
|
|
175
237
|
return;
|
|
176
238
|
}
|
|
177
239
|
|
|
@@ -189,6 +251,6 @@ module.exports = function addFeature(featureName) {
|
|
|
189
251
|
process.exit(1);
|
|
190
252
|
}
|
|
191
253
|
|
|
192
|
-
run(trimmed);
|
|
254
|
+
run(trimmed, options);
|
|
193
255
|
});
|
|
194
256
|
};
|
package/lib/cli.js
CHANGED
|
@@ -16,7 +16,13 @@ function createProgram() {
|
|
|
16
16
|
.command("add-feature")
|
|
17
17
|
.description("Create a new feature from template")
|
|
18
18
|
.argument("[name]")
|
|
19
|
-
.
|
|
19
|
+
.option(
|
|
20
|
+
"--preset",
|
|
21
|
+
"Include the full preset (API layer + React Query hooks)"
|
|
22
|
+
)
|
|
23
|
+
.action((name, options) => {
|
|
24
|
+
addFeature(name, options);
|
|
25
|
+
});
|
|
20
26
|
|
|
21
27
|
program
|
|
22
28
|
.command("add-lang")
|
package/package.json
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "crdncli",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "bin/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"crdn": "bin/index.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
-
"prepack": "node -c ./bin/index.js && node -c ./lib/cli.js && node -c ./commands/addFeature.js && node -c ./commands/addLang.js && node -c ./commands/deleteLang.js"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [],
|
|
14
|
-
"author": "Creiden",
|
|
15
|
-
"homepage": "https://creiden.com/",
|
|
16
|
-
"license": "ISC",
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "crdncli",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "bin/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"crdn": "bin/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
+
"prepack": "node -c ./bin/index.js && node -c ./lib/cli.js && node -c ./commands/addFeature.js && node -c ./commands/addLang.js && node -c ./commands/deleteLang.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "Creiden",
|
|
15
|
+
"homepage": "https://creiden.com/",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20.9.0"
|
|
19
|
+
},
|
|
20
|
+
"type": "commonjs",
|
|
21
|
+
"files": [
|
|
22
|
+
"bin",
|
|
23
|
+
"lib",
|
|
24
|
+
"commands",
|
|
25
|
+
"templates",
|
|
26
|
+
"package.json",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"chalk": "^4.1.2",
|
|
35
|
+
"commander": "^14.0.3",
|
|
36
|
+
"fs-extra": "^11.2.0"
|
|
37
|
+
}
|
|
38
|
+
}
|