@ikas/component-cli 1.4.0-beta.114 → 1.4.0-beta.115
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/config.d.ts.map +1 -1
- package/dist/commands/config.js +307 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +2 -0
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +1 -0
- package/dist/commands/publish.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/websocket-server.d.ts +7 -0
- package/dist/utils/websocket-server.d.ts.map +1 -1
- package/dist/utils/websocket-server.js.map +1 -1
- package/package.json +1 -1
- package/dist/commands/create.d.ts +0 -4
- package/dist/commands/create.d.ts.map +0 -1
- package/dist/commands/create.js +0 -176
- package/dist/commands/create.js.map +0 -1
- package/dist/utils/__tests__/detect-theme-global-name-lookup.test.d.ts +0 -2
- package/dist/utils/__tests__/detect-theme-global-name-lookup.test.d.ts.map +0 -1
- package/dist/utils/__tests__/detect-theme-global-name-lookup.test.js +0 -83
- package/dist/utils/__tests__/detect-theme-global-name-lookup.test.js.map +0 -1
- package/dist/utils/detect-theme-global-name-lookup.d.ts +0 -38
- package/dist/utils/detect-theme-global-name-lookup.d.ts.map +0 -1
- package/dist/utils/detect-theme-global-name-lookup.js +0 -173
- package/dist/utils/detect-theme-global-name-lookup.js.map +0 -1
|
@@ -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;AAwyEpC,wBAAgB,mBAAmB,IAAI,OAAO,CA+U7C"}
|
package/dist/commands/config.js
CHANGED
|
@@ -162,7 +162,54 @@ const ALLOWED_PROP_FIELDS = new Set([
|
|
|
162
162
|
"enumTypeId",
|
|
163
163
|
"filteredComponentIds",
|
|
164
164
|
"privateVarMap",
|
|
165
|
+
"numberRangeData",
|
|
165
166
|
]);
|
|
167
|
+
/**
|
|
168
|
+
* Validate/sanitize a numberRangeData object for a NUMBER_RANGE prop. Accepts an object
|
|
169
|
+
* or a JSON string. min/max/interval are truncated to integers; only a positive interval
|
|
170
|
+
* is kept (0/negative would yield an invalid slider step). Exits with a structured error
|
|
171
|
+
* on malformed input.
|
|
172
|
+
*/
|
|
173
|
+
function parseNumberRangeData(raw, propName) {
|
|
174
|
+
const fail = (error) => {
|
|
175
|
+
console.log(JSON.stringify({ success: false, error }));
|
|
176
|
+
process.exit(1);
|
|
177
|
+
};
|
|
178
|
+
let obj = raw;
|
|
179
|
+
if (typeof raw === "string") {
|
|
180
|
+
try {
|
|
181
|
+
obj = JSON.parse(raw);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
fail(`Invalid --numberRangeData JSON for prop "${propName}": ${raw}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
|
|
188
|
+
fail(`numberRangeData for prop "${propName}" must be an object { min, max, interval?, unit? }.`);
|
|
189
|
+
}
|
|
190
|
+
const o = obj;
|
|
191
|
+
const asInt = (v, field) => {
|
|
192
|
+
if (v === undefined || v === null)
|
|
193
|
+
return undefined;
|
|
194
|
+
if (typeof v !== "number" || !Number.isFinite(v)) {
|
|
195
|
+
fail(`numberRangeData.${field} for prop "${propName}" must be a finite number.`);
|
|
196
|
+
}
|
|
197
|
+
return Math.trunc(v);
|
|
198
|
+
};
|
|
199
|
+
const min = asInt(o.min, "min");
|
|
200
|
+
const max = asInt(o.max, "max");
|
|
201
|
+
const interval = asInt(o.interval, "interval");
|
|
202
|
+
const unit = typeof o.unit === "string" && o.unit.trim() ? o.unit.trim() : undefined;
|
|
203
|
+
if (min !== undefined && max !== undefined && min >= max) {
|
|
204
|
+
fail(`numberRangeData for prop "${propName}": min (${min}) must be less than max (${max}).`);
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
...(min !== undefined ? { min } : {}),
|
|
208
|
+
...(max !== undefined ? { max } : {}),
|
|
209
|
+
...(interval !== undefined && interval > 0 ? { interval } : {}),
|
|
210
|
+
...(unit ? { unit } : {}),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
166
213
|
/**
|
|
167
214
|
* Parse and validate the --props JSON flag for add-component.
|
|
168
215
|
* Returns validated ComponentProp[] or exits with error.
|
|
@@ -240,6 +287,8 @@ async function parsePropsFlag(propsJson, config, configPath) {
|
|
|
240
287
|
}));
|
|
241
288
|
process.exit(1);
|
|
242
289
|
}
|
|
290
|
+
// Dynamic (merchant-data reference) props can't carry a static default.
|
|
291
|
+
rejectDynamicDefault(r.name, propType, r.defaultValue);
|
|
243
292
|
// Validate LINK / LIST_OF_LINK defaultValue shape (reject JSON strings and legacy { href })
|
|
244
293
|
if ((propType === "LINK" || propType === "LIST_OF_LINK") &&
|
|
245
294
|
r.defaultValue !== undefined) {
|
|
@@ -258,6 +307,15 @@ async function parsePropsFlag(propsJson, config, configPath) {
|
|
|
258
307
|
process.exit(1);
|
|
259
308
|
}
|
|
260
309
|
}
|
|
310
|
+
// Validate TYPE (structured/style) defaultValue shape — must be an object (or an array for an
|
|
311
|
+
// _array typeId), never a bare string that would be emitted as a wrong-shaped default.
|
|
312
|
+
if (propType === "TYPE" && r.defaultValue !== undefined) {
|
|
313
|
+
const typeError = validateTypeDefaultValue(r.defaultValue, r.name, r.typeId);
|
|
314
|
+
if (typeError) {
|
|
315
|
+
console.log(JSON.stringify({ success: false, error: typeError }));
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
261
319
|
// Auto-generate displayName if omitted
|
|
262
320
|
const displayName = typeof r.displayName === "string" && r.displayName
|
|
263
321
|
? r.displayName
|
|
@@ -328,6 +386,9 @@ async function parsePropsFlag(propsJson, config, configPath) {
|
|
|
328
386
|
privateVarMap: r.privateVarMap,
|
|
329
387
|
}
|
|
330
388
|
: {}),
|
|
389
|
+
...(propType === "NUMBER_RANGE" && r.numberRangeData !== undefined
|
|
390
|
+
? { numberRangeData: parseNumberRangeData(r.numberRangeData, r.name) }
|
|
391
|
+
: {}),
|
|
331
392
|
};
|
|
332
393
|
props.push(prop);
|
|
333
394
|
}
|
|
@@ -557,6 +618,7 @@ async function addProp(ref, options) {
|
|
|
557
618
|
process.exit(1);
|
|
558
619
|
}
|
|
559
620
|
}
|
|
621
|
+
rejectDynamicDefault(options.name, propType, options.defaultValue);
|
|
560
622
|
const parsedDefaultValue = options.defaultValue !== undefined
|
|
561
623
|
? parseDefaultValue(options.defaultValue, propType)
|
|
562
624
|
: undefined;
|
|
@@ -576,6 +638,23 @@ async function addProp(ref, options) {
|
|
|
576
638
|
process.exit(1);
|
|
577
639
|
}
|
|
578
640
|
}
|
|
641
|
+
if (propType === "TYPE" && parsedDefaultValue !== undefined) {
|
|
642
|
+
const typeError = validateTypeDefaultValue(parsedDefaultValue, options.name, options.typeId);
|
|
643
|
+
if (typeError) {
|
|
644
|
+
console.log(JSON.stringify({ success: false, error: typeError }));
|
|
645
|
+
process.exit(1);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
const parsedNumberRangeData = propType === "NUMBER_RANGE" && options.numberRangeData !== undefined
|
|
649
|
+
? parseNumberRangeData(options.numberRangeData, options.name)
|
|
650
|
+
: undefined;
|
|
651
|
+
if (propType === "NUMBER_RANGE" && parsedDefaultValue !== undefined) {
|
|
652
|
+
const nrError = validateNumberRangeDefaultValue(parsedDefaultValue, parsedNumberRangeData, options.name);
|
|
653
|
+
if (nrError) {
|
|
654
|
+
console.log(JSON.stringify({ success: false, error: nrError }));
|
|
655
|
+
process.exit(1);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
579
658
|
const newProp = {
|
|
580
659
|
name: options.name,
|
|
581
660
|
displayName: options.displayName,
|
|
@@ -590,6 +669,9 @@ async function addProp(ref, options) {
|
|
|
590
669
|
...(options.enumTypeId ? { enumTypeId: options.enumTypeId } : {}),
|
|
591
670
|
...(parsedFilteredIds ? { filteredComponentIds: parsedFilteredIds } : {}),
|
|
592
671
|
...(parsedPrivateVarMap ? { privateVarMap: parsedPrivateVarMap } : {}),
|
|
672
|
+
...(parsedNumberRangeData
|
|
673
|
+
? { numberRangeData: parsedNumberRangeData }
|
|
674
|
+
: {}),
|
|
593
675
|
};
|
|
594
676
|
component.props.push(newProp);
|
|
595
677
|
saveConfig(configPath, config);
|
|
@@ -612,6 +694,9 @@ async function addProp(ref, options) {
|
|
|
612
694
|
...(newProp.privateVarMap
|
|
613
695
|
? { privateVarMap: newProp.privateVarMap }
|
|
614
696
|
: {}),
|
|
697
|
+
...(newProp.numberRangeData
|
|
698
|
+
? { numberRangeData: newProp.numberRangeData }
|
|
699
|
+
: {}),
|
|
615
700
|
},
|
|
616
701
|
}));
|
|
617
702
|
}
|
|
@@ -642,10 +727,66 @@ function parseDefaultValue(value, propType) {
|
|
|
642
727
|
catch {
|
|
643
728
|
return value;
|
|
644
729
|
}
|
|
730
|
+
case "NUMBER_RANGE":
|
|
731
|
+
// The default arrives as a string; a NUMBER_RANGE value is a typed object
|
|
732
|
+
// { value, unit }. Parse it here; if it is not valid JSON, return the raw string
|
|
733
|
+
// so validateNumberRangeDefaultValue can report a precise error.
|
|
734
|
+
try {
|
|
735
|
+
return JSON.parse(value);
|
|
736
|
+
}
|
|
737
|
+
catch {
|
|
738
|
+
return value;
|
|
739
|
+
}
|
|
740
|
+
case "TYPE":
|
|
741
|
+
// A TYPE (structured/style) default is a typed object — e.g. { value, unit } for a size
|
|
742
|
+
// style type — or an array of them for an _array typeId. Parse it here; if it is not valid
|
|
743
|
+
// JSON, return the raw string so validateTypeDefaultValue can report a precise error.
|
|
744
|
+
// (Without this the --defaultValue flag would store the raw string, a wrong-shaped default.)
|
|
745
|
+
try {
|
|
746
|
+
return JSON.parse(value);
|
|
747
|
+
}
|
|
748
|
+
catch {
|
|
749
|
+
return value;
|
|
750
|
+
}
|
|
645
751
|
default:
|
|
646
752
|
return value;
|
|
647
753
|
}
|
|
648
754
|
}
|
|
755
|
+
// Prop types whose value is a dynamic reference to merchant storefront data (products, media,
|
|
756
|
+
// categories, brands, blogs, raffles). They resolve at storefront render time, so a static config
|
|
757
|
+
// default is invalid and is rejected on add/update-prop. Keep in sync with @ikas/editor-models
|
|
758
|
+
// DYNAMIC_PROP_TYPES (the CLI must not depend on that private package).
|
|
759
|
+
const DYNAMIC_PROP_TYPES = [
|
|
760
|
+
"IMAGE",
|
|
761
|
+
"IMAGE_LIST",
|
|
762
|
+
"VIDEO",
|
|
763
|
+
"PRODUCT",
|
|
764
|
+
"PRODUCT_LIST",
|
|
765
|
+
"PRODUCT_ATTRIBUTE",
|
|
766
|
+
"PRODUCT_ATTRIBUTE_LIST",
|
|
767
|
+
"BRAND",
|
|
768
|
+
"BRAND_LIST",
|
|
769
|
+
"CATEGORY",
|
|
770
|
+
"CATEGORY_LIST",
|
|
771
|
+
"BLOG",
|
|
772
|
+
"BLOG_LIST",
|
|
773
|
+
"BLOG_CATEGORY",
|
|
774
|
+
"BLOG_CATEGORY_LIST",
|
|
775
|
+
"RAFFLE",
|
|
776
|
+
"RAFFLE_LIST",
|
|
777
|
+
];
|
|
778
|
+
const dynamicPropDefaultError = (propName, propType) => `defaultValue is not allowed for prop "${propName}" of type ${propType}. ${propType} resolves to merchant storefront data at render time, so it can't carry a static default — omit defaultValue.`;
|
|
779
|
+
// Reject a static default on a dynamic (merchant-data reference) prop type: print the standard
|
|
780
|
+
// error and exit. No-op when the type isn't dynamic or no default was supplied.
|
|
781
|
+
const rejectDynamicDefault = (propName, propType, defaultValue) => {
|
|
782
|
+
if (DYNAMIC_PROP_TYPES.includes(propType) && defaultValue !== undefined) {
|
|
783
|
+
console.log(JSON.stringify({
|
|
784
|
+
success: false,
|
|
785
|
+
error: dynamicPropDefaultError(propName, propType),
|
|
786
|
+
}));
|
|
787
|
+
process.exit(1);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
649
790
|
const VALID_LINK_TYPES = ["PAGE", "EXTERNAL", "FILE"];
|
|
650
791
|
const LINK_SHAPE_HELP = 'A link must be an object: { "linkType": "EXTERNAL", "label": "Text", "externalLink": "https://...", "subLinks": [] } ' +
|
|
651
792
|
'for external links, or { "linkType": "PAGE", "label": "Text", "pageType": "INDEX", "subLinks": [] } for store pages. ' +
|
|
@@ -762,6 +903,141 @@ function validateSvgDefaultValue(propType, value, propName) {
|
|
|
762
903
|
: null;
|
|
763
904
|
});
|
|
764
905
|
}
|
|
906
|
+
const NUMBER_RANGE_DEFAULT_HELP = 'A NUMBER_RANGE default must be an object { "value": <number>, "unit": "px" | null }. ' +
|
|
907
|
+
"When the prop defines numberRangeData, value must be within [min, max] and on the interval grid (min + k·interval).";
|
|
908
|
+
// Validates a NUMBER_RANGE defaultValue. Returns an error message, or null if valid.
|
|
909
|
+
// Checks the { value, unit } shape and — when the prop carries numberRangeData — that the
|
|
910
|
+
// value is within [min, max] and lands on the interval grid, mirroring the editor's slider
|
|
911
|
+
// so an agent can't author an out-of-range or off-step default.
|
|
912
|
+
function validateNumberRangeDefaultValue(value, numberRangeData, propName) {
|
|
913
|
+
if (value === undefined || value === null)
|
|
914
|
+
return null;
|
|
915
|
+
const where = `defaultValue for prop "${propName}"`;
|
|
916
|
+
if (typeof value === "string") {
|
|
917
|
+
return `${where} is a JSON string but must be an object. ${NUMBER_RANGE_DEFAULT_HELP}`;
|
|
918
|
+
}
|
|
919
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
920
|
+
return `${where} must be an object. ${NUMBER_RANGE_DEFAULT_HELP}`;
|
|
921
|
+
}
|
|
922
|
+
const v = value;
|
|
923
|
+
if (typeof v.value !== "number" || !Number.isFinite(v.value)) {
|
|
924
|
+
return `${where}: "value" must be a finite number. ${NUMBER_RANGE_DEFAULT_HELP}`;
|
|
925
|
+
}
|
|
926
|
+
if (v.unit !== undefined && v.unit !== null && typeof v.unit !== "string") {
|
|
927
|
+
return `${where}: "unit" must be a string or null. ${NUMBER_RANGE_DEFAULT_HELP}`;
|
|
928
|
+
}
|
|
929
|
+
if (numberRangeData) {
|
|
930
|
+
const { min, max, interval } = numberRangeData;
|
|
931
|
+
if (min !== undefined && v.value < min) {
|
|
932
|
+
return `${where}: value ${v.value} is below the configured min (${min}).`;
|
|
933
|
+
}
|
|
934
|
+
if (max !== undefined && v.value > max) {
|
|
935
|
+
return `${where}: value ${v.value} is above the configured max (${max}).`;
|
|
936
|
+
}
|
|
937
|
+
if (interval !== undefined &&
|
|
938
|
+
interval > 0 &&
|
|
939
|
+
min !== undefined &&
|
|
940
|
+
(v.value - min) % interval !== 0) {
|
|
941
|
+
return `${where}: value ${v.value} is not on the interval grid (min ${min} + k·${interval}).`;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
const STYLE_TYPE_DEFAULT_HELP = "A size/style TYPE default must be an object matching the type's shape: " +
|
|
947
|
+
'{ "value": <number>, "unit": "px" | "rem" | "%" | "vh" | "vw" } (or { "css": "<raw css>" }). ' +
|
|
948
|
+
"Author it via add-component --props '[…]' or --defaultValue '<json>'.";
|
|
949
|
+
const BP_STOREFRONT_PREFIX = "@ikas/bp-storefront-models-";
|
|
950
|
+
// The size/style types that share the { css?, value?, unit? } shape. This is EXACTLY the set of
|
|
951
|
+
// TYPE typeIds whose default the generator emits (mirror of DYNAMIC_STYLE_TYPE_IDS in
|
|
952
|
+
// @ikas/blueprint-modules design-generator/generate-helpers/styles.ts — the standalone CLI must not
|
|
953
|
+
// depend on that package, so it is hand-maintained here and kept in sync by a parity test). Every
|
|
954
|
+
// OTHER TYPE typeId (BorderStyleType, BoxShadowStyleType, GridTemplateColumnsStyleType, string-union
|
|
955
|
+
// styles like TextAlignStyleType, IkasProduct, custom types) has a DIFFERENT value shape, so their
|
|
956
|
+
// defaults are not shape-checked (and are dead code in the generator anyway).
|
|
957
|
+
const SIZE_STYLE_TYPE_NAMES = [
|
|
958
|
+
"SizeStyleType",
|
|
959
|
+
"PaddingStyleType",
|
|
960
|
+
"PaddingTopStyleType",
|
|
961
|
+
"PaddingRightStyleType",
|
|
962
|
+
"PaddingBottomStyleType",
|
|
963
|
+
"PaddingLeftStyleType",
|
|
964
|
+
"MarginStyleType",
|
|
965
|
+
"MarginTopStyleType",
|
|
966
|
+
"MarginRightStyleType",
|
|
967
|
+
"MarginBottomStyleType",
|
|
968
|
+
"MarginLeftStyleType",
|
|
969
|
+
"BorderRadiusStyleType",
|
|
970
|
+
"BorderRadiusTopLeftStyleType",
|
|
971
|
+
"BorderRadiusTopRightStyleType",
|
|
972
|
+
"BorderRadiusBottomRightStyleType",
|
|
973
|
+
"BorderRadiusBottomLeftStyleType",
|
|
974
|
+
"FontSizeStyleType",
|
|
975
|
+
"LineHeightStyleType",
|
|
976
|
+
"LetterSpacingStyleType",
|
|
977
|
+
"HeightStyleType",
|
|
978
|
+
"MinHeightStyleType",
|
|
979
|
+
"MaxHeightStyleType",
|
|
980
|
+
"WidthStyleType",
|
|
981
|
+
"MinWidthStyleType",
|
|
982
|
+
"MaxWidthStyleType",
|
|
983
|
+
"GapStyleType",
|
|
984
|
+
"BorderWidthStyleType",
|
|
985
|
+
"TopStyleType",
|
|
986
|
+
"RightStyleType",
|
|
987
|
+
"BottomStyleType",
|
|
988
|
+
"LeftStyleType",
|
|
989
|
+
];
|
|
990
|
+
// Validates a single style-type default object. Every size style type shares the optional
|
|
991
|
+
// { css?, value?, unit? } shape, so inner fields are checked loosely — the key rejection is a
|
|
992
|
+
// non-object (e.g. a bare JSON string, the common failure when a --defaultValue flag is not parsed).
|
|
993
|
+
function styleDefaultObjectError(value, where) {
|
|
994
|
+
if (typeof value === "string") {
|
|
995
|
+
return `${where} is a JSON string but must be an object. ${STYLE_TYPE_DEFAULT_HELP}`;
|
|
996
|
+
}
|
|
997
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
998
|
+
return `${where} must be an object. ${STYLE_TYPE_DEFAULT_HELP}`;
|
|
999
|
+
}
|
|
1000
|
+
const v = value;
|
|
1001
|
+
if (v.value !== undefined &&
|
|
1002
|
+
(typeof v.value !== "number" || !Number.isFinite(v.value))) {
|
|
1003
|
+
return `${where}: "value" must be a finite number. ${STYLE_TYPE_DEFAULT_HELP}`;
|
|
1004
|
+
}
|
|
1005
|
+
if (v.unit !== undefined && v.unit !== null && typeof v.unit !== "string") {
|
|
1006
|
+
return `${where}: "unit" must be a string. ${STYLE_TYPE_DEFAULT_HELP}`;
|
|
1007
|
+
}
|
|
1008
|
+
if (v.css !== undefined && typeof v.css !== "string") {
|
|
1009
|
+
return `${where}: "css" must be a string. ${STYLE_TYPE_DEFAULT_HELP}`;
|
|
1010
|
+
}
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
// Validates a TYPE prop defaultValue — but ONLY for the size/style types whose shape we know
|
|
1014
|
+
// ({ css?, value?, unit? }). Any other TYPE typeId (color/border/box-shadow/grid/string-union
|
|
1015
|
+
// styles, IkasProduct, custom types) has a different value shape we can't verify offline, so its
|
|
1016
|
+
// default is passed through unchecked. The generator only emits a default for these size/style
|
|
1017
|
+
// types anyway. Returns an error message, or null if valid / not a size-style type.
|
|
1018
|
+
function validateTypeDefaultValue(value, propName, typeId) {
|
|
1019
|
+
if (value === undefined || value === null)
|
|
1020
|
+
return null;
|
|
1021
|
+
if (typeof typeId !== "string" || !typeId.startsWith(BP_STOREFRONT_PREFIX)) {
|
|
1022
|
+
return null;
|
|
1023
|
+
}
|
|
1024
|
+
// Strip the prefix and an optional _array suffix to get the base type name.
|
|
1025
|
+
const withoutPrefix = typeId.slice(BP_STOREFRONT_PREFIX.length);
|
|
1026
|
+
const isArray = withoutPrefix.endsWith("_array");
|
|
1027
|
+
const baseName = isArray
|
|
1028
|
+
? withoutPrefix.slice(0, -"_array".length)
|
|
1029
|
+
: withoutPrefix;
|
|
1030
|
+
if (!SIZE_STYLE_TYPE_NAMES.includes(baseName))
|
|
1031
|
+
return null;
|
|
1032
|
+
const where = `defaultValue for prop "${propName}"`;
|
|
1033
|
+
if (isArray) {
|
|
1034
|
+
if (!Array.isArray(value)) {
|
|
1035
|
+
return `${where} must be an array for an _array TYPE prop: [ { "value": …, "unit": … }, … ]. ${STYLE_TYPE_DEFAULT_HELP}`;
|
|
1036
|
+
}
|
|
1037
|
+
return firstError(value, (el, i) => styleDefaultObjectError(el, `${where}[${i}]`));
|
|
1038
|
+
}
|
|
1039
|
+
return styleDefaultObjectError(value, where);
|
|
1040
|
+
}
|
|
765
1041
|
async function updateProp(ref, options) {
|
|
766
1042
|
const { config, configPath } = loadConfig();
|
|
767
1043
|
const component = resolveComponent(config, ref);
|
|
@@ -794,7 +1070,18 @@ async function updateProp(ref, options) {
|
|
|
794
1070
|
if (options.description !== undefined) {
|
|
795
1071
|
prop.description = options.description || undefined;
|
|
796
1072
|
}
|
|
1073
|
+
// Resolve numberRangeData before defaultValue so a NUMBER_RANGE default can be validated
|
|
1074
|
+
// against the (possibly just-updated) slider config in the same call.
|
|
1075
|
+
if (options.numberRangeData !== undefined) {
|
|
1076
|
+
if (options.numberRangeData === "" || options.numberRangeData === "none") {
|
|
1077
|
+
delete prop.numberRangeData;
|
|
1078
|
+
}
|
|
1079
|
+
else {
|
|
1080
|
+
prop.numberRangeData = parseNumberRangeData(options.numberRangeData, prop.name);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
797
1083
|
if (options.defaultValue !== undefined) {
|
|
1084
|
+
rejectDynamicDefault(prop.name, prop.type, options.defaultValue);
|
|
798
1085
|
const parsed = parseDefaultValue(options.defaultValue, prop.type);
|
|
799
1086
|
if (prop.type === "LINK" || prop.type === "LIST_OF_LINK") {
|
|
800
1087
|
const linkError = validateLinkDefaultValue(prop.type, parsed, prop.name);
|
|
@@ -803,6 +1090,21 @@ async function updateProp(ref, options) {
|
|
|
803
1090
|
process.exit(1);
|
|
804
1091
|
}
|
|
805
1092
|
}
|
|
1093
|
+
if (prop.type === "NUMBER_RANGE") {
|
|
1094
|
+
const nrError = validateNumberRangeDefaultValue(parsed, prop.numberRangeData, prop.name);
|
|
1095
|
+
if (nrError) {
|
|
1096
|
+
console.log(JSON.stringify({ success: false, error: nrError }));
|
|
1097
|
+
process.exit(1);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
if (prop.type === "TYPE") {
|
|
1101
|
+
// Prefer a typeId supplied in this same update over the stored one.
|
|
1102
|
+
const typeError = validateTypeDefaultValue(parsed, prop.name, options.typeId ?? prop.typeId);
|
|
1103
|
+
if (typeError) {
|
|
1104
|
+
console.log(JSON.stringify({ success: false, error: typeError }));
|
|
1105
|
+
process.exit(1);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
806
1108
|
prop.defaultValue = parsed;
|
|
807
1109
|
}
|
|
808
1110
|
if (options.group !== undefined) {
|
|
@@ -925,6 +1227,9 @@ async function updateProp(ref, options) {
|
|
|
925
1227
|
? { filteredComponentIds: prop.filteredComponentIds }
|
|
926
1228
|
: {}),
|
|
927
1229
|
...(prop.privateVarMap ? { privateVarMap: prop.privateVarMap } : {}),
|
|
1230
|
+
...(prop.numberRangeData
|
|
1231
|
+
? { numberRangeData: prop.numberRangeData }
|
|
1232
|
+
: {}),
|
|
928
1233
|
},
|
|
929
1234
|
}));
|
|
930
1235
|
}
|
|
@@ -1423,6 +1728,7 @@ export function createConfigCommand() {
|
|
|
1423
1728
|
.option("--enumTypeId <enumTypeId>", "Enum type ID for ENUM props (required when type is ENUM)")
|
|
1424
1729
|
.option("--filteredComponentIds <json>", "JSON array of component IDs to restrict selection (for COMPONENT/COMPONENT_LIST)")
|
|
1425
1730
|
.option("--privateVarMap <json>", "JSON object mapping variable keys to {id, typeId} (for COMPONENT/COMPONENT_LIST)")
|
|
1731
|
+
.option("--numberRangeData <json>", 'JSON slider config for NUMBER_RANGE props, e.g. \'{"min":0,"max":100,"interval":5,"unit":"px"}\'')
|
|
1426
1732
|
.action((options) => {
|
|
1427
1733
|
addProp({ id: options.componentId, name: options.component }, options);
|
|
1428
1734
|
});
|
|
@@ -1442,6 +1748,7 @@ export function createConfigCommand() {
|
|
|
1442
1748
|
.option("--enumTypeId <enumTypeId>", "Enum type ID for ENUM props (use 'none' to clear)")
|
|
1443
1749
|
.option("--filteredComponentIds <json>", "JSON array of component IDs (use 'none' to clear)")
|
|
1444
1750
|
.option("--privateVarMap <json>", "JSON object mapping variable keys to {id, typeId} (use 'none' to clear)")
|
|
1751
|
+
.option("--numberRangeData <json>", "JSON slider config for NUMBER_RANGE props (use 'none' to clear)")
|
|
1445
1752
|
.action((options) => {
|
|
1446
1753
|
updateProp({ id: options.componentId, name: options.component }, options);
|
|
1447
1754
|
});
|