@ikas/component-cli 1.4.0-beta.6 → 1.4.0-beta.60
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-sections-to-page.d.ts +3 -0
- package/dist/commands/add-sections-to-page.d.ts.map +1 -0
- package/dist/commands/add-sections-to-page.js +39 -0
- package/dist/commands/add-sections-to-page.js.map +1 -0
- 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/build.d.ts.map +1 -1
- package/dist/commands/build.js +5 -165
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +230 -114
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/create-design-tokens.d.ts +7 -0
- package/dist/commands/create-design-tokens.d.ts.map +1 -0
- package/dist/commands/create-design-tokens.js +127 -0
- package/dist/commands/create-design-tokens.js.map +1 -0
- package/dist/commands/create-global-variable.d.ts +3 -0
- package/dist/commands/create-global-variable.d.ts.map +1 -0
- package/dist/commands/create-global-variable.js +53 -0
- package/dist/commands/create-global-variable.js.map +1 -0
- package/dist/commands/create-page.d.ts +3 -0
- package/dist/commands/create-page.d.ts.map +1 -0
- package/dist/commands/create-page.js +31 -0
- package/dist/commands/create-page.js.map +1 -0
- package/dist/commands/create.d.ts +3 -8
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +175 -8
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/delete-theme-globals.d.ts +4 -0
- package/dist/commands/delete-theme-globals.d.ts.map +1 -0
- package/dist/commands/delete-theme-globals.js +48 -0
- package/dist/commands/delete-theme-globals.js.map +1 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +220 -25
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/get-component-props.d.ts +3 -0
- package/dist/commands/get-component-props.d.ts.map +1 -0
- package/dist/commands/get-component-props.js +32 -0
- package/dist/commands/get-component-props.js.map +1 -0
- package/dist/commands/get-page-by-type.d.ts +3 -0
- package/dist/commands/get-page-by-type.d.ts.map +1 -0
- package/dist/commands/get-page-by-type.js +25 -0
- package/dist/commands/get-page-by-type.js.map +1 -0
- package/dist/commands/get-section-values.d.ts +3 -0
- package/dist/commands/get-section-values.d.ts.map +1 -0
- package/dist/commands/get-section-values.js +39 -0
- package/dist/commands/get-section-values.js.map +1 -0
- 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-entities.d.ts +3 -0
- package/dist/commands/list-entities.d.ts.map +1 -0
- package/dist/commands/list-entities.js +32 -0
- package/dist/commands/list-entities.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/list-theme-globals.d.ts +3 -0
- package/dist/commands/list-theme-globals.d.ts.map +1 -0
- package/dist/commands/list-theme-globals.js +22 -0
- package/dist/commands/list-theme-globals.js.map +1 -0
- package/dist/commands/publish-theme.d.ts +3 -0
- package/dist/commands/publish-theme.d.ts.map +1 -0
- package/dist/commands/publish-theme.js +29 -0
- package/dist/commands/publish-theme.js.map +1 -0
- package/dist/commands/search-products.d.ts +3 -0
- package/dist/commands/search-products.d.ts.map +1 -0
- package/dist/commands/search-products.js +40 -0
- package/dist/commands/search-products.js.map +1 -0
- package/dist/commands/update-global-variable.d.ts +3 -0
- package/dist/commands/update-global-variable.d.ts.map +1 -0
- package/dist/commands/update-global-variable.js +47 -0
- package/dist/commands/update-global-variable.js.map +1 -0
- package/dist/commands/update-page-sections.d.ts +3 -0
- package/dist/commands/update-page-sections.d.ts.map +1 -0
- package/dist/commands/update-page-sections.js +39 -0
- package/dist/commands/update-page-sections.js.map +1 -0
- 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 +38 -0
- package/dist/commands/upload-image.js.map +1 -0
- package/dist/commands/upload-images.d.ts +3 -0
- package/dist/commands/upload-images.d.ts.map +1 -0
- package/dist/commands/upload-images.js +48 -0
- package/dist/commands/upload-images.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +11 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/compile.d.ts +4 -1
- package/dist/utils/compile.d.ts.map +1 -1
- package/dist/utils/compile.js +517 -48
- package/dist/utils/compile.js.map +1 -1
- package/dist/utils/component-helpers.d.ts +3 -3
- package/dist/utils/component-helpers.d.ts.map +1 -1
- package/dist/utils/component-helpers.js +75 -4
- 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 +116 -0
- package/dist/utils/editor-action-client.js.map +1 -0
- package/dist/utils/load-image.d.ts +16 -0
- package/dist/utils/load-image.d.ts.map +1 -0
- package/dist/utils/load-image.js +50 -0
- package/dist/utils/load-image.js.map +1 -0
- package/dist/utils/websocket-server.d.ts +52 -2
- package/dist/utils/websocket-server.d.ts.map +1 -1
- package/dist/utils/websocket-server.js +59 -1
- package/dist/utils/websocket-server.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/proxy.d.ts +0 -39
- package/dist/commands/proxy.d.ts.map +0 -1
- package/dist/commands/proxy.js +0 -212
- package/dist/commands/proxy.js.map +0 -1
package/dist/commands/config.js
CHANGED
|
@@ -17,9 +17,48 @@ 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);
|
|
@@ -105,6 +144,19 @@ function camelCaseToDisplayName(name) {
|
|
|
105
144
|
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
106
145
|
.replace(/^./, (c) => c.toUpperCase());
|
|
107
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
|
+
]);
|
|
108
160
|
/**
|
|
109
161
|
* Parse and validate the --props JSON flag for add-component.
|
|
110
162
|
* Returns validated ComponentProp[] or exits with error.
|
|
@@ -132,6 +184,16 @@ async function parsePropsFlag(propsJson, config, configPath) {
|
|
|
132
184
|
const props = [];
|
|
133
185
|
for (const raw of rawProps) {
|
|
134
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
|
+
}
|
|
135
197
|
if (!r.name || typeof r.name !== "string") {
|
|
136
198
|
console.log(JSON.stringify({
|
|
137
199
|
success: false,
|
|
@@ -172,6 +234,14 @@ async function parsePropsFlag(propsJson, config, configPath) {
|
|
|
172
234
|
}));
|
|
173
235
|
process.exit(1);
|
|
174
236
|
}
|
|
237
|
+
// Validate LINK / LIST_OF_LINK defaultValue shape (reject JSON strings and legacy { href })
|
|
238
|
+
if ((propType === "LINK" || propType === "LIST_OF_LINK") && r.defaultValue !== undefined) {
|
|
239
|
+
const linkError = validateLinkDefaultValue(propType, r.defaultValue, r.name);
|
|
240
|
+
if (linkError) {
|
|
241
|
+
console.log(JSON.stringify({ success: false, error: linkError }));
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
175
245
|
// Auto-generate displayName if omitted
|
|
176
246
|
const displayName = typeof r.displayName === "string" && r.displayName
|
|
177
247
|
? r.displayName
|
|
@@ -322,16 +392,9 @@ async function addComponent(name, options) {
|
|
|
322
392
|
],
|
|
323
393
|
}));
|
|
324
394
|
}
|
|
325
|
-
async function addProp(
|
|
395
|
+
async function addProp(ref, options) {
|
|
326
396
|
const { config, configPath } = loadConfig();
|
|
327
|
-
const component =
|
|
328
|
-
if (!component) {
|
|
329
|
-
console.log(JSON.stringify({
|
|
330
|
-
success: false,
|
|
331
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
332
|
-
}));
|
|
333
|
-
process.exit(1);
|
|
334
|
-
}
|
|
397
|
+
const component = resolveComponent(config, ref);
|
|
335
398
|
// Validate prop type
|
|
336
399
|
const propType = options.type.toUpperCase();
|
|
337
400
|
if (!PROP_TYPES.includes(propType)) {
|
|
@@ -434,14 +497,22 @@ async function addProp(componentName, options) {
|
|
|
434
497
|
process.exit(1);
|
|
435
498
|
}
|
|
436
499
|
}
|
|
500
|
+
const parsedDefaultValue = options.defaultValue !== undefined ? parseDefaultValue(options.defaultValue, propType) : undefined;
|
|
501
|
+
if ((propType === "LINK" || propType === "LIST_OF_LINK") && parsedDefaultValue !== undefined) {
|
|
502
|
+
const linkError = validateLinkDefaultValue(propType, parsedDefaultValue, options.name);
|
|
503
|
+
if (linkError) {
|
|
504
|
+
console.log(JSON.stringify({ success: false, error: linkError }));
|
|
505
|
+
process.exit(1);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
437
508
|
const newProp = {
|
|
438
509
|
name: options.name,
|
|
439
510
|
displayName: options.displayName,
|
|
440
511
|
type: propType,
|
|
441
512
|
required: options.required ?? false,
|
|
442
513
|
...(options.description ? { description: options.description } : {}),
|
|
443
|
-
...(
|
|
444
|
-
? { defaultValue:
|
|
514
|
+
...(parsedDefaultValue !== undefined
|
|
515
|
+
? { defaultValue: parsedDefaultValue }
|
|
445
516
|
: {}),
|
|
446
517
|
...(options.group ? { groupId: options.group } : {}),
|
|
447
518
|
...(options.typeId ? { typeId: options.typeId } : {}),
|
|
@@ -475,20 +546,73 @@ function parseDefaultValue(value, propType) {
|
|
|
475
546
|
return Number(value);
|
|
476
547
|
case "BOOLEAN":
|
|
477
548
|
return value === "true";
|
|
549
|
+
case "LINK":
|
|
550
|
+
case "LIST_OF_LINK":
|
|
551
|
+
// The --default-value flag arrives as a string; LINK values must be stored as a
|
|
552
|
+
// typed object. Parse it here; if it is not valid JSON, return the raw string so
|
|
553
|
+
// validateLinkDefaultValue can report a precise error.
|
|
554
|
+
try {
|
|
555
|
+
return JSON.parse(value);
|
|
556
|
+
}
|
|
557
|
+
catch {
|
|
558
|
+
return value;
|
|
559
|
+
}
|
|
478
560
|
default:
|
|
479
561
|
return value;
|
|
480
562
|
}
|
|
481
563
|
}
|
|
482
|
-
|
|
564
|
+
const VALID_LINK_TYPES = ["PAGE", "EXTERNAL", "FILE"];
|
|
565
|
+
const LINK_SHAPE_HELP = 'A link must be an object: { "linkType": "EXTERNAL", "label": "Text", "externalLink": "https://...", "subLinks": [] } ' +
|
|
566
|
+
'for external links, or { "linkType": "PAGE", "label": "Text", "pageType": "INDEX", "subLinks": [] } for store pages. ' +
|
|
567
|
+
"Do NOT pass a JSON string or a { label, href } shape.";
|
|
568
|
+
// Returns the index of the first array element that fails `fn`, as an error string, or null.
|
|
569
|
+
const firstError = (arr, fn) => arr.reduce((acc, item, index) => acc ?? fn(item, index), null);
|
|
570
|
+
const validateSingleLink = (link, propName, path) => {
|
|
571
|
+
const where = `defaultValue for prop "${propName}"${path}`;
|
|
572
|
+
if (typeof link === "string") {
|
|
573
|
+
return `${where} is a JSON string but must be an object. ${LINK_SHAPE_HELP}`;
|
|
574
|
+
}
|
|
575
|
+
if (!link || typeof link !== "object" || Array.isArray(link)) {
|
|
576
|
+
return `${where} must be a link object. ${LINK_SHAPE_HELP}`;
|
|
577
|
+
}
|
|
578
|
+
const l = link;
|
|
579
|
+
if ("href" in l && !("linkType" in l)) {
|
|
580
|
+
return `${where} uses a legacy { href } shape without "linkType". Use "linkType" + "externalLink"/"pageType" instead. ${LINK_SHAPE_HELP}`;
|
|
581
|
+
}
|
|
582
|
+
if (typeof l.linkType !== "string" || !VALID_LINK_TYPES.includes(l.linkType)) {
|
|
583
|
+
return `${where} must have a valid "linkType" (one of ${VALID_LINK_TYPES.join(", ")}). ${LINK_SHAPE_HELP}`;
|
|
584
|
+
}
|
|
585
|
+
if (l.subLinks !== undefined && !Array.isArray(l.subLinks)) {
|
|
586
|
+
return `${where}: "subLinks" must be an array (use [] when there are none).`;
|
|
587
|
+
}
|
|
588
|
+
if (Array.isArray(l.subLinks)) {
|
|
589
|
+
return firstError(l.subLinks, (sl, i) => validateSingleLink(sl, propName, `${path}.subLinks[${i}]`));
|
|
590
|
+
}
|
|
591
|
+
return null;
|
|
592
|
+
};
|
|
593
|
+
// Validates a LINK / LIST_OF_LINK defaultValue. Returns an error message, or null if valid.
|
|
594
|
+
// These defaults are a frequent source of bad data: agents tend to pass a JSON string or a
|
|
595
|
+
// legacy { label, href } shape. Rejecting them at authoring time keeps malformed link values
|
|
596
|
+
// out of published themes.
|
|
597
|
+
function validateLinkDefaultValue(propType, value, propName) {
|
|
598
|
+
if (value === undefined || value === null)
|
|
599
|
+
return null;
|
|
600
|
+
if (propType === "LINK") {
|
|
601
|
+
return validateSingleLink(value, propName, "");
|
|
602
|
+
}
|
|
603
|
+
// LIST_OF_LINK
|
|
604
|
+
if (typeof value === "string") {
|
|
605
|
+
return `defaultValue for prop "${propName}" is a JSON string but must be an object { "links": [...] }. ${LINK_SHAPE_HELP}`;
|
|
606
|
+
}
|
|
607
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !Array.isArray(value.links)) {
|
|
608
|
+
return `defaultValue for prop "${propName}" must be an object with a "links" array: { "links": [ <link>, ... ] }. ${LINK_SHAPE_HELP}`;
|
|
609
|
+
}
|
|
610
|
+
const links = value.links;
|
|
611
|
+
return firstError(links, (link, i) => validateSingleLink(link, propName, `.links[${i}]`));
|
|
612
|
+
}
|
|
613
|
+
function updateProp(ref, options) {
|
|
483
614
|
const { config, configPath } = loadConfig();
|
|
484
|
-
const component =
|
|
485
|
-
if (!component) {
|
|
486
|
-
console.log(JSON.stringify({
|
|
487
|
-
success: false,
|
|
488
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
489
|
-
}));
|
|
490
|
-
process.exit(1);
|
|
491
|
-
}
|
|
615
|
+
const component = resolveComponent(config, ref);
|
|
492
616
|
const propIndex = component.props.findIndex((p) => p.name === options.prop);
|
|
493
617
|
if (propIndex === -1) {
|
|
494
618
|
console.log(JSON.stringify({
|
|
@@ -519,7 +643,15 @@ function updateProp(componentName, options) {
|
|
|
519
643
|
prop.description = options.description || undefined;
|
|
520
644
|
}
|
|
521
645
|
if (options.defaultValue !== undefined) {
|
|
522
|
-
|
|
646
|
+
const parsed = parseDefaultValue(options.defaultValue, prop.type);
|
|
647
|
+
if (prop.type === "LINK" || prop.type === "LIST_OF_LINK") {
|
|
648
|
+
const linkError = validateLinkDefaultValue(prop.type, parsed, prop.name);
|
|
649
|
+
if (linkError) {
|
|
650
|
+
console.log(JSON.stringify({ success: false, error: linkError }));
|
|
651
|
+
process.exit(1);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
prop.defaultValue = parsed;
|
|
523
655
|
}
|
|
524
656
|
if (options.group !== undefined) {
|
|
525
657
|
if (options.group === "" || options.group === "none") {
|
|
@@ -622,16 +754,9 @@ function updateProp(componentName, options) {
|
|
|
622
754
|
},
|
|
623
755
|
}));
|
|
624
756
|
}
|
|
625
|
-
function removeProp(
|
|
757
|
+
function removeProp(ref, options) {
|
|
626
758
|
const { config, configPath } = loadConfig();
|
|
627
|
-
const component =
|
|
628
|
-
if (!component) {
|
|
629
|
-
console.log(JSON.stringify({
|
|
630
|
-
success: false,
|
|
631
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
632
|
-
}));
|
|
633
|
-
process.exit(1);
|
|
634
|
-
}
|
|
759
|
+
const component = resolveComponent(config, ref);
|
|
635
760
|
const propIndex = component.props.findIndex((p) => p.name === options.prop);
|
|
636
761
|
if (propIndex === -1) {
|
|
637
762
|
console.log(JSON.stringify({
|
|
@@ -652,21 +777,30 @@ function removeProp(componentName, options) {
|
|
|
652
777
|
remainingProps: component.props.map((p) => p.name),
|
|
653
778
|
}));
|
|
654
779
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
780
|
+
/**
|
|
781
|
+
* Strip a deleted component's ID from every other component's COMPONENT/COMPONENT_LIST
|
|
782
|
+
* `filteredComponentIds` allowlist. Empty arrays are deleted to keep the field optional
|
|
783
|
+
* (mirrors the editor-side convention).
|
|
784
|
+
*/
|
|
785
|
+
function pruneFilteredComponentIdRefs(config, removedId) {
|
|
786
|
+
for (const component of config.components) {
|
|
787
|
+
for (const prop of component.props || []) {
|
|
788
|
+
if (!prop.filteredComponentIds)
|
|
789
|
+
continue;
|
|
790
|
+
prop.filteredComponentIds = prop.filteredComponentIds.filter((id) => id !== removedId);
|
|
791
|
+
if (prop.filteredComponentIds.length === 0)
|
|
792
|
+
delete prop.filteredComponentIds;
|
|
793
|
+
}
|
|
665
794
|
}
|
|
666
|
-
|
|
795
|
+
}
|
|
796
|
+
function removeComponent(ref) {
|
|
797
|
+
const { config, configPath } = loadConfig();
|
|
798
|
+
const component = resolveComponent(config, ref);
|
|
799
|
+
const componentIndex = config.components.indexOf(component);
|
|
667
800
|
const componentDir = path.resolve(process.cwd(), path.dirname(component.entry));
|
|
668
|
-
// Remove component from config
|
|
801
|
+
// Remove component from config and strip orphaned references from remaining components
|
|
669
802
|
config.components.splice(componentIndex, 1);
|
|
803
|
+
pruneFilteredComponentIdRefs(config, component.id);
|
|
670
804
|
saveConfig(configPath, config);
|
|
671
805
|
// Remove component directory
|
|
672
806
|
if (fs.existsSync(componentDir)) {
|
|
@@ -676,21 +810,15 @@ function removeComponent(options) {
|
|
|
676
810
|
updateBarrelExport(process.cwd(), getComponentNames(config));
|
|
677
811
|
console.log(JSON.stringify({
|
|
678
812
|
success: true,
|
|
679
|
-
|
|
813
|
+
removedComponentId: component.id,
|
|
814
|
+
removedComponentName: component.name,
|
|
680
815
|
removedDirectory: path.relative(process.cwd(), componentDir),
|
|
681
|
-
remainingComponents:
|
|
816
|
+
remainingComponents: config.components.map((c) => ({ id: c.id, name: c.name })),
|
|
682
817
|
}));
|
|
683
818
|
}
|
|
684
|
-
function addPropGroup(
|
|
819
|
+
function addPropGroup(ref, options) {
|
|
685
820
|
const { config, configPath } = loadConfig();
|
|
686
|
-
const component =
|
|
687
|
-
if (!component) {
|
|
688
|
-
console.log(JSON.stringify({
|
|
689
|
-
success: false,
|
|
690
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
691
|
-
}));
|
|
692
|
-
process.exit(1);
|
|
693
|
-
}
|
|
821
|
+
const component = resolveComponent(config, ref);
|
|
694
822
|
if (!component.propGroups)
|
|
695
823
|
component.propGroups = [];
|
|
696
824
|
// Check uniqueness
|
|
@@ -741,16 +869,9 @@ function addPropGroup(componentName, options) {
|
|
|
741
869
|
},
|
|
742
870
|
}));
|
|
743
871
|
}
|
|
744
|
-
function updatePropGroup(
|
|
872
|
+
function updatePropGroup(ref, options) {
|
|
745
873
|
const { config, configPath } = loadConfig();
|
|
746
|
-
const component =
|
|
747
|
-
if (!component) {
|
|
748
|
-
console.log(JSON.stringify({
|
|
749
|
-
success: false,
|
|
750
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
751
|
-
}));
|
|
752
|
-
process.exit(1);
|
|
753
|
-
}
|
|
874
|
+
const component = resolveComponent(config, ref);
|
|
754
875
|
if (!component.propGroups || component.propGroups.length === 0) {
|
|
755
876
|
console.log(JSON.stringify({
|
|
756
877
|
success: false,
|
|
@@ -780,16 +901,9 @@ function updatePropGroup(componentName, options) {
|
|
|
780
901
|
},
|
|
781
902
|
}));
|
|
782
903
|
}
|
|
783
|
-
function removePropGroup(
|
|
904
|
+
function removePropGroup(ref, options) {
|
|
784
905
|
const { config, configPath } = loadConfig();
|
|
785
|
-
const component =
|
|
786
|
-
if (!component) {
|
|
787
|
-
console.log(JSON.stringify({
|
|
788
|
-
success: false,
|
|
789
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
790
|
-
}));
|
|
791
|
-
process.exit(1);
|
|
792
|
-
}
|
|
906
|
+
const component = resolveComponent(config, ref);
|
|
793
907
|
if (!component.propGroups || component.propGroups.length === 0) {
|
|
794
908
|
console.log(JSON.stringify({
|
|
795
909
|
success: false,
|
|
@@ -825,16 +939,9 @@ function removePropGroup(componentName, options) {
|
|
|
825
939
|
remainingPropGroups: component.propGroups.map(g => g.id),
|
|
826
940
|
}));
|
|
827
941
|
}
|
|
828
|
-
function movePropGroup(
|
|
942
|
+
function movePropGroup(ref, options) {
|
|
829
943
|
const { config, configPath } = loadConfig();
|
|
830
|
-
const component =
|
|
831
|
-
if (!component) {
|
|
832
|
-
console.log(JSON.stringify({
|
|
833
|
-
success: false,
|
|
834
|
-
error: `Component "${componentName}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
835
|
-
}));
|
|
836
|
-
process.exit(1);
|
|
837
|
-
}
|
|
944
|
+
const component = resolveComponent(config, ref);
|
|
838
945
|
if (!component.propGroups || component.propGroups.length === 0) {
|
|
839
946
|
console.log(JSON.stringify({
|
|
840
947
|
success: false,
|
|
@@ -857,16 +964,9 @@ function movePropGroup(componentName, options) {
|
|
|
857
964
|
parentGroupId: options.parent || null,
|
|
858
965
|
}));
|
|
859
966
|
}
|
|
860
|
-
function updateComponent(options) {
|
|
967
|
+
function updateComponent(ref, options) {
|
|
861
968
|
const { config, configPath } = loadConfig();
|
|
862
|
-
const component =
|
|
863
|
-
if (!component) {
|
|
864
|
-
console.log(JSON.stringify({
|
|
865
|
-
success: false,
|
|
866
|
-
error: `Component "${options.name}" not found. Available: ${getComponentNames(config).join(", ")}`,
|
|
867
|
-
}));
|
|
868
|
-
process.exit(1);
|
|
869
|
-
}
|
|
969
|
+
const component = resolveComponent(config, ref);
|
|
870
970
|
if (options.isHeader !== undefined) {
|
|
871
971
|
if (options.isHeader) {
|
|
872
972
|
component.isHeader = true;
|
|
@@ -1119,14 +1219,16 @@ export function createConfigCommand() {
|
|
|
1119
1219
|
.option("--type <type>", "Component type: section or component", "component")
|
|
1120
1220
|
.option("--isHeader", "Mark this section as the store header (only for type: section)")
|
|
1121
1221
|
.option("--isFooter", "Mark this section as the store footer (only for type: section)")
|
|
1122
|
-
.option("--props <json>", "JSON array of props
|
|
1222
|
+
.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. " +
|
|
1223
|
+
"Example: '[{\"name\":\"title\",\"type\":\"TEXT\",\"required\":true,\"defaultValue\":\"Hello\",\"groupId\":\"basic\"}]'")
|
|
1123
1224
|
.action((options) => {
|
|
1124
1225
|
addComponent(options.name, options);
|
|
1125
1226
|
});
|
|
1126
1227
|
config
|
|
1127
1228
|
.command("add-prop")
|
|
1128
1229
|
.description("Add a prop to a component")
|
|
1129
|
-
.
|
|
1230
|
+
.option("--component-id <id>", "Component id (preferred; from `config list-components`)")
|
|
1231
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1130
1232
|
.requiredOption("--name <name>", "Prop name (camelCase)")
|
|
1131
1233
|
.requiredOption("--displayName <displayName>", "Display name in editor")
|
|
1132
1234
|
.requiredOption("--type <type>", `Prop type: ${PROP_TYPES.join(", ")}`)
|
|
@@ -1139,12 +1241,13 @@ export function createConfigCommand() {
|
|
|
1139
1241
|
.option("--filteredComponentIds <json>", "JSON array of component IDs to restrict selection (for COMPONENT/COMPONENT_LIST)")
|
|
1140
1242
|
.option("--privateVarMap <json>", 'JSON object mapping variable keys to {id, typeId} (for COMPONENT/COMPONENT_LIST)')
|
|
1141
1243
|
.action((options) => {
|
|
1142
|
-
addProp(options.component, options);
|
|
1244
|
+
addProp({ id: options.componentId, name: options.component }, options);
|
|
1143
1245
|
});
|
|
1144
1246
|
config
|
|
1145
1247
|
.command("update-prop")
|
|
1146
1248
|
.description("Update a prop on a component")
|
|
1147
|
-
.
|
|
1249
|
+
.option("--component-id <id>", "Component id (preferred; from `config list-components`)")
|
|
1250
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1148
1251
|
.requiredOption("--prop <propName>", "Prop name to update")
|
|
1149
1252
|
.option("--displayName <displayName>", "New display name")
|
|
1150
1253
|
.option("--type <type>", "New prop type")
|
|
@@ -1157,76 +1260,89 @@ export function createConfigCommand() {
|
|
|
1157
1260
|
.option("--filteredComponentIds <json>", "JSON array of component IDs (use 'none' to clear)")
|
|
1158
1261
|
.option("--privateVarMap <json>", "JSON object mapping variable keys to {id, typeId} (use 'none' to clear)")
|
|
1159
1262
|
.action((options) => {
|
|
1160
|
-
updateProp(options.component, options);
|
|
1263
|
+
updateProp({ id: options.componentId, name: options.component }, options);
|
|
1161
1264
|
});
|
|
1162
1265
|
config
|
|
1163
1266
|
.command("remove-prop")
|
|
1164
1267
|
.description("Remove a prop from a component")
|
|
1165
|
-
.
|
|
1268
|
+
.option("--component-id <id>", "Component id (preferred; from `config list-components`)")
|
|
1269
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1166
1270
|
.requiredOption("--prop <propName>", "Prop name to remove")
|
|
1167
1271
|
.action((options) => {
|
|
1168
|
-
removeProp(options.component, options);
|
|
1272
|
+
removeProp({ id: options.componentId, name: options.component }, options);
|
|
1169
1273
|
});
|
|
1170
1274
|
config
|
|
1171
1275
|
.command("update-component")
|
|
1172
|
-
.description("Update a component's metadata (isHeader, isFooter)")
|
|
1173
|
-
.
|
|
1276
|
+
.description("Update a component's metadata (isHeader, isFooter). Identify by --id (preferred) or exact --name.")
|
|
1277
|
+
.option("--id <id>", "Component id (preferred; from `config list-components`)")
|
|
1278
|
+
.option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1174
1279
|
.option("--isHeader", "Mark as store header")
|
|
1175
1280
|
.option("--no-isHeader", "Unmark as store header")
|
|
1176
1281
|
.option("--isFooter", "Mark as store footer")
|
|
1177
1282
|
.option("--no-isFooter", "Unmark as store footer")
|
|
1178
1283
|
.action((options) => {
|
|
1179
|
-
updateComponent(options);
|
|
1284
|
+
updateComponent({ id: options.id, name: options.name }, options);
|
|
1180
1285
|
});
|
|
1181
1286
|
config
|
|
1182
1287
|
.command("remove-component")
|
|
1183
|
-
.description("Remove a component from the project (deletes files)")
|
|
1184
|
-
.
|
|
1288
|
+
.description("Remove a component from the project (deletes files). Identify by --id (preferred) or exact --name.")
|
|
1289
|
+
.option("--id <id>", "Component id (preferred; from `config list-components`)")
|
|
1290
|
+
.option("--name <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1185
1291
|
.action((options) => {
|
|
1186
|
-
removeComponent(options);
|
|
1292
|
+
removeComponent({ id: options.id, name: options.name });
|
|
1187
1293
|
});
|
|
1188
1294
|
config
|
|
1189
1295
|
.command("add-prop-group")
|
|
1190
1296
|
.description("Add a prop group to a component")
|
|
1191
|
-
.
|
|
1297
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1298
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1192
1299
|
.requiredOption("--id <id>", "Group ID (unique within component, kebab-case)")
|
|
1193
1300
|
.requiredOption("--name <name>", "Display name in editor")
|
|
1194
1301
|
.option("--description <description>", "Group description")
|
|
1195
1302
|
.option("--parent <parentId>", "Parent group ID (for nesting, max 1 level)")
|
|
1196
1303
|
.action((options) => {
|
|
1197
|
-
addPropGroup(options.component, options);
|
|
1304
|
+
addPropGroup({ id: options.componentId, name: options.component }, options);
|
|
1198
1305
|
});
|
|
1199
1306
|
config
|
|
1200
1307
|
.command("update-prop-group")
|
|
1201
1308
|
.description("Update a prop group on a component")
|
|
1202
|
-
.
|
|
1309
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1310
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1203
1311
|
.requiredOption("--id <id>", "Group ID to update")
|
|
1204
1312
|
.option("--name <name>", "New display name")
|
|
1205
1313
|
.option("--description <description>", "New description")
|
|
1206
1314
|
.action((options) => {
|
|
1207
|
-
updatePropGroup(options.component, options);
|
|
1315
|
+
updatePropGroup({ id: options.componentId, name: options.component }, options);
|
|
1208
1316
|
});
|
|
1209
1317
|
config
|
|
1210
1318
|
.command("remove-prop-group")
|
|
1211
1319
|
.description("Remove a prop group from a component (props become ungrouped)")
|
|
1212
|
-
.
|
|
1320
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1321
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1213
1322
|
.requiredOption("--id <id>", "Group ID to remove")
|
|
1214
1323
|
.action((options) => {
|
|
1215
|
-
removePropGroup(options.component, options);
|
|
1324
|
+
removePropGroup({ id: options.componentId, name: options.component }, options);
|
|
1216
1325
|
});
|
|
1217
1326
|
config
|
|
1218
1327
|
.command("move-prop-group")
|
|
1219
1328
|
.description("Move a prop group to a different parent or position (for drag-and-drop reordering)")
|
|
1220
|
-
.
|
|
1329
|
+
.option("--component-id <componentId>", "Component id (preferred; from `config list-components`)")
|
|
1330
|
+
.option("--component <name>", "Component name — exact match (PascalCase, as stored in ikas.config.json)")
|
|
1221
1331
|
.requiredOption("--id <id>", "Group ID to move")
|
|
1222
1332
|
.option("--parent <parentId>", "Target parent group ID (omit to move to root)")
|
|
1223
1333
|
.option("--index <index>", "Zero-based insertion index within the target parent (appends when omitted)", v => parseInt(v, 10))
|
|
1224
1334
|
.action((options) => {
|
|
1225
|
-
movePropGroup(options.component, options);
|
|
1335
|
+
movePropGroup({ id: options.componentId, name: options.component }, options);
|
|
1336
|
+
});
|
|
1337
|
+
config
|
|
1338
|
+
.command("list-components")
|
|
1339
|
+
.description("List all components and their props (with canonical ids for use with --id flags)")
|
|
1340
|
+
.action(() => {
|
|
1341
|
+
listComponents();
|
|
1226
1342
|
});
|
|
1227
1343
|
config
|
|
1228
1344
|
.command("list")
|
|
1229
|
-
.description("
|
|
1345
|
+
.description("Alias for `list-components` (kept for backwards compatibility)")
|
|
1230
1346
|
.action(() => {
|
|
1231
1347
|
listComponents();
|
|
1232
1348
|
});
|