@ikas/component-cli 1.4.0-beta.2 → 1.4.0-beta.21
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/dist/commands/add-to-page.d.ts +3 -0
- package/dist/commands/add-to-page.d.ts.map +1 -0
- package/dist/commands/add-to-page.js +41 -0
- package/dist/commands/add-to-page.js.map +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +185 -120
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/create.d.ts +3 -8
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +227 -8
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +230 -24
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/import.d.ts +3 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +25 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/list-imported.d.ts +3 -0
- package/dist/commands/list-imported.d.ts.map +1 -0
- package/dist/commands/list-imported.js +25 -0
- package/dist/commands/list-imported.js.map +1 -0
- package/dist/commands/list-page-sections.d.ts +3 -0
- package/dist/commands/list-page-sections.d.ts.map +1 -0
- package/dist/commands/list-page-sections.js +25 -0
- package/dist/commands/list-page-sections.js.map +1 -0
- package/dist/commands/list-pages.d.ts +3 -0
- package/dist/commands/list-pages.d.ts.map +1 -0
- package/dist/commands/list-pages.js +21 -0
- package/dist/commands/list-pages.js.map +1 -0
- package/dist/commands/proxy.d.ts.map +1 -1
- package/dist/commands/proxy.js +4 -6
- package/dist/commands/proxy.js.map +1 -1
- package/dist/commands/update-section-prop.d.ts +3 -0
- package/dist/commands/update-section-prop.d.ts.map +1 -0
- package/dist/commands/update-section-prop.js +59 -0
- package/dist/commands/update-section-prop.js.map +1 -0
- package/dist/commands/upload-image.d.ts +3 -0
- package/dist/commands/upload-image.d.ts.map +1 -0
- package/dist/commands/upload-image.js +79 -0
- package/dist/commands/upload-image.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/component-helpers.d.ts +14 -1
- package/dist/utils/component-helpers.d.ts.map +1 -1
- package/dist/utils/component-helpers.js +16 -0
- package/dist/utils/component-helpers.js.map +1 -1
- package/dist/utils/editor-action-client.d.ts +28 -0
- package/dist/utils/editor-action-client.d.ts.map +1 -0
- package/dist/utils/editor-action-client.js +101 -0
- package/dist/utils/editor-action-client.js.map +1 -0
- package/dist/utils/websocket-server.d.ts +48 -0
- package/dist/utils/websocket-server.d.ts.map +1 -1
- package/dist/utils/websocket-server.js +58 -0
- package/dist/utils/websocket-server.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-to-page.d.ts","sourceRoot":"","sources":["../../src/commands/add-to-page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6CpC,wBAAgB,sBAAsB,IAAI,OAAO,CAYhD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { printErrorAndExit, printResultAndExit, runEditorAction, } from "../utils/editor-action-client.js";
|
|
3
|
+
async function runAddToPage(options) {
|
|
4
|
+
if (!options.componentId || typeof options.componentId !== "string") {
|
|
5
|
+
printErrorAndExit(new Error("--component-id is required"));
|
|
6
|
+
}
|
|
7
|
+
if (!options.pageId || typeof options.pageId !== "string") {
|
|
8
|
+
printErrorAndExit(new Error("--page-id is required (use `ikas-component list-pages` to discover ids)"));
|
|
9
|
+
}
|
|
10
|
+
let index;
|
|
11
|
+
if (options.index !== undefined) {
|
|
12
|
+
index = parseInt(options.index, 10);
|
|
13
|
+
if (Number.isNaN(index) || index < 0) {
|
|
14
|
+
printErrorAndExit(new Error("--index must be a non-negative integer"));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const port = options.port ? parseInt(options.port, 10) : undefined;
|
|
18
|
+
try {
|
|
19
|
+
const result = await runEditorAction("add-section-to-page", {
|
|
20
|
+
componentId: options.componentId,
|
|
21
|
+
pageId: options.pageId,
|
|
22
|
+
...(typeof index === "number" ? { index } : {}),
|
|
23
|
+
}, port ? { port } : {});
|
|
24
|
+
printResultAndExit(result);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
printErrorAndExit(e);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function createAddToPageCommand() {
|
|
31
|
+
const cmd = new Command("add-to-page");
|
|
32
|
+
cmd
|
|
33
|
+
.description("Place a section-type code component on a page. Requires the component to be imported first (see `ikas-component import`).")
|
|
34
|
+
.requiredOption("--component-id <id>", "Code component id (from `ikas-component list-imported`)")
|
|
35
|
+
.requiredOption("--page-id <id>", "Page id (from `ikas-component list-pages`)")
|
|
36
|
+
.option("--index <n>", "Zero-based insertion index in the page; appends when omitted")
|
|
37
|
+
.option("--port <port>", "Dev server WebSocket port", "5201")
|
|
38
|
+
.action(runAddToPage);
|
|
39
|
+
return cmd;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=add-to-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-to-page.js","sourceRoot":"","sources":["../../src/commands/add-to-page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,GAChB,MAAM,kCAAkC,CAAC;AAS1C,KAAK,UAAU,YAAY,CAAC,OAAyB;IACnD,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,OAAO,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;QACpE,iBAAiB,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1D,iBAAiB,CAAC,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC,CAAC;IAC1G,CAAC;IACD,IAAI,KAAyB,CAAC;IAC9B,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACrC,iBAAiB,CAAC,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACnE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAClC,qBAAqB,EACrB;YACE,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChD,EACD,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CACrB,CAAC;QACF,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,iBAAiB,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IACvC,GAAG;SACA,WAAW,CACV,2HAA2H,CAC5H;SACA,cAAc,CAAC,qBAAqB,EAAE,yDAAyD,CAAC;SAChG,cAAc,CAAC,gBAAgB,EAAE,4CAA4C,CAAC;SAC9E,MAAM,CAAC,aAAa,EAAE,8DAA8D,CAAC;SACrF,MAAM,CAAC,eAAe,EAAE,2BAA2B,EAAE,MAAM,CAAC;SAC5D,MAAM,CAAC,YAAY,CAAC,CAAC;IACxB,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAw/CpC,wBAAgB,mBAAmB,IAAI,OAAO,CA2M7C"}
|
package/dist/commands/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
|
-
import { PROP_TYPES, toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, generateComponentFile, generateStylesFile, generateProjectId, generateComponentId, generateUniqueId, updateBarrelExport, findPropGroup, collectPropGroupIds, movePropGroupInTree, } from "../utils/component-helpers.js";
|
|
4
|
+
import { PROP_TYPES, toPascalCase, generateTypesFile, generateGlobalTypesFile, collectUsedEnumIds, generateComponentFile, generateStylesFile, generateProjectId, generateComponentId, generateUniqueId, updateBarrelExport, findPropGroup, collectPropGroupIds, movePropGroupInTree, validateFilteredComponentIds, } from "../utils/component-helpers.js";
|
|
5
5
|
function loadConfig() {
|
|
6
6
|
const configPath = path.resolve(process.cwd(), "ikas.config.json");
|
|
7
7
|
if (!fs.existsSync(configPath)) {
|
|
@@ -17,13 +17,79 @@ function loadConfig() {
|
|
|
17
17
|
function saveConfig(configPath, config) {
|
|
18
18
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a component by canonical id (preferred) or exact PascalCase name.
|
|
22
|
+
* No silent normalization: pass --id from `config list-components`, or pass --name
|
|
23
|
+
* exactly as stored in ikas.config.json. Exits with a structured JSON error
|
|
24
|
+
* (listing valid {id, name} pairs) if zero/both/missing.
|
|
25
|
+
*/
|
|
26
|
+
function resolveComponent(config, ref) {
|
|
27
|
+
const id = ref.id?.trim() || undefined;
|
|
28
|
+
const name = ref.name?.trim() || undefined;
|
|
29
|
+
if (!id && !name) {
|
|
30
|
+
console.log(JSON.stringify({
|
|
31
|
+
success: false,
|
|
32
|
+
error: "Component reference required: pass --id (preferred) or --name (exact PascalCase). " +
|
|
33
|
+
"Run `ikas-component config list-components` to see canonical ids.",
|
|
34
|
+
validComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
|
|
35
|
+
}));
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
if (id && name) {
|
|
39
|
+
console.log(JSON.stringify({
|
|
40
|
+
success: false,
|
|
41
|
+
error: "Specify only one of --id or --name, not both.",
|
|
42
|
+
}));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const found = id
|
|
46
|
+
? config.components.find((c) => c.id === id)
|
|
47
|
+
: config.components.find((c) => c.name === name);
|
|
48
|
+
if (!found) {
|
|
49
|
+
console.log(JSON.stringify({
|
|
50
|
+
success: false,
|
|
51
|
+
error: id
|
|
52
|
+
? `Component not found: id="${id}".`
|
|
53
|
+
: `Component not found: name="${name}". Names are matched exactly (PascalCase, no normalization).`,
|
|
54
|
+
lookup: id ? { id } : { name },
|
|
55
|
+
validComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
|
|
56
|
+
hint: "Use --id (preferred) or exact PascalCase --name. " +
|
|
57
|
+
"Run `ikas-component config list-components` to see canonical ids.",
|
|
58
|
+
}));
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
return found;
|
|
23
62
|
}
|
|
24
63
|
function getComponentNames(config) {
|
|
25
64
|
return config.components.map((c) => c.name);
|
|
26
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Emit a structured JSON error for unknown filteredComponentIds entries and exit non-zero.
|
|
68
|
+
* Lists valid `{ id, name }` pairs so the LLM/caller can recover.
|
|
69
|
+
*/
|
|
70
|
+
function emitFilteredComponentIdsError(unknown, components) {
|
|
71
|
+
console.log(JSON.stringify({
|
|
72
|
+
success: false,
|
|
73
|
+
error: `Unknown filteredComponentIds: ${unknown.join(", ")}. ` +
|
|
74
|
+
`Component ids are opaque and cannot be derived from names — they must come from the ` +
|
|
75
|
+
`componentId returned by 'config add-component' or from 'config list'.`,
|
|
76
|
+
validComponents: components.map((c) => ({ id: c.id, name: c.name })),
|
|
77
|
+
}));
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Validate `input` ids against `config.components` and return the same array on success.
|
|
82
|
+
* Exits with a JSON error if any id is unknown. Use at every write site that accepts
|
|
83
|
+
* filteredComponentIds from user/LLM input.
|
|
84
|
+
*/
|
|
85
|
+
function assertKnownComponentIds(input, config) {
|
|
86
|
+
const components = config?.components ?? [];
|
|
87
|
+
const { unknown } = validateFilteredComponentIds(input, components);
|
|
88
|
+
if (unknown.length > 0) {
|
|
89
|
+
emitFilteredComponentIdsError(unknown, components);
|
|
90
|
+
}
|
|
91
|
+
return input;
|
|
92
|
+
}
|
|
27
93
|
function regenerateTypes(component, componentType, config) {
|
|
28
94
|
const componentDir = path.resolve(process.cwd(), path.dirname(component.entry));
|
|
29
95
|
const typesPath = path.join(componentDir, "types.ts");
|
|
@@ -78,6 +144,19 @@ function camelCaseToDisplayName(name) {
|
|
|
78
144
|
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
79
145
|
.replace(/^./, (c) => c.toUpperCase());
|
|
80
146
|
}
|
|
147
|
+
const ALLOWED_PROP_FIELDS = new Set([
|
|
148
|
+
"name",
|
|
149
|
+
"displayName",
|
|
150
|
+
"type",
|
|
151
|
+
"required",
|
|
152
|
+
"description",
|
|
153
|
+
"defaultValue",
|
|
154
|
+
"groupId",
|
|
155
|
+
"typeId",
|
|
156
|
+
"enumTypeId",
|
|
157
|
+
"filteredComponentIds",
|
|
158
|
+
"privateVarMap",
|
|
159
|
+
]);
|
|
81
160
|
/**
|
|
82
161
|
* Parse and validate the --props JSON flag for add-component.
|
|
83
162
|
* Returns validated ComponentProp[] or exits with error.
|
|
@@ -105,6 +184,16 @@ async function parsePropsFlag(propsJson, config, configPath) {
|
|
|
105
184
|
const props = [];
|
|
106
185
|
for (const raw of rawProps) {
|
|
107
186
|
const r = raw;
|
|
187
|
+
const unknownFields = Object.keys(r).filter((k) => !ALLOWED_PROP_FIELDS.has(k));
|
|
188
|
+
if (unknownFields.length > 0) {
|
|
189
|
+
console.log(JSON.stringify({
|
|
190
|
+
success: false,
|
|
191
|
+
error: `Unknown field(s) in --props entry: ${unknownFields.join(", ")}. ` +
|
|
192
|
+
`Allowed: ${[...ALLOWED_PROP_FIELDS].join(", ")}. ` +
|
|
193
|
+
`Note: use "groupId" (not "group") and "defaultValue" (not "default") in --props JSON.`,
|
|
194
|
+
}));
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
108
197
|
if (!r.name || typeof r.name !== "string") {
|
|
109
198
|
console.log(JSON.stringify({
|
|
110
199
|
success: false,
|
|
@@ -201,7 +290,7 @@ async function parsePropsFlag(propsJson, config, configPath) {
|
|
|
201
290
|
? { enumTypeId: r.enumTypeId }
|
|
202
291
|
: {}),
|
|
203
292
|
...((propType === "COMPONENT" || propType === "COMPONENT_LIST") && r.filteredComponentIds && Array.isArray(r.filteredComponentIds)
|
|
204
|
-
? { filteredComponentIds: r.filteredComponentIds }
|
|
293
|
+
? { filteredComponentIds: assertKnownComponentIds(r.filteredComponentIds, config) }
|
|
205
294
|
: {}),
|
|
206
295
|
...((propType === "COMPONENT" || propType === "COMPONENT_LIST") && r.privateVarMap && typeof r.privateVarMap === "object"
|
|
207
296
|
? { privateVarMap: r.privateVarMap }
|
|
@@ -236,14 +325,15 @@ async function addComponent(name, options) {
|
|
|
236
325
|
if (!config.projectId) {
|
|
237
326
|
config.projectId = generateProjectId();
|
|
238
327
|
}
|
|
328
|
+
// Parse --props (and validate filteredComponentIds) BEFORE any filesystem side-effects
|
|
329
|
+
// so a bad payload doesn't leave an empty component directory behind.
|
|
330
|
+
const props = options.props
|
|
331
|
+
? await parsePropsFlag(options.props, config, configPath)
|
|
332
|
+
: [];
|
|
239
333
|
const componentId = generateComponentId(config.projectId);
|
|
240
334
|
const componentDir = path.resolve(process.cwd(), `src/components/${pascalName}`);
|
|
241
335
|
// Create directory
|
|
242
336
|
fs.mkdirSync(componentDir, { recursive: true });
|
|
243
|
-
// Parse --props if provided, otherwise empty
|
|
244
|
-
const props = options.props
|
|
245
|
-
? await parsePropsFlag(options.props, config, configPath)
|
|
246
|
-
: [];
|
|
247
337
|
// Auto-create prop groups from groupId references in props
|
|
248
338
|
const referencedGroupIds = new Set();
|
|
249
339
|
for (const prop of props) {
|
|
@@ -294,16 +384,9 @@ async function addComponent(name, options) {
|
|
|
294
384
|
],
|
|
295
385
|
}));
|
|
296
386
|
}
|
|
297
|
-
async function addProp(
|
|
387
|
+
async function addProp(ref, options) {
|
|
298
388
|
const { config, configPath } = loadConfig();
|
|
299
|
-
const component =
|
|
300
|
-
if (!component) {
|
|
301
|
-
console.log(JSON.stringify({
|
|
302
|
-
success: false,
|
|
303
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
304
|
-
}));
|
|
305
|
-
process.exit(1);
|
|
306
|
-
}
|
|
389
|
+
const component = resolveComponent(config, ref);
|
|
307
390
|
// Validate prop type
|
|
308
391
|
const propType = options.type.toUpperCase();
|
|
309
392
|
if (!PROP_TYPES.includes(propType)) {
|
|
@@ -389,6 +472,7 @@ async function addProp(componentName, options) {
|
|
|
389
472
|
console.log(JSON.stringify({ success: false, error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}` }));
|
|
390
473
|
process.exit(1);
|
|
391
474
|
}
|
|
475
|
+
assertKnownComponentIds(parsedFilteredIds, config);
|
|
392
476
|
}
|
|
393
477
|
// Parse privateVarMap JSON for COMPONENT/COMPONENT_LIST
|
|
394
478
|
let parsedPrivateVarMap;
|
|
@@ -450,16 +534,9 @@ function parseDefaultValue(value, propType) {
|
|
|
450
534
|
return value;
|
|
451
535
|
}
|
|
452
536
|
}
|
|
453
|
-
function updateProp(
|
|
537
|
+
function updateProp(ref, options) {
|
|
454
538
|
const { config, configPath } = loadConfig();
|
|
455
|
-
const component =
|
|
456
|
-
if (!component) {
|
|
457
|
-
console.log(JSON.stringify({
|
|
458
|
-
success: false,
|
|
459
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
460
|
-
}));
|
|
461
|
-
process.exit(1);
|
|
462
|
-
}
|
|
539
|
+
const component = resolveComponent(config, ref);
|
|
463
540
|
const propIndex = component.props.findIndex((p) => p.name === options.prop);
|
|
464
541
|
if (propIndex === -1) {
|
|
465
542
|
console.log(JSON.stringify({
|
|
@@ -542,11 +619,15 @@ function updateProp(componentName, options) {
|
|
|
542
619
|
console.log(JSON.stringify({ success: false, error: "--filteredComponentIds must be a JSON array of strings." }));
|
|
543
620
|
process.exit(1);
|
|
544
621
|
}
|
|
622
|
+
assertKnownComponentIds(parsed, config);
|
|
545
623
|
prop.filteredComponentIds = parsed;
|
|
546
624
|
}
|
|
547
|
-
catch {
|
|
548
|
-
|
|
549
|
-
|
|
625
|
+
catch (err) {
|
|
626
|
+
if (err instanceof SyntaxError) {
|
|
627
|
+
console.log(JSON.stringify({ success: false, error: `Invalid --filteredComponentIds JSON: ${options.filteredComponentIds}` }));
|
|
628
|
+
process.exit(1);
|
|
629
|
+
}
|
|
630
|
+
throw err;
|
|
550
631
|
}
|
|
551
632
|
}
|
|
552
633
|
}
|
|
@@ -589,16 +670,9 @@ function updateProp(componentName, options) {
|
|
|
589
670
|
},
|
|
590
671
|
}));
|
|
591
672
|
}
|
|
592
|
-
function removeProp(
|
|
673
|
+
function removeProp(ref, options) {
|
|
593
674
|
const { config, configPath } = loadConfig();
|
|
594
|
-
const component =
|
|
595
|
-
if (!component) {
|
|
596
|
-
console.log(JSON.stringify({
|
|
597
|
-
success: false,
|
|
598
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
599
|
-
}));
|
|
600
|
-
process.exit(1);
|
|
601
|
-
}
|
|
675
|
+
const component = resolveComponent(config, ref);
|
|
602
676
|
const propIndex = component.props.findIndex((p) => p.name === options.prop);
|
|
603
677
|
if (propIndex === -1) {
|
|
604
678
|
console.log(JSON.stringify({
|
|
@@ -619,21 +693,30 @@ function removeProp(componentName, options) {
|
|
|
619
693
|
remainingProps: component.props.map((p) => p.name),
|
|
620
694
|
}));
|
|
621
695
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
696
|
+
/**
|
|
697
|
+
* Strip a deleted component's ID from every other component's COMPONENT/COMPONENT_LIST
|
|
698
|
+
* `filteredComponentIds` allowlist. Empty arrays are deleted to keep the field optional
|
|
699
|
+
* (mirrors the editor-side convention).
|
|
700
|
+
*/
|
|
701
|
+
function pruneFilteredComponentIdRefs(config, removedId) {
|
|
702
|
+
for (const component of config.components) {
|
|
703
|
+
for (const prop of component.props || []) {
|
|
704
|
+
if (!prop.filteredComponentIds)
|
|
705
|
+
continue;
|
|
706
|
+
prop.filteredComponentIds = prop.filteredComponentIds.filter((id) => id !== removedId);
|
|
707
|
+
if (prop.filteredComponentIds.length === 0)
|
|
708
|
+
delete prop.filteredComponentIds;
|
|
709
|
+
}
|
|
632
710
|
}
|
|
633
|
-
|
|
711
|
+
}
|
|
712
|
+
function removeComponent(ref) {
|
|
713
|
+
const { config, configPath } = loadConfig();
|
|
714
|
+
const component = resolveComponent(config, ref);
|
|
715
|
+
const componentIndex = config.components.indexOf(component);
|
|
634
716
|
const componentDir = path.resolve(process.cwd(), path.dirname(component.entry));
|
|
635
|
-
// Remove component from config
|
|
717
|
+
// Remove component from config and strip orphaned references from remaining components
|
|
636
718
|
config.components.splice(componentIndex, 1);
|
|
719
|
+
pruneFilteredComponentIdRefs(config, component.id);
|
|
637
720
|
saveConfig(configPath, config);
|
|
638
721
|
// Remove component directory
|
|
639
722
|
if (fs.existsSync(componentDir)) {
|
|
@@ -643,21 +726,15 @@ function removeComponent(options) {
|
|
|
643
726
|
updateBarrelExport(process.cwd(), getComponentNames(config));
|
|
644
727
|
console.log(JSON.stringify({
|
|
645
728
|
success: true,
|
|
646
|
-
|
|
729
|
+
removedComponentId: component.id,
|
|
730
|
+
removedComponentName: component.name,
|
|
647
731
|
removedDirectory: path.relative(process.cwd(), componentDir),
|
|
648
|
-
remainingComponents:
|
|
732
|
+
remainingComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
|
|
649
733
|
}));
|
|
650
734
|
}
|
|
651
|
-
function addPropGroup(
|
|
735
|
+
function addPropGroup(ref, options) {
|
|
652
736
|
const { config, configPath } = loadConfig();
|
|
653
|
-
const component =
|
|
654
|
-
if (!component) {
|
|
655
|
-
console.log(JSON.stringify({
|
|
656
|
-
success: false,
|
|
657
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
658
|
-
}));
|
|
659
|
-
process.exit(1);
|
|
660
|
-
}
|
|
737
|
+
const component = resolveComponent(config, ref);
|
|
661
738
|
if (!component.propGroups)
|
|
662
739
|
component.propGroups = [];
|
|
663
740
|
// Check uniqueness
|
|
@@ -708,16 +785,9 @@ function addPropGroup(componentName, options) {
|
|
|
708
785
|
},
|
|
709
786
|
}));
|
|
710
787
|
}
|
|
711
|
-
function updatePropGroup(
|
|
788
|
+
function updatePropGroup(ref, options) {
|
|
712
789
|
const { config, configPath } = loadConfig();
|
|
713
|
-
const component =
|
|
714
|
-
if (!component) {
|
|
715
|
-
console.log(JSON.stringify({
|
|
716
|
-
success: false,
|
|
717
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
718
|
-
}));
|
|
719
|
-
process.exit(1);
|
|
720
|
-
}
|
|
790
|
+
const component = resolveComponent(config, ref);
|
|
721
791
|
if (!component.propGroups || component.propGroups.length === 0) {
|
|
722
792
|
console.log(JSON.stringify({
|
|
723
793
|
success: false,
|
|
@@ -747,16 +817,9 @@ function updatePropGroup(componentName, options) {
|
|
|
747
817
|
},
|
|
748
818
|
}));
|
|
749
819
|
}
|
|
750
|
-
function removePropGroup(
|
|
820
|
+
function removePropGroup(ref, options) {
|
|
751
821
|
const { config, configPath } = loadConfig();
|
|
752
|
-
const component =
|
|
753
|
-
if (!component) {
|
|
754
|
-
console.log(JSON.stringify({
|
|
755
|
-
success: false,
|
|
756
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
757
|
-
}));
|
|
758
|
-
process.exit(1);
|
|
759
|
-
}
|
|
822
|
+
const component = resolveComponent(config, ref);
|
|
760
823
|
if (!component.propGroups || component.propGroups.length === 0) {
|
|
761
824
|
console.log(JSON.stringify({
|
|
762
825
|
success: false,
|
|
@@ -792,16 +855,9 @@ function removePropGroup(componentName, options) {
|
|
|
792
855
|
remainingPropGroups: component.propGroups.map(g => g.id),
|
|
793
856
|
}));
|
|
794
857
|
}
|
|
795
|
-
function movePropGroup(
|
|
858
|
+
function movePropGroup(ref, options) {
|
|
796
859
|
const { config, configPath } = loadConfig();
|
|
797
|
-
const component =
|
|
798
|
-
if (!component) {
|
|
799
|
-
console.log(JSON.stringify({
|
|
800
|
-
success: false,
|
|
801
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
802
|
-
}));
|
|
803
|
-
process.exit(1);
|
|
804
|
-
}
|
|
860
|
+
const component = resolveComponent(config, ref);
|
|
805
861
|
if (!component.propGroups || component.propGroups.length === 0) {
|
|
806
862
|
console.log(JSON.stringify({
|
|
807
863
|
success: false,
|
|
@@ -824,16 +880,9 @@ function movePropGroup(componentName, options) {
|
|
|
824
880
|
parentGroupId: options.parent || null,
|
|
825
881
|
}));
|
|
826
882
|
}
|
|
827
|
-
function updateComponent(options) {
|
|
883
|
+
function updateComponent(ref, options) {
|
|
828
884
|
const { config, configPath } = loadConfig();
|
|
829
|
-
const component =
|
|
830
|
-
if (!component) {
|
|
831
|
-
console.log(JSON.stringify({
|
|
832
|
-
success: false,
|
|
833
|
-
error: `Component "${options.name}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
834
|
-
}));
|
|
835
|
-
process.exit(1);
|
|
836
|
-
}
|
|
885
|
+
const component = resolveComponent(config, ref);
|
|
837
886
|
if (options.isHeader !== undefined) {
|
|
838
887
|
if (options.isHeader) {
|
|
839
888
|
component.isHeader = true;
|
|
@@ -1086,14 +1135,16 @@ export function createConfigCommand() {
|
|
|
1086
1135
|
.option("--type <type>", "Component type: section or component", "component")
|
|
1087
1136
|
.option("--isHeader", "Mark this section as the store header (only for type: section)")
|
|
1088
1137
|
.option("--isFooter", "Mark this section as the store footer (only for type: section)")
|
|
1089
|
-
.option("--props <json>", "JSON array of props
|
|
1138
|
+
.option("--props <json>", "JSON array of props. Required per entry: name, type. Optional: displayName (auto from name), required, description, defaultValue, groupId, typeId (TYPE props), enumTypeId (ENUM props), filteredComponentIds, privateVarMap. " +
|
|
1139
|
+
"Example: '[{\"name\":\"title\",\"type\":\"TEXT\",\"required\":true,\"defaultValue\":\"Hello\",\"groupId\":\"basic\"}]'")
|
|
1090
1140
|
.action((options) => {
|
|
1091
1141
|
addComponent(options.name, options);
|
|
1092
1142
|
});
|
|
1093
1143
|
config
|
|
1094
1144
|
.command("add-prop")
|
|
1095
1145
|
.description("Add a prop to a component")
|
|
1096
|
-
.
|
|
1146
|
+
.option("--component-id <id>", "Component id (preferred; from `config list-components`)")
|
|
1147
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1097
1148
|
.requiredOption("--name <name>", "Prop name (camelCase)")
|
|
1098
1149
|
.requiredOption("--displayName <displayName>", "Display name in editor")
|
|
1099
1150
|
.requiredOption("--type <type>", `Prop type: ${PROP_TYPES.join(", ")}`)
|
|
@@ -1106,12 +1157,13 @@ export function createConfigCommand() {
|
|
|
1106
1157
|
.option("--filteredComponentIds <json>", "JSON array of component IDs to restrict selection (for COMPONENT/COMPONENT_LIST)")
|
|
1107
1158
|
.option("--privateVarMap <json>", 'JSON object mapping variable keys to {id, typeId} (for COMPONENT/COMPONENT_LIST)')
|
|
1108
1159
|
.action((options) => {
|
|
1109
|
-
addProp(options.component, options);
|
|
1160
|
+
addProp({ id: options.componentId, name: options.component }, options);
|
|
1110
1161
|
});
|
|
1111
1162
|
config
|
|
1112
1163
|
.command("update-prop")
|
|
1113
1164
|
.description("Update a prop on a component")
|
|
1114
|
-
.
|
|
1165
|
+
.option("--component-id <id>", "Component id (preferred; from `config list-components`)")
|
|
1166
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1115
1167
|
.requiredOption("--prop <propName>", "Prop name to update")
|
|
1116
1168
|
.option("--displayName <displayName>", "New display name")
|
|
1117
1169
|
.option("--type <type>", "New prop type")
|
|
@@ -1124,76 +1176,89 @@ export function createConfigCommand() {
|
|
|
1124
1176
|
.option("--filteredComponentIds <json>", "JSON array of component IDs (use 'none' to clear)")
|
|
1125
1177
|
.option("--privateVarMap <json>", "JSON object mapping variable keys to {id, typeId} (use 'none' to clear)")
|
|
1126
1178
|
.action((options) => {
|
|
1127
|
-
updateProp(options.component, options);
|
|
1179
|
+
updateProp({ id: options.componentId, name: options.component }, options);
|
|
1128
1180
|
});
|
|
1129
1181
|
config
|
|
1130
1182
|
.command("remove-prop")
|
|
1131
1183
|
.description("Remove a prop from a component")
|
|
1132
|
-
.
|
|
1184
|
+
.option("--component-id <id>", "Component id (preferred; from `config list-components`)")
|
|
1185
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1133
1186
|
.requiredOption("--prop <propName>", "Prop name to remove")
|
|
1134
1187
|
.action((options) => {
|
|
1135
|
-
removeProp(options.component, options);
|
|
1188
|
+
removeProp({ id: options.componentId, name: options.component }, options);
|
|
1136
1189
|
});
|
|
1137
1190
|
config
|
|
1138
1191
|
.command("update-component")
|
|
1139
|
-
.description("Update a component's metadata (isHeader, isFooter)")
|
|
1140
|
-
.
|
|
1192
|
+
.description("Update a component's metadata (isHeader, isFooter). Identify by --id (preferred) or exact --name.")
|
|
1193
|
+
.option("--id <id>", "Component id (preferred; from `config list-components`)")
|
|
1194
|
+
.option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1141
1195
|
.option("--isHeader", "Mark as store header")
|
|
1142
1196
|
.option("--no-isHeader", "Unmark as store header")
|
|
1143
1197
|
.option("--isFooter", "Mark as store footer")
|
|
1144
1198
|
.option("--no-isFooter", "Unmark as store footer")
|
|
1145
1199
|
.action((options) => {
|
|
1146
|
-
updateComponent(options);
|
|
1200
|
+
updateComponent({ id: options.id, name: options.name }, options);
|
|
1147
1201
|
});
|
|
1148
1202
|
config
|
|
1149
1203
|
.command("remove-component")
|
|
1150
|
-
.description("Remove a component from the project (deletes files)")
|
|
1151
|
-
.
|
|
1204
|
+
.description("Remove a component from the project (deletes files). Identify by --id (preferred) or exact --name.")
|
|
1205
|
+
.option("--id <id>", "Component id (preferred; from `config list-components`)")
|
|
1206
|
+
.option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1152
1207
|
.action((options) => {
|
|
1153
|
-
removeComponent(options);
|
|
1208
|
+
removeComponent({ id: options.id, name: options.name });
|
|
1154
1209
|
});
|
|
1155
1210
|
config
|
|
1156
1211
|
.command("add-prop-group")
|
|
1157
1212
|
.description("Add a prop group to a component")
|
|
1158
|
-
.
|
|
1213
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1214
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1159
1215
|
.requiredOption("--id <id>", "Group ID (unique within component, kebab-case)")
|
|
1160
1216
|
.requiredOption("--name <name>", "Display name in editor")
|
|
1161
1217
|
.option("--description <description>", "Group description")
|
|
1162
1218
|
.option("--parent <parentId>", "Parent group ID (for nesting, max 1 level)")
|
|
1163
1219
|
.action((options) => {
|
|
1164
|
-
addPropGroup(options.component, options);
|
|
1220
|
+
addPropGroup({ id: options.componentId, name: options.component }, options);
|
|
1165
1221
|
});
|
|
1166
1222
|
config
|
|
1167
1223
|
.command("update-prop-group")
|
|
1168
1224
|
.description("Update a prop group on a component")
|
|
1169
|
-
.
|
|
1225
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1226
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1170
1227
|
.requiredOption("--id <id>", "Group ID to update")
|
|
1171
1228
|
.option("--name <name>", "New display name")
|
|
1172
1229
|
.option("--description <description>", "New description")
|
|
1173
1230
|
.action((options) => {
|
|
1174
|
-
updatePropGroup(options.component, options);
|
|
1231
|
+
updatePropGroup({ id: options.componentId, name: options.component }, options);
|
|
1175
1232
|
});
|
|
1176
1233
|
config
|
|
1177
1234
|
.command("remove-prop-group")
|
|
1178
1235
|
.description("Remove a prop group from a component (props become ungrouped)")
|
|
1179
|
-
.
|
|
1236
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1237
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1180
1238
|
.requiredOption("--id <id>", "Group ID to remove")
|
|
1181
1239
|
.action((options) => {
|
|
1182
|
-
removePropGroup(options.component, options);
|
|
1240
|
+
removePropGroup({ id: options.componentId, name: options.component }, options);
|
|
1183
1241
|
});
|
|
1184
1242
|
config
|
|
1185
1243
|
.command("move-prop-group")
|
|
1186
1244
|
.description("Move a prop group to a different parent or position (for drag-and-drop reordering)")
|
|
1187
|
-
.
|
|
1245
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1246
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1188
1247
|
.requiredOption("--id <id>", "Group ID to move")
|
|
1189
1248
|
.option("--parent <parentId>", "Target parent group ID (omit to move to root)")
|
|
1190
1249
|
.option("--index <index>", "Zero-based insertion index within the target parent (appends when omitted)", v => parseInt(v, 10))
|
|
1191
1250
|
.action((options) => {
|
|
1192
|
-
movePropGroup(options.component, options);
|
|
1251
|
+
movePropGroup({ id: options.componentId, name: options.component }, options);
|
|
1252
|
+
});
|
|
1253
|
+
config
|
|
1254
|
+
.command("list-components")
|
|
1255
|
+
.description("List all components and their props (with canonical ids for use with --id flags)")
|
|
1256
|
+
.action(() => {
|
|
1257
|
+
listComponents();
|
|
1193
1258
|
});
|
|
1194
1259
|
config
|
|
1195
1260
|
.command("list")
|
|
1196
|
-
.description("
|
|
1261
|
+
.description("Alias for `list-components` (kept for backwards compatibility)")
|
|
1197
1262
|
.action(() => {
|
|
1198
1263
|
listComponents();
|
|
1199
1264
|
});
|