@kosdev-code/kos-ui-cli 2.0.8 → 2.0.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kosdev-code/kos-ui-cli",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "bin": {
5
5
  "kosui": "./src/lib/cli.mjs"
6
6
  },
@@ -20,7 +20,7 @@
20
20
  "main": "./src/index.js",
21
21
  "kos": {
22
22
  "build": {
23
- "gitHash": "8584fd420609fe114b6a0417595eb9b83bb1301a"
23
+ "gitHash": "3f829f56d0cb6147af6735c40f3f1f52734cf673"
24
24
  }
25
25
  },
26
26
  "publishConfig": {
package/src/lib/cli.mjs CHANGED
@@ -4,122 +4,72 @@ import minimist from "minimist";
4
4
  import path, { dirname } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { Plop, run } from "plop";
7
+ import { clearCache } from "./utils/cache.mjs";
8
+ import { getGeneratorMetadata } from "./utils/generator-loader.mjs";
7
9
 
8
- const args = process.argv.slice(2);
9
- const argv = minimist(args);
10
+ // -- Step 1: Sanitize flags early and persist to env
11
+ const originalArgs = process.argv.slice(2);
12
+ const parsedArgs = minimist(originalArgs);
10
13
 
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
- figlet("KOS CLI", function (err, data) {
13
- if (err) {
14
- console.log("Something went wrong...");
15
- console.dir(err);
16
- return;
17
- }
14
+ const customFlags = ["--no-cache", "--refresh"];
15
+ const hasNoCache = originalArgs.includes("--no-cache");
16
+ const hasRefresh = originalArgs.includes("--refresh");
18
17
 
19
- const command = args.length > 0 ? args[0] : "help";
18
+ if (hasNoCache || hasRefresh) {
19
+ process.env.DISABLE_CACHE = "true";
20
+ console.log("[kos-cli] Cache disabled or refresh forced. Clearing cache...");
21
+ clearCache();
22
+ }
20
23
 
21
- switch (command) {
22
- case "workspace":
23
- case "component":
24
- case "pluginComponent":
25
- case "plugin:cui":
26
- case "plugin:utility":
27
- case "plugin:setup":
28
- case "plugin:setting":
29
- case "plugin:nav":
30
- case "plugin:troubleAction":
31
- case "project":
32
- case "project:splash":
33
- case "theme":
34
- case "plugin":
35
- case "i18n":
36
- case "i18n:namespace":
37
- case "model": {
38
- Plop.prepare(
39
- {
40
- cwd: argv.cwd,
41
- configPath: path.join(__dirname, "plopfile.mjs"),
42
- preload: argv.preload || [],
43
- completion: argv.completion,
44
- },
45
- (env) =>
46
- Plop.execute(env, (env) => {
47
- const options = {
48
- ...env,
49
- dest: process.cwd(), // this will make the destination path to be based on the cwd when calling the wrapper
50
- };
51
- return run(options, undefined, true);
52
- })
53
- );
24
+ // -- Step 2: Strip custom flags from argv so Plop doesn't choke
25
+ process.argv = [
26
+ ...process.argv.slice(0, 2),
27
+ ...originalArgs.filter((arg) => !customFlags.includes(arg)),
28
+ ];
54
29
 
55
- break;
56
- }
57
- case "hook":
58
- case "container":
59
- case "context":
60
- case "model:companion": {
61
- console.warn(`--- Create a new KOS Model - ${args[0]} ---`);
62
- Plop.prepare(
63
- {
64
- cwd: argv.cwd,
65
- configPath: path.join(__dirname, "model-aware-plopfile.mjs"),
66
- preload: argv.preload || [],
67
- completion: argv.completion,
68
- },
69
- (env) =>
70
- Plop.execute(env, (env) => {
71
- const options = {
72
- ...env,
73
- dest: process.cwd(), // this will make the destination path to be based on the cwd when calling the wrapper
74
- };
75
- return run(options, undefined, true);
76
- })
77
- );
30
+ // -- Step 3: Resolve generator
31
+ const command = parsedArgs._[0] || "help";
32
+ const __dirname = dirname(fileURLToPath(import.meta.url));
33
+ const configPath = path.join(__dirname, "plopfile.mjs");
78
34
 
79
- break;
80
- }
81
- case "env": {
82
- console.warn("--- Discover Studio Environment Variables ---");
83
- console.warn("The following will discover Studio Environment Variables.");
84
- Plop.prepare(
85
- {
86
- cwd: argv.cwd,
87
- configPath: path.join(__dirname, "env-plopfile.mjs"),
88
- preload: argv.preload || [],
89
- completion: argv.completion,
90
- },
91
- (env) =>
92
- Plop.execute(env, (env) => {
93
- const options = {
94
- ...env,
95
- dest: process.cwd(), // this will make the destination path to be based on the cwd when calling the wrapper
96
- };
97
- return run(options, undefined, true);
98
- })
99
- );
35
+ const showBanner =
36
+ command !== "help" &&
37
+ command !== "env" &&
38
+ process.env.DISABLE_CLI_BANNER !== "true";
39
+
40
+ // -- Step 4: Optional figlet banner
41
+ function launch() {
42
+ Plop.prepare(
43
+ {
44
+ cwd: parsedArgs.cwd,
45
+ configPath,
46
+ preload: parsedArgs.preload || [],
47
+ completion: parsedArgs.completion,
48
+ },
49
+ async (env) => {
50
+ if (command && command !== "help" && command !== "env") {
51
+ const meta = await getGeneratorMetadata(command);
52
+ console.log(`--- Running KOS Generator: ${meta?.name || command} ---`);
53
+ } else if (command === "env") {
54
+ console.warn("--- Discover Studio Environment Variables ---");
55
+ } else {
56
+ console.warn("--- KOS CLI Help ---");
57
+ }
100
58
 
101
- break;
59
+ return run({ ...env, dest: process.cwd() }, undefined, true);
102
60
  }
103
- default: {
104
- console.warn("--- KOS CLI Help ---");
105
- Plop.prepare(
106
- {
107
- cwd: argv.cwd,
108
- configPath: path.join(__dirname, "routing-plopfile.mjs"),
109
- preload: argv.preload || [],
110
- completion: argv.completion,
111
- },
112
- (env) =>
113
- Plop.execute(env, (env) => {
114
- const options = {
115
- ...env,
116
- dest: process.cwd(), // this will make the destination path to be based on the cwd when calling the wrapper
117
- };
118
- return run(options, undefined, true);
119
- })
120
- );
61
+ );
62
+ }
121
63
 
122
- break;
64
+ if (showBanner) {
65
+ figlet("KOS CLI", function (err, data) {
66
+ if (err) {
67
+ console.error("Figlet failed:", err);
68
+ return launch();
123
69
  }
124
- }
125
- });
70
+ console.log(data);
71
+ launch();
72
+ });
73
+ } else {
74
+ launch();
75
+ }
@@ -0,0 +1,12 @@
1
+ import { clearCache } from "../../utils/cache.mjs";
2
+
3
+ export default function registerCacheGenerators(plop) {
4
+ plop.setGenerator("cache:clear", {
5
+ description: "Clear the generator context cache",
6
+ prompts: [],
7
+ actions: () => {
8
+ clearCache();
9
+ return ["[ok] CLI cache cleared successfully."];
10
+ },
11
+ });
12
+ }
@@ -0,0 +1,48 @@
1
+ // generators/component/index.mjs
2
+ import { execute } from "../../utils/exec.mjs";
3
+ import { getAllProjects } from "../../utils/nx-context.mjs";
4
+ import { required } from "../../utils/validators.mjs";
5
+
6
+ export const metadata = {
7
+ key: "component",
8
+ name: "KOS React Component",
9
+ };
10
+
11
+ export default async function (plop) {
12
+ const allProjects = await getAllProjects();
13
+
14
+ plop.setActionType("createComponent", async function (answers) {
15
+ const command = `npx nx generate @kosdev-code/kos-nx-plugin:kos-component \
16
+ --name=${answers.componentName} \
17
+ --appProject=${answers.componentProject} \
18
+ --type=components \
19
+ --no-interactive`;
20
+
21
+ try {
22
+ await execute(command);
23
+ } catch (error) {
24
+ throw new Error(error);
25
+ }
26
+
27
+ return `Component ${answers.componentName} created in ${answers.componentProject}`;
28
+ });
29
+
30
+ plop.setGenerator("component", {
31
+ description: "Create a new KOS Component",
32
+ prompts: [
33
+ {
34
+ type: "input",
35
+ name: "componentName",
36
+ message: "Enter the name of the component",
37
+ validate: required,
38
+ },
39
+ {
40
+ type: "list",
41
+ name: "componentProject",
42
+ message: "Which project should the component be created in?",
43
+ choices: allProjects,
44
+ },
45
+ ],
46
+ actions: () => [{ type: "createComponent" }],
47
+ });
48
+ }
@@ -1,14 +1,26 @@
1
+ // generators/env/index.mjs
1
2
  import fs from "fs";
2
3
  import directoryPrompt from "inquirer-directory";
3
- import { findJavaExecutable } from "./utils/java-home.mjs";
4
- import { findStudioHome } from "./utils/studio-home.mjs";
5
- import { detectWorkspace } from "./utils/utils.mjs";
4
+ import { findJavaExecutable } from "../../utils/java-home.mjs";
5
+ import { detectWorkspace } from "../../utils/nx-context.mjs";
6
+ import { findStudioHome } from "../../utils/studio-home.mjs";
6
7
 
8
+ export const metadata = {
9
+ key: "env",
10
+ name: "Discover and Set Studio Environment Variables",
11
+ };
7
12
  export default async function (plop) {
8
13
  plop.setPrompt("directory", directoryPrompt);
14
+
9
15
  const isWorkspace = await detectWorkspace();
16
+ if (!isWorkspace) {
17
+ console.warn(
18
+ "[kos-cli] Not inside an Nx workspace. Skipping env generator."
19
+ );
20
+ return;
21
+ }
10
22
 
11
- plop.setActionType("findEnv", async function (answers, config, plop) {
23
+ plop.setActionType("findEnv", async function () {
12
24
  const studioHome = findStudioHome();
13
25
  const javaHome = findJavaExecutable();
14
26
 
@@ -23,11 +35,6 @@ export default async function (plop) {
23
35
  plop.setGenerator("env", {
24
36
  description: "Discover Studio Environment Variables",
25
37
  prompts: [],
26
- actions: function (data) {
27
- const action = {
28
- type: "findEnv",
29
- };
30
- return [action];
31
- },
38
+ actions: () => [{ type: "findEnv" }],
32
39
  });
33
40
  }
@@ -0,0 +1,55 @@
1
+ // generators/i18n/namespace.mjs
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { getAllProjects, getProjectDetails } from "../../utils/nx-context.mjs";
5
+ import { required } from "../../utils/validators.mjs";
6
+
7
+ export const metadata = {
8
+ key: "i18n:namespace",
9
+ name: "KOS i18n Project Namespace",
10
+ };
11
+
12
+ export default async function (plop) {
13
+ const allProjects = await getAllProjects();
14
+
15
+ plop.setActionType("addNamespace", async function (answers) {
16
+ const i18nProject = await getProjectDetails(answers.project);
17
+ const srcRoot = i18nProject.sourceRoot;
18
+ const locale = answers.locale;
19
+ const namespaceDir = path.join(srcRoot, "assets", "locales", locale);
20
+ const namespacePath = path.join(namespaceDir, `${answers.name}.json`);
21
+
22
+ fs.mkdirSync(namespaceDir, { recursive: true });
23
+ fs.writeFileSync(
24
+ namespacePath,
25
+ JSON.stringify({ name: answers.name }, null, 2)
26
+ );
27
+
28
+ return `Namespace ${answers.name}.json created for locale ${locale} in ${answers.project}`;
29
+ });
30
+
31
+ plop.setGenerator("i18n:namespace", {
32
+ description: "Create a new KOS UI i18n namespace",
33
+ prompts: [
34
+ {
35
+ type: "input",
36
+ name: "name",
37
+ message: "What is the name of the i18n namespace?",
38
+ validate: required,
39
+ },
40
+ {
41
+ type: "input",
42
+ name: "locale",
43
+ message: "What is the locale of the i18n namespace?",
44
+ validate: required,
45
+ },
46
+ {
47
+ type: "list",
48
+ name: "project",
49
+ message: "Which project should the namespace be created in?",
50
+ choices: allProjects,
51
+ },
52
+ ],
53
+ actions: () => [{ type: "addNamespace" }],
54
+ });
55
+ }
@@ -0,0 +1,150 @@
1
+ [
2
+ {
3
+ "category": "component",
4
+ "file": "index.mjs",
5
+ "metadata": {
6
+ "key": "component",
7
+ "name": "KOS React Component"
8
+ }
9
+ },
10
+ {
11
+ "category": "env",
12
+ "file": "index.mjs",
13
+ "metadata": {
14
+ "key": "env",
15
+ "name": "Discover and Set Studio Environment Variables"
16
+ }
17
+ },
18
+ {
19
+ "category": "i18n",
20
+ "file": "namespace.mjs",
21
+ "metadata": {
22
+ "key": "i18n:namespace",
23
+ "name": "KOS i18n Project Namespace"
24
+ }
25
+ },
26
+ {
27
+ "category": "model",
28
+ "file": "companion.mjs",
29
+ "metadata": {
30
+ "key": "model:companion",
31
+ "name": "KOS Companion Model"
32
+ }
33
+ },
34
+ {
35
+ "category": "model",
36
+ "file": "container.mjs",
37
+ "metadata": {
38
+ "key": "container",
39
+ "name": "KOS Container Model"
40
+ }
41
+ },
42
+ {
43
+ "category": "model",
44
+ "file": "context.mjs",
45
+ "metadata": {
46
+ "key": "context",
47
+ "name": "KOS Model React Context"
48
+ }
49
+ },
50
+ {
51
+ "category": "model",
52
+ "file": "hook.mjs",
53
+ "metadata": {
54
+ "key": "hook",
55
+ "name": "KOS Model React Hook"
56
+ }
57
+ },
58
+ {
59
+ "category": "model",
60
+ "file": "model.mjs",
61
+ "metadata": {
62
+ "key": "model",
63
+ "name": "KOS Model",
64
+ "invalidateCache": true
65
+ }
66
+ },
67
+ {
68
+ "category": "plugin",
69
+ "file": "index.mjs",
70
+ "metadata": [
71
+ {
72
+ "key": "pluginComponent",
73
+ "name": "KOS UI Plugin Component"
74
+ },
75
+ {
76
+ "key": "plugin:cui",
77
+ "name": "KOS UI Plugin CUI Configuration"
78
+ },
79
+ {
80
+ "key": "plugin:setup",
81
+ "name": "KOS UI Plugin Setup Step"
82
+ },
83
+ {
84
+ "key": "plugin:utility",
85
+ "name": "KOS UI Plugin Utility"
86
+ },
87
+ {
88
+ "key": "plugin:setting",
89
+ "name": "KOS UI Plugin Setting"
90
+ },
91
+ {
92
+ "key": "plugin:nav",
93
+ "name": "KOS UI Plugin Navigation View"
94
+ }
95
+ ]
96
+ },
97
+ {
98
+ "category": "project",
99
+ "file": "app.mjs",
100
+ "metadata": {
101
+ "key": "project",
102
+ "name": "KOS UI App Project",
103
+ "invalidateCache": true
104
+ }
105
+ },
106
+ {
107
+ "category": "project",
108
+ "file": "i18n.mjs",
109
+ "metadata": {
110
+ "key": "i18n",
111
+ "name": "KOS Localization Project",
112
+ "invalidateCache": true
113
+ }
114
+ },
115
+ {
116
+ "category": "project",
117
+ "file": "plugin.mjs",
118
+ "metadata": {
119
+ "key": "plugin",
120
+ "name": "KOS Plugin Project",
121
+ "invalidateCache": true
122
+ }
123
+ },
124
+ {
125
+ "category": "project",
126
+ "file": "splash.mjs",
127
+ "metadata": {
128
+ "key": "project:splash",
129
+ "name": "KOS Splash Screen Project",
130
+ "invalidateCache": true
131
+ }
132
+ },
133
+ {
134
+ "category": "project",
135
+ "file": "theme.mjs",
136
+ "metadata": {
137
+ "key": "theme",
138
+ "name": "KOS Theme Project",
139
+ "invalidateCache": true
140
+ }
141
+ },
142
+ {
143
+ "category": "workspace",
144
+ "file": "index.mjs",
145
+ "metadata": {
146
+ "key": "workspace",
147
+ "name": "Create a new KOS UI Workspace"
148
+ }
149
+ }
150
+ ]
@@ -0,0 +1,77 @@
1
+ // generators/model/companion.mjs
2
+ import { execute } from "../../utils/exec.mjs";
3
+ import {
4
+ getAllModels,
5
+ getLibraryProjects,
6
+ getProjectDetails,
7
+ } from "../../utils/nx-context.mjs";
8
+ import { DEFAULT_PROMPTS, MODEL_PROMPTS } from "../../utils/prompts.mjs";
9
+ import { required } from "../../utils/validators.mjs";
10
+
11
+ export const metadata = {
12
+ key: "model:companion",
13
+ name: "KOS Companion Model",
14
+ };
15
+
16
+ export default async function (plop) {
17
+ const allModels = await getAllModels();
18
+ const libraryProjects = await getLibraryProjects();
19
+ const modelChoices = allModels.map((m) => ({
20
+ name: `${m.model} (${m.project})`,
21
+ value: m.model,
22
+ }));
23
+
24
+ plop.setActionType("createCompanionModel", async function (answers) {
25
+ const modelProject = await getProjectDetails(answers.modelProject);
26
+ const companionProject = allModels.find(
27
+ (m) => m.model === answers.companionParent
28
+ )?.project;
29
+
30
+ const command = `npx nx generate @kosdev-code/kos-nx-plugin:kos-model \
31
+ --name=${answers.modelName} \
32
+ --modelProject=${modelProject.name} \
33
+ --skipRegistration=true \
34
+ --container=${!!answers.container} \
35
+ --dataServices=${!!answers.dataServices} \
36
+ --singleton=${!!answers.singleton} \
37
+ --parentAware=${!!answers.parentAware} \
38
+ --companion=true \
39
+ --companionModel=${answers.companionParent} \
40
+ --companionModelProject=${companionProject} \
41
+ --no-interactive ${answers.dryRun ? "--dryRun" : ""} --verbose`;
42
+
43
+ try {
44
+ await execute(command);
45
+ } catch (error) {
46
+ throw new Error(error);
47
+ }
48
+ });
49
+
50
+ plop.setGenerator("model:companion", {
51
+ description: "Create a new KOS Companion Model",
52
+ prompts: [
53
+ ...DEFAULT_PROMPTS,
54
+ {
55
+ type: "input",
56
+ name: "modelName",
57
+ message: "Enter the name of the model",
58
+ validate: required,
59
+ },
60
+ {
61
+ type: "list",
62
+ name: "modelProject",
63
+ message: "Which model project to use?",
64
+ validate: required,
65
+ choices: libraryProjects,
66
+ },
67
+ {
68
+ type: "list",
69
+ name: "companionParent",
70
+ message: "Select the companion parent model",
71
+ choices: modelChoices,
72
+ },
73
+ ...MODEL_PROMPTS,
74
+ ],
75
+ actions: () => [{ type: "createCompanionModel" }],
76
+ });
77
+ }
@@ -0,0 +1,66 @@
1
+ // generators/model/container.mjs
2
+ import { execute } from "../../utils/exec.mjs";
3
+ import {
4
+ getAllModels,
5
+ getAllProjects,
6
+ getProjectDetails,
7
+ } from "../../utils/nx-context.mjs";
8
+ import { DEFAULT_PROMPTS, MODEL_PROMPTS } from "../../utils/prompts.mjs";
9
+
10
+ export const metadata = {
11
+ key: "container",
12
+ name: "KOS Container Model",
13
+ };
14
+
15
+ export default async function (plop) {
16
+ const allModels = await getAllModels();
17
+ const allProjects = await getAllProjects();
18
+ const modelChoices = allModels.map((m) => ({
19
+ name: `${m.model} (${m.project})`,
20
+ value: m.model,
21
+ }));
22
+
23
+ plop.setActionType("createContainer", async function (answers) {
24
+ const modelProject = allModels.find(
25
+ (m) => m.model === answers.modelName
26
+ )?.project;
27
+ const projectDetails = await getProjectDetails(modelProject);
28
+
29
+ const command = `npx nx generate @kosdev-code/kos-nx-plugin:kos-container-model \
30
+ --modelName=${answers.modelName} \
31
+ --modelProject=${projectDetails.name} \
32
+ --skipRegistration=true \
33
+ --dataServices=${!!answers.dataServices} \
34
+ --singleton=${!!answers.singleton} \
35
+ --no-interactive ${answers.dryRun ? "--dryRun" : ""} --verbose`;
36
+
37
+ try {
38
+ await execute(command);
39
+ } catch (error) {
40
+ throw new Error(error);
41
+ }
42
+
43
+ return `Container model created for ${answers.modelName}`;
44
+ });
45
+
46
+ plop.setGenerator("container", {
47
+ description: "Create a new KOS Container Model",
48
+ prompts: [
49
+ ...DEFAULT_PROMPTS,
50
+ {
51
+ type: "list",
52
+ name: "modelName",
53
+ message: "Which model to use?",
54
+ choices: modelChoices,
55
+ },
56
+ {
57
+ type: "list",
58
+ name: "registrationProject",
59
+ message: "Which project should the model be registered in?",
60
+ choices: allProjects,
61
+ },
62
+ ...MODEL_PROMPTS,
63
+ ],
64
+ actions: () => [{ type: "createContainer" }],
65
+ });
66
+ }