@wcstack/state 1.14.0 → 1.16.0
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/index.d.ts +79 -2
- package/dist/index.esm.js +165 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/manifest.d.ts +74 -0
- package/dist/manifest.esm.js +925 -0
- package/dist/wcs-manifest.json +533 -0
- package/package.json +8 -3
|
@@ -0,0 +1,925 @@
|
|
|
1
|
+
const _config = {
|
|
2
|
+
bindAttributeName: 'data-wcs',
|
|
3
|
+
tagNames: {
|
|
4
|
+
state: 'wcs-state'},
|
|
5
|
+
locale: 'en'};
|
|
6
|
+
// backward compatible export (read-only usage)
|
|
7
|
+
const config = _config;
|
|
8
|
+
|
|
9
|
+
function raiseError(message) {
|
|
10
|
+
throw new Error(`[@wcstack/state] ${message}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* errorMessages.ts
|
|
15
|
+
*
|
|
16
|
+
* Error message generation utilities used by filter functions.
|
|
17
|
+
*
|
|
18
|
+
* Main responsibilities:
|
|
19
|
+
* - Throws clear error messages when filter options or value type checks fail
|
|
20
|
+
* - Takes function name as argument to specify which filter caused the error
|
|
21
|
+
*
|
|
22
|
+
* Design points:
|
|
23
|
+
* - optionsRequired: Error when required option is not specified
|
|
24
|
+
* - optionMustBeNumber: Error when option value is not a number
|
|
25
|
+
* - valueMustBeNumber: Error when value is not a number
|
|
26
|
+
* - valueMustBeBoolean: Error when value is not boolean
|
|
27
|
+
* - valueMustBeDate: Error when value is not a Date
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Throws error when filter requires at least one option but none provided.
|
|
31
|
+
*
|
|
32
|
+
* @param fnName - Name of the filter function
|
|
33
|
+
* @returns Never returns (always throws)
|
|
34
|
+
*/
|
|
35
|
+
function optionsRequired(fnName) {
|
|
36
|
+
raiseError(`filter ${fnName} requires at least one option`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Throws error when filter option must be a number but invalid value provided.
|
|
40
|
+
*
|
|
41
|
+
* @param fnName - Name of the filter function
|
|
42
|
+
* @returns Never returns (always throws)
|
|
43
|
+
*/
|
|
44
|
+
function optionMustBeNumber(fnName) {
|
|
45
|
+
raiseError(`filter ${fnName} requires a number as option`);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Throws error when filter requires numeric value but non-number provided.
|
|
49
|
+
*
|
|
50
|
+
* @param fnName - Name of the filter function
|
|
51
|
+
* @returns Never returns (always throws)
|
|
52
|
+
*/
|
|
53
|
+
function valueMustBeNumber(fnName) {
|
|
54
|
+
raiseError(`filter ${fnName} requires a number value`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Throws error when filter requires boolean value but non-boolean provided.
|
|
58
|
+
*
|
|
59
|
+
* @param fnName - Name of the filter function
|
|
60
|
+
* @returns Never returns (always throws)
|
|
61
|
+
*/
|
|
62
|
+
function valueMustBeBoolean(fnName) {
|
|
63
|
+
raiseError(`filter ${fnName} requires a boolean value`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Throws error when filter requires Date value but non-Date provided.
|
|
67
|
+
*
|
|
68
|
+
* @param fnName - Name of the filter function
|
|
69
|
+
* @returns Never returns (always throws)
|
|
70
|
+
*/
|
|
71
|
+
function valueMustBeDate(fnName) {
|
|
72
|
+
raiseError(`filter ${fnName} requires a date value`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* builtinFilters.ts
|
|
77
|
+
*
|
|
78
|
+
* Implementation file for built-in filter functions available in Structive.
|
|
79
|
+
*
|
|
80
|
+
* Main responsibilities:
|
|
81
|
+
* - Provides filters for conversion, comparison, formatting, and validation of numbers, strings, dates, booleans, etc.
|
|
82
|
+
* - Defines functions with options for each filter name, enabling flexible use during binding
|
|
83
|
+
* - Designed for common use as both input and output filters
|
|
84
|
+
*
|
|
85
|
+
* Design points:
|
|
86
|
+
* - Comprehensive coverage of diverse filters: eq, ne, lt, gt, inc, fix, locale, uc, lc, cap, trim, slice, pad, int, float, round, date, time, ymd, falsy, truthy, defaults, boolean, number, string, null, etc.
|
|
87
|
+
* - Rich type checking and error handling for option values
|
|
88
|
+
* - Centralized management of filter functions with FilterWithOptions type, easy to extend
|
|
89
|
+
* - Dynamic retrieval of filter functions from filter names and options via builtinFilterFn
|
|
90
|
+
*/
|
|
91
|
+
function validateNumberString(value) {
|
|
92
|
+
if (!value || isNaN(Number(value))) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Equality filter - compares value with option.
|
|
99
|
+
*
|
|
100
|
+
* @param options - Array with comparison value as first element
|
|
101
|
+
* @returns Filter function that returns boolean
|
|
102
|
+
*/
|
|
103
|
+
const eq = (options) => {
|
|
104
|
+
const opt = options?.[0] ?? optionsRequired('eq');
|
|
105
|
+
return (value) => {
|
|
106
|
+
// Align types for comparison
|
|
107
|
+
if (typeof value === 'number') {
|
|
108
|
+
if (!validateNumberString(opt)) {
|
|
109
|
+
optionMustBeNumber('eq');
|
|
110
|
+
}
|
|
111
|
+
return value === Number(opt);
|
|
112
|
+
}
|
|
113
|
+
if (typeof value === 'string') {
|
|
114
|
+
return value === opt;
|
|
115
|
+
}
|
|
116
|
+
// Strict equality for others
|
|
117
|
+
return value === opt;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Inequality filter - compares value with option.
|
|
122
|
+
*
|
|
123
|
+
* @param options - Array with comparison value as first element
|
|
124
|
+
* @returns Filter function that returns boolean
|
|
125
|
+
*/
|
|
126
|
+
const ne = (options) => {
|
|
127
|
+
const opt = options?.[0] ?? optionsRequired('ne');
|
|
128
|
+
return (value) => {
|
|
129
|
+
// Align types for comparison
|
|
130
|
+
if (typeof value === 'number') {
|
|
131
|
+
if (!validateNumberString(opt)) {
|
|
132
|
+
optionMustBeNumber('ne');
|
|
133
|
+
}
|
|
134
|
+
return value !== Number(opt);
|
|
135
|
+
}
|
|
136
|
+
if (typeof value === 'string') {
|
|
137
|
+
return value !== opt;
|
|
138
|
+
}
|
|
139
|
+
// Strict equality for others
|
|
140
|
+
return value !== opt;
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Boolean NOT filter - inverts boolean value.
|
|
145
|
+
*
|
|
146
|
+
* @param options - Unused
|
|
147
|
+
* @returns Filter function that returns inverted boolean
|
|
148
|
+
*/
|
|
149
|
+
const not = (_options) => {
|
|
150
|
+
return (value) => {
|
|
151
|
+
if (typeof value !== 'boolean') {
|
|
152
|
+
valueMustBeBoolean('not');
|
|
153
|
+
}
|
|
154
|
+
return !value;
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Less than filter - checks if value is less than option.
|
|
159
|
+
*
|
|
160
|
+
* @param options - Array with comparison number as first element
|
|
161
|
+
* @returns Filter function that returns boolean
|
|
162
|
+
*/
|
|
163
|
+
const lt = (options) => {
|
|
164
|
+
const opt = options?.[0] ?? optionsRequired('lt');
|
|
165
|
+
if (!validateNumberString(opt)) {
|
|
166
|
+
optionMustBeNumber('lt');
|
|
167
|
+
}
|
|
168
|
+
return (value) => {
|
|
169
|
+
if (typeof value !== 'number') {
|
|
170
|
+
valueMustBeNumber('lt');
|
|
171
|
+
}
|
|
172
|
+
return value < Number(opt);
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Less than or equal filter - checks if value is less than or equal to option.
|
|
177
|
+
*
|
|
178
|
+
* @param options - Array with comparison number as first element
|
|
179
|
+
* @returns Filter function that returns boolean
|
|
180
|
+
*/
|
|
181
|
+
const le = (options) => {
|
|
182
|
+
const opt = options?.[0] ?? optionsRequired('le');
|
|
183
|
+
if (!validateNumberString(opt)) {
|
|
184
|
+
optionMustBeNumber('le');
|
|
185
|
+
}
|
|
186
|
+
return (value) => {
|
|
187
|
+
if (typeof value !== 'number') {
|
|
188
|
+
valueMustBeNumber('le');
|
|
189
|
+
}
|
|
190
|
+
return value <= Number(opt);
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Greater than filter - checks if value is greater than option.
|
|
195
|
+
*
|
|
196
|
+
* @param options - Array with comparison number as first element
|
|
197
|
+
* @returns Filter function that returns boolean
|
|
198
|
+
*/
|
|
199
|
+
const gt = (options) => {
|
|
200
|
+
const opt = options?.[0] ?? optionsRequired('gt');
|
|
201
|
+
if (!validateNumberString(opt)) {
|
|
202
|
+
optionMustBeNumber('gt');
|
|
203
|
+
}
|
|
204
|
+
return (value) => {
|
|
205
|
+
if (typeof value !== 'number') {
|
|
206
|
+
valueMustBeNumber('gt');
|
|
207
|
+
}
|
|
208
|
+
return value > Number(opt);
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Greater than or equal filter - checks if value is greater than or equal to option.
|
|
213
|
+
*
|
|
214
|
+
* @param options - Array with comparison number as first element
|
|
215
|
+
* @returns Filter function that returns boolean
|
|
216
|
+
*/
|
|
217
|
+
const ge = (options) => {
|
|
218
|
+
const opt = options?.[0] ?? optionsRequired('ge');
|
|
219
|
+
if (!validateNumberString(opt)) {
|
|
220
|
+
optionMustBeNumber('ge');
|
|
221
|
+
}
|
|
222
|
+
return (value) => {
|
|
223
|
+
if (typeof value !== 'number') {
|
|
224
|
+
valueMustBeNumber('ge');
|
|
225
|
+
}
|
|
226
|
+
return value >= Number(opt);
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Increment filter - adds option value to input value.
|
|
231
|
+
*
|
|
232
|
+
* @param options - Array with increment number as first element
|
|
233
|
+
* @returns Filter function that returns incremented number
|
|
234
|
+
*/
|
|
235
|
+
const inc = (options) => {
|
|
236
|
+
const opt = options?.[0] ?? optionsRequired('inc');
|
|
237
|
+
if (!validateNumberString(opt)) {
|
|
238
|
+
optionMustBeNumber('inc');
|
|
239
|
+
}
|
|
240
|
+
return (value) => {
|
|
241
|
+
if (typeof value !== 'number') {
|
|
242
|
+
valueMustBeNumber('inc');
|
|
243
|
+
}
|
|
244
|
+
return value + Number(opt);
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Decrement filter - subtracts option value from input value.
|
|
249
|
+
*
|
|
250
|
+
* @param options - Array with decrement number as first element
|
|
251
|
+
* @returns Filter function that returns decremented number
|
|
252
|
+
*/
|
|
253
|
+
const dec = (options) => {
|
|
254
|
+
const opt = options?.[0] ?? optionsRequired('dec');
|
|
255
|
+
if (!validateNumberString(opt)) {
|
|
256
|
+
optionMustBeNumber('dec');
|
|
257
|
+
}
|
|
258
|
+
return (value) => {
|
|
259
|
+
if (typeof value !== 'number') {
|
|
260
|
+
valueMustBeNumber('dec');
|
|
261
|
+
}
|
|
262
|
+
return value - Number(opt);
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
/**
|
|
266
|
+
* Multiply filter - multiplies value by option.
|
|
267
|
+
*
|
|
268
|
+
* @param options - Array with multiplier number as first element
|
|
269
|
+
* @returns Filter function that returns multiplied number
|
|
270
|
+
*/
|
|
271
|
+
const mul = (options) => {
|
|
272
|
+
const opt = options?.[0] ?? optionsRequired('mul');
|
|
273
|
+
if (!validateNumberString(opt)) {
|
|
274
|
+
optionMustBeNumber('mul');
|
|
275
|
+
}
|
|
276
|
+
return (value) => {
|
|
277
|
+
if (typeof value !== 'number') {
|
|
278
|
+
valueMustBeNumber('mul');
|
|
279
|
+
}
|
|
280
|
+
return value * Number(opt);
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Divide filter - divides value by option.
|
|
285
|
+
*
|
|
286
|
+
* @param options - Array with divisor number as first element
|
|
287
|
+
* @returns Filter function that returns divided number
|
|
288
|
+
*/
|
|
289
|
+
const div = (options) => {
|
|
290
|
+
const opt = options?.[0] ?? optionsRequired('div');
|
|
291
|
+
if (!validateNumberString(opt)) {
|
|
292
|
+
optionMustBeNumber('div');
|
|
293
|
+
}
|
|
294
|
+
return (value) => {
|
|
295
|
+
if (typeof value !== 'number') {
|
|
296
|
+
valueMustBeNumber('div');
|
|
297
|
+
}
|
|
298
|
+
return value / Number(opt);
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
/**
|
|
302
|
+
* Modulo filter - returns remainder of division.
|
|
303
|
+
*
|
|
304
|
+
* @param options - Array with divisor number as first element
|
|
305
|
+
* @returns Filter function that returns remainder
|
|
306
|
+
*/
|
|
307
|
+
const mod = (options) => {
|
|
308
|
+
const opt = options?.[0] ?? optionsRequired('mod');
|
|
309
|
+
if (!validateNumberString(opt)) {
|
|
310
|
+
optionMustBeNumber('mod');
|
|
311
|
+
}
|
|
312
|
+
return (value) => {
|
|
313
|
+
if (typeof value !== 'number') {
|
|
314
|
+
valueMustBeNumber('mod');
|
|
315
|
+
}
|
|
316
|
+
return value % Number(opt);
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Fixed decimal filter - formats number to fixed decimal places.
|
|
321
|
+
*
|
|
322
|
+
* @param options - Array with decimal places as first element (default: 0)
|
|
323
|
+
* @returns Filter function that returns formatted string
|
|
324
|
+
*/
|
|
325
|
+
const fix = (options) => {
|
|
326
|
+
const opt = options?.[0] ?? "0";
|
|
327
|
+
if (!validateNumberString(opt)) {
|
|
328
|
+
optionMustBeNumber('fix');
|
|
329
|
+
}
|
|
330
|
+
return (value) => {
|
|
331
|
+
if (typeof value !== 'number') {
|
|
332
|
+
valueMustBeNumber('fix');
|
|
333
|
+
}
|
|
334
|
+
return value.toFixed(Number(opt));
|
|
335
|
+
};
|
|
336
|
+
};
|
|
337
|
+
/**
|
|
338
|
+
* Locale number filter - formats number according to locale.
|
|
339
|
+
*
|
|
340
|
+
* @param options - Array with locale string as first element (default: config.locale)
|
|
341
|
+
* @returns Filter function that returns localized number string
|
|
342
|
+
*/
|
|
343
|
+
const locale = (options) => {
|
|
344
|
+
const opt = options?.[0] ?? config.locale;
|
|
345
|
+
return (value) => {
|
|
346
|
+
if (typeof value !== 'number') {
|
|
347
|
+
valueMustBeNumber('locale');
|
|
348
|
+
}
|
|
349
|
+
return value.toLocaleString(opt);
|
|
350
|
+
};
|
|
351
|
+
};
|
|
352
|
+
/**
|
|
353
|
+
* Uppercase filter - converts string to uppercase.
|
|
354
|
+
*
|
|
355
|
+
* @param options - Unused
|
|
356
|
+
* @returns Filter function that returns uppercase string
|
|
357
|
+
*/
|
|
358
|
+
const uc = (_options) => {
|
|
359
|
+
return (value) => {
|
|
360
|
+
return String(value).toUpperCase();
|
|
361
|
+
};
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* Lowercase filter - converts string to lowercase.
|
|
365
|
+
*
|
|
366
|
+
* @param options - Unused
|
|
367
|
+
* @returns Filter function that returns lowercase string
|
|
368
|
+
*/
|
|
369
|
+
const lc = (_options) => {
|
|
370
|
+
return (value) => {
|
|
371
|
+
return String(value).toLowerCase();
|
|
372
|
+
};
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* Capitalize filter - capitalizes first character of string.
|
|
376
|
+
*
|
|
377
|
+
* @param options - Unused
|
|
378
|
+
* @returns Filter function that returns capitalized string
|
|
379
|
+
*/
|
|
380
|
+
const cap = (_options) => {
|
|
381
|
+
return (value) => {
|
|
382
|
+
const v = String(value);
|
|
383
|
+
if (v.length === 0) {
|
|
384
|
+
return v;
|
|
385
|
+
}
|
|
386
|
+
if (v.length === 1) {
|
|
387
|
+
return v.toUpperCase();
|
|
388
|
+
}
|
|
389
|
+
return v.charAt(0).toUpperCase() + v.slice(1);
|
|
390
|
+
};
|
|
391
|
+
};
|
|
392
|
+
/**
|
|
393
|
+
* Trim filter - removes whitespace from both ends of string.
|
|
394
|
+
*
|
|
395
|
+
* @param options - Unused
|
|
396
|
+
* @returns Filter function that returns trimmed string
|
|
397
|
+
*/
|
|
398
|
+
const trim = (_options) => {
|
|
399
|
+
return (value) => {
|
|
400
|
+
return String(value).trim();
|
|
401
|
+
};
|
|
402
|
+
};
|
|
403
|
+
/**
|
|
404
|
+
* Slice filter - extracts portion of string from specified index.
|
|
405
|
+
*
|
|
406
|
+
* @param options - Array with start index and optional end index
|
|
407
|
+
* @returns Filter function that returns sliced string
|
|
408
|
+
*/
|
|
409
|
+
const slice = (options) => {
|
|
410
|
+
const numberedOpts = [];
|
|
411
|
+
const opt1 = options?.[0] ?? optionsRequired('slice');
|
|
412
|
+
if (!validateNumberString(opt1)) {
|
|
413
|
+
optionMustBeNumber('slice');
|
|
414
|
+
}
|
|
415
|
+
numberedOpts.push(Number(opt1));
|
|
416
|
+
const opt2 = options?.[1];
|
|
417
|
+
if (typeof opt2 !== 'undefined') {
|
|
418
|
+
if (!validateNumberString(opt2)) {
|
|
419
|
+
optionMustBeNumber('slice');
|
|
420
|
+
}
|
|
421
|
+
numberedOpts.push(Number(opt2));
|
|
422
|
+
}
|
|
423
|
+
return (value) => {
|
|
424
|
+
return String(value).slice(...numberedOpts);
|
|
425
|
+
};
|
|
426
|
+
};
|
|
427
|
+
/**
|
|
428
|
+
* Substring filter - extracts substring from specified position and length.
|
|
429
|
+
*
|
|
430
|
+
* @param options - Array with start index and length
|
|
431
|
+
* @returns Filter function that returns substring
|
|
432
|
+
*/
|
|
433
|
+
const substr = (options) => {
|
|
434
|
+
const opt1 = options?.[0] ?? optionsRequired('substr');
|
|
435
|
+
if (!validateNumberString(opt1)) {
|
|
436
|
+
optionMustBeNumber('substr');
|
|
437
|
+
}
|
|
438
|
+
const opt2 = options?.[1] ?? optionsRequired('substr');
|
|
439
|
+
if (!validateNumberString(opt2)) {
|
|
440
|
+
optionMustBeNumber('substr');
|
|
441
|
+
}
|
|
442
|
+
return (value) => {
|
|
443
|
+
return String(value).substr(Number(opt1), Number(opt2));
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* Pad filter - pads string to specified length from start.
|
|
448
|
+
*
|
|
449
|
+
* @param options - Array with target length and pad string (default: '0')
|
|
450
|
+
* @returns Filter function that returns padded string
|
|
451
|
+
*/
|
|
452
|
+
const pad = (options) => {
|
|
453
|
+
const opt1 = options?.[0] ?? optionsRequired('pad');
|
|
454
|
+
if (!validateNumberString(opt1)) {
|
|
455
|
+
optionMustBeNumber('pad');
|
|
456
|
+
}
|
|
457
|
+
const opt2 = options?.[1] ?? '0';
|
|
458
|
+
return (value) => {
|
|
459
|
+
return String(value).padStart(Number(opt1), opt2);
|
|
460
|
+
};
|
|
461
|
+
};
|
|
462
|
+
/**
|
|
463
|
+
* Repeat filter - repeats string specified number of times.
|
|
464
|
+
*
|
|
465
|
+
* @param options - Array with repeat count as first element
|
|
466
|
+
* @returns Filter function that returns repeated string
|
|
467
|
+
*/
|
|
468
|
+
const rep = (options) => {
|
|
469
|
+
const opt = options?.[0] ?? optionsRequired('rep');
|
|
470
|
+
if (!validateNumberString(opt)) {
|
|
471
|
+
optionMustBeNumber('rep');
|
|
472
|
+
}
|
|
473
|
+
return (value) => {
|
|
474
|
+
return String(value).repeat(Number(opt));
|
|
475
|
+
};
|
|
476
|
+
};
|
|
477
|
+
/**
|
|
478
|
+
* Reverse filter - reverses character order in string.
|
|
479
|
+
*
|
|
480
|
+
* @param options - Unused
|
|
481
|
+
* @returns Filter function that returns reversed string
|
|
482
|
+
*/
|
|
483
|
+
const rev = (_options) => {
|
|
484
|
+
return (value) => {
|
|
485
|
+
return String(value).split('').reverse().join('');
|
|
486
|
+
};
|
|
487
|
+
};
|
|
488
|
+
/**
|
|
489
|
+
* Integer filter - parses value to integer.
|
|
490
|
+
*
|
|
491
|
+
* @param options - Unused
|
|
492
|
+
* @returns Filter function that returns integer
|
|
493
|
+
*/
|
|
494
|
+
const int = (_options) => {
|
|
495
|
+
return (value) => {
|
|
496
|
+
return parseInt(String(value), 10);
|
|
497
|
+
};
|
|
498
|
+
};
|
|
499
|
+
/**
|
|
500
|
+
* Float filter - parses value to floating point number.
|
|
501
|
+
*
|
|
502
|
+
* @param options - Unused
|
|
503
|
+
* @returns Filter function that returns float
|
|
504
|
+
*/
|
|
505
|
+
const float = (_options) => {
|
|
506
|
+
return (value) => {
|
|
507
|
+
return parseFloat(String(value));
|
|
508
|
+
};
|
|
509
|
+
};
|
|
510
|
+
/**
|
|
511
|
+
* Round filter - rounds number to specified decimal places.
|
|
512
|
+
*
|
|
513
|
+
* @param options - Array with decimal places as first element (default: 0)
|
|
514
|
+
* @returns Filter function that returns rounded number
|
|
515
|
+
*/
|
|
516
|
+
const round = (options) => {
|
|
517
|
+
const opt = options?.[0] ?? '0';
|
|
518
|
+
if (!validateNumberString(opt)) {
|
|
519
|
+
optionMustBeNumber('round');
|
|
520
|
+
}
|
|
521
|
+
return (value) => {
|
|
522
|
+
if (typeof value !== 'number') {
|
|
523
|
+
valueMustBeNumber('round');
|
|
524
|
+
}
|
|
525
|
+
const optValue = Math.pow(10, Number(opt));
|
|
526
|
+
return Math.round(value * optValue) / optValue;
|
|
527
|
+
};
|
|
528
|
+
};
|
|
529
|
+
/**
|
|
530
|
+
* Floor filter - rounds number down to specified decimal places.
|
|
531
|
+
*
|
|
532
|
+
* @param options - Array with decimal places as first element (default: 0)
|
|
533
|
+
* @returns Filter function that returns floored number
|
|
534
|
+
*/
|
|
535
|
+
const floor = (options) => {
|
|
536
|
+
const opt = options?.[0] ?? '0';
|
|
537
|
+
if (!validateNumberString(opt)) {
|
|
538
|
+
optionMustBeNumber('floor');
|
|
539
|
+
}
|
|
540
|
+
return (value) => {
|
|
541
|
+
if (typeof value !== 'number') {
|
|
542
|
+
valueMustBeNumber('floor');
|
|
543
|
+
}
|
|
544
|
+
const optValue = Math.pow(10, Number(opt));
|
|
545
|
+
return Math.floor(value * optValue) / optValue;
|
|
546
|
+
};
|
|
547
|
+
};
|
|
548
|
+
/**
|
|
549
|
+
* Ceiling filter - rounds number up to specified decimal places.
|
|
550
|
+
*
|
|
551
|
+
* @param options - Array with decimal places as first element (default: 0)
|
|
552
|
+
* @returns Filter function that returns ceiled number
|
|
553
|
+
*/
|
|
554
|
+
const ceil = (options) => {
|
|
555
|
+
const opt = options?.[0] ?? '0';
|
|
556
|
+
if (!validateNumberString(opt)) {
|
|
557
|
+
optionMustBeNumber('ceil');
|
|
558
|
+
}
|
|
559
|
+
return (value) => {
|
|
560
|
+
if (typeof value !== 'number') {
|
|
561
|
+
valueMustBeNumber('ceil');
|
|
562
|
+
}
|
|
563
|
+
const optValue = Math.pow(10, Number(opt));
|
|
564
|
+
return Math.ceil(value * optValue) / optValue;
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
/**
|
|
568
|
+
* Percent filter - formats number as percentage string.
|
|
569
|
+
*
|
|
570
|
+
* @param options - Array with decimal places as first element (default: 0)
|
|
571
|
+
* @returns Filter function that returns percentage string with '%'
|
|
572
|
+
*/
|
|
573
|
+
const percent = (options) => {
|
|
574
|
+
const opt = options?.[0] ?? '0';
|
|
575
|
+
if (!validateNumberString(opt)) {
|
|
576
|
+
optionMustBeNumber('percent');
|
|
577
|
+
}
|
|
578
|
+
return (value) => {
|
|
579
|
+
if (typeof value !== 'number') {
|
|
580
|
+
valueMustBeNumber('percent');
|
|
581
|
+
}
|
|
582
|
+
return `${(value * 100).toFixed(Number(opt))}%`;
|
|
583
|
+
};
|
|
584
|
+
};
|
|
585
|
+
/**
|
|
586
|
+
* Date filter - formats Date object as localized date string.
|
|
587
|
+
*
|
|
588
|
+
* @param options - Array with locale string as first element (default: config.locale)
|
|
589
|
+
* @returns Filter function that returns date string
|
|
590
|
+
*/
|
|
591
|
+
const date = (options) => {
|
|
592
|
+
const opt = options?.[0] ?? config.locale;
|
|
593
|
+
return (value) => {
|
|
594
|
+
if (!(value instanceof Date)) {
|
|
595
|
+
valueMustBeDate('date');
|
|
596
|
+
}
|
|
597
|
+
return value.toLocaleDateString(opt);
|
|
598
|
+
};
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* Time filter - formats Date object as localized time string.
|
|
602
|
+
*
|
|
603
|
+
* @param options - Array with locale string as first element (default: config.locale)
|
|
604
|
+
* @returns Filter function that returns time string
|
|
605
|
+
*/
|
|
606
|
+
const time = (options) => {
|
|
607
|
+
const opt = options?.[0] ?? config.locale;
|
|
608
|
+
return (value) => {
|
|
609
|
+
if (!(value instanceof Date)) {
|
|
610
|
+
valueMustBeDate('time');
|
|
611
|
+
}
|
|
612
|
+
return value.toLocaleTimeString(opt);
|
|
613
|
+
};
|
|
614
|
+
};
|
|
615
|
+
/**
|
|
616
|
+
* DateTime filter - formats Date object as localized date and time string.
|
|
617
|
+
*
|
|
618
|
+
* @param options - Array with locale string as first element (default: config.locale)
|
|
619
|
+
* @returns Filter function that returns datetime string
|
|
620
|
+
*/
|
|
621
|
+
const datetime = (options) => {
|
|
622
|
+
const opt = options?.[0] ?? config.locale;
|
|
623
|
+
return (value) => {
|
|
624
|
+
if (!(value instanceof Date)) {
|
|
625
|
+
valueMustBeDate('datetime');
|
|
626
|
+
}
|
|
627
|
+
return value.toLocaleString(opt);
|
|
628
|
+
};
|
|
629
|
+
};
|
|
630
|
+
/**
|
|
631
|
+
* Year-Month-Day filter - formats Date object as YYYY-MM-DD string.
|
|
632
|
+
*
|
|
633
|
+
* @param options - Array with separator string as first element (default: '-')
|
|
634
|
+
* @returns Filter function that returns formatted date string
|
|
635
|
+
*/
|
|
636
|
+
const ymd = (options) => {
|
|
637
|
+
const opt = options?.[0] ?? '-';
|
|
638
|
+
return (value) => {
|
|
639
|
+
if (!(value instanceof Date)) {
|
|
640
|
+
valueMustBeDate('ymd');
|
|
641
|
+
}
|
|
642
|
+
const year = value.getFullYear().toString();
|
|
643
|
+
const month = (value.getMonth() + 1).toString().padStart(2, '0');
|
|
644
|
+
const day = value.getDate().toString().padStart(2, '0');
|
|
645
|
+
return `${year}${opt}${month}${opt}${day}`;
|
|
646
|
+
};
|
|
647
|
+
};
|
|
648
|
+
/**
|
|
649
|
+
* Falsy filter - checks if value is falsy.
|
|
650
|
+
*
|
|
651
|
+
* @param options - Unused
|
|
652
|
+
* @returns Filter function that returns true for false/null/undefined/0/''/NaN
|
|
653
|
+
*/
|
|
654
|
+
const falsy = (_options) => {
|
|
655
|
+
return (value) => value === false || value === null || value === undefined || value === 0 || value === '' || Number.isNaN(value);
|
|
656
|
+
};
|
|
657
|
+
/**
|
|
658
|
+
* Truthy filter - checks if value is truthy.
|
|
659
|
+
*
|
|
660
|
+
* @param options - Unused
|
|
661
|
+
* @returns Filter function that returns true for non-falsy values
|
|
662
|
+
*/
|
|
663
|
+
const truthy = (_options) => {
|
|
664
|
+
return (value) => value !== false && value !== null && value !== undefined && value !== 0 && value !== '' && !Number.isNaN(value);
|
|
665
|
+
};
|
|
666
|
+
/**
|
|
667
|
+
* Default filter - returns default value if input is falsy.
|
|
668
|
+
*
|
|
669
|
+
* @param options - Array with default value as first element
|
|
670
|
+
* @returns Filter function that returns value or default
|
|
671
|
+
*/
|
|
672
|
+
const defaults = (options) => {
|
|
673
|
+
const opt = options?.[0] ?? optionsRequired('defaults');
|
|
674
|
+
return (value) => {
|
|
675
|
+
if (value === false || value === null || value === undefined || value === 0 || value === '' || Number.isNaN(value)) {
|
|
676
|
+
return opt;
|
|
677
|
+
}
|
|
678
|
+
return value;
|
|
679
|
+
};
|
|
680
|
+
};
|
|
681
|
+
/**
|
|
682
|
+
* Boolean filter - converts value to boolean.
|
|
683
|
+
*
|
|
684
|
+
* @param options - Unused
|
|
685
|
+
* @returns Filter function that returns boolean
|
|
686
|
+
*/
|
|
687
|
+
const boolean = (_options) => {
|
|
688
|
+
return (value) => {
|
|
689
|
+
return Boolean(value);
|
|
690
|
+
};
|
|
691
|
+
};
|
|
692
|
+
/**
|
|
693
|
+
* Number filter - converts value to number.
|
|
694
|
+
*
|
|
695
|
+
* @param options - Unused
|
|
696
|
+
* @returns Filter function that returns number
|
|
697
|
+
*/
|
|
698
|
+
const number = (_options) => {
|
|
699
|
+
return (value) => {
|
|
700
|
+
return Number(value);
|
|
701
|
+
};
|
|
702
|
+
};
|
|
703
|
+
/**
|
|
704
|
+
* String filter - converts value to string.
|
|
705
|
+
*
|
|
706
|
+
* @param options - Unused
|
|
707
|
+
* @returns Filter function that returns string
|
|
708
|
+
*/
|
|
709
|
+
const string = (_options) => {
|
|
710
|
+
return (value) => {
|
|
711
|
+
return String(value);
|
|
712
|
+
};
|
|
713
|
+
};
|
|
714
|
+
/**
|
|
715
|
+
* Null filter - converts empty string to null.
|
|
716
|
+
*
|
|
717
|
+
* @param options - Unused
|
|
718
|
+
* @returns Filter function that returns null for empty string, otherwise original value
|
|
719
|
+
*/
|
|
720
|
+
const _null = (_options) => {
|
|
721
|
+
return (value) => {
|
|
722
|
+
return (value === "") ? null : value;
|
|
723
|
+
};
|
|
724
|
+
};
|
|
725
|
+
const builtinFilters = {
|
|
726
|
+
"eq": eq,
|
|
727
|
+
"ne": ne,
|
|
728
|
+
"not": not,
|
|
729
|
+
"lt": lt,
|
|
730
|
+
"le": le,
|
|
731
|
+
"gt": gt,
|
|
732
|
+
"ge": ge,
|
|
733
|
+
"inc": inc,
|
|
734
|
+
"dec": dec,
|
|
735
|
+
"mul": mul,
|
|
736
|
+
"div": div,
|
|
737
|
+
"mod": mod,
|
|
738
|
+
"fix": fix,
|
|
739
|
+
"locale": locale,
|
|
740
|
+
"uc": uc,
|
|
741
|
+
"lc": lc,
|
|
742
|
+
"cap": cap,
|
|
743
|
+
"trim": trim,
|
|
744
|
+
"slice": slice,
|
|
745
|
+
"substr": substr,
|
|
746
|
+
"pad": pad,
|
|
747
|
+
"rep": rep,
|
|
748
|
+
"rev": rev,
|
|
749
|
+
"int": int,
|
|
750
|
+
"float": float,
|
|
751
|
+
"round": round,
|
|
752
|
+
"floor": floor,
|
|
753
|
+
"ceil": ceil,
|
|
754
|
+
"percent": percent,
|
|
755
|
+
"date": date,
|
|
756
|
+
"time": time,
|
|
757
|
+
"datetime": datetime,
|
|
758
|
+
"ymd": ymd,
|
|
759
|
+
"falsy": falsy,
|
|
760
|
+
"truthy": truthy,
|
|
761
|
+
"defaults": defaults,
|
|
762
|
+
"boolean": boolean,
|
|
763
|
+
"number": number,
|
|
764
|
+
"string": string,
|
|
765
|
+
"null": _null,
|
|
766
|
+
};
|
|
767
|
+
const outputBuiltinFilters = builtinFilters;
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* filterMeta.ts — 組み込みフィルタの構造化メタデータ(単一正本・route-a A2-1)。
|
|
771
|
+
*
|
|
772
|
+
* これまで vscode-wcs(completionData.ts BUILTIN_FILTERS)が手で持っていたフィルタの
|
|
773
|
+
* 引数仕様・型・説明を、実装側(@wcstack/state)に**正本として移設**したもの。
|
|
774
|
+
* manifest.ts がこれを公開し、vscode-wcs はそれを消費して手リストを撤去できる。
|
|
775
|
+
*
|
|
776
|
+
* 完全性は __tests__/manifest.test.ts のドリフト検出が保証する
|
|
777
|
+
* (filterMeta のキー集合 == builtinFilters のキー集合)。フィルタを追加して meta を
|
|
778
|
+
* 書き忘れると CI が落ちる。
|
|
779
|
+
*/
|
|
780
|
+
/** 組み込みフィルタ名 → 構造化メタデータ。キー集合は builtinFilters と一致しなければならない。 */
|
|
781
|
+
const builtinFilterMeta = {
|
|
782
|
+
// 比較・論理
|
|
783
|
+
eq: { description: "等しいか比較", hasArgs: true, resultType: "boolean", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
|
|
784
|
+
ne: { description: "異なるか比較", hasArgs: true, resultType: "boolean", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
|
|
785
|
+
not: { description: "ブール値を反転", hasArgs: false, resultType: "boolean", acceptTypes: ["boolean"], minArgs: 0, maxArgs: 0 },
|
|
786
|
+
lt: { description: "より小さいか", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
787
|
+
le: { description: "以下か", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
788
|
+
gt: { description: "より大きいか", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
789
|
+
ge: { description: "以上か", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
790
|
+
// 算術
|
|
791
|
+
inc: { description: "加算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
792
|
+
dec: { description: "減算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
793
|
+
mul: { description: "乗算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
794
|
+
div: { description: "除算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
795
|
+
mod: { description: "剰余", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
796
|
+
// 数値フォーマット
|
|
797
|
+
fix: { description: "固定小数点表記", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
798
|
+
locale: { description: "ロケール形式で数値フォーマット", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
|
|
799
|
+
// 文字列
|
|
800
|
+
uc: { description: "大文字に変換", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
801
|
+
lc: { description: "小文字に変換", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
802
|
+
cap: { description: "先頭文字を大文字に", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
803
|
+
trim: { description: "前後の空白を削除", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
804
|
+
slice: { description: "部分文字列 (start[,end])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
|
|
805
|
+
substr: { description: "部分文字列 (pos,len)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
|
|
806
|
+
pad: { description: "パディング (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
|
|
807
|
+
rep: { description: "繰り返し (count)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
808
|
+
rev: { description: "文字順を反転", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
809
|
+
// 数値パース・丸め
|
|
810
|
+
int: { description: "整数にパース", hasArgs: false, resultType: "number", acceptTypes: ["string", "number"], minArgs: 0, maxArgs: 0 },
|
|
811
|
+
float: { description: "浮動小数点数にパース", hasArgs: false, resultType: "number", acceptTypes: ["string", "number"], minArgs: 0, maxArgs: 0 },
|
|
812
|
+
round: { description: "四捨五入", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
813
|
+
floor: { description: "切り下げ", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
814
|
+
ceil: { description: "切り上げ", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
815
|
+
percent: { description: "パーセンテージ形式", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
816
|
+
// 日付・時刻
|
|
817
|
+
date: { description: "ロケール形式の日付", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
818
|
+
time: { description: "ロケール形式の時刻", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
819
|
+
datetime: { description: "ロケール形式の日時", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
820
|
+
ymd: { description: "YYYY-MM-DD 形式", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
|
|
821
|
+
// 真偽値・変換
|
|
822
|
+
falsy: { description: "偽値か判定", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
823
|
+
truthy: { description: "真値か判定", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
824
|
+
defaults: { description: "偽値の場合デフォルト値", hasArgs: true, resultType: "passthrough", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
|
|
825
|
+
boolean: { description: "ブール値に変換", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
826
|
+
number: { description: "数値に変換", hasArgs: false, resultType: "number", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
827
|
+
string: { description: "文字列に変換", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
828
|
+
null: { description: "空文字列をnullに変換", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
const STRUCTURAL_BINDING_TYPE_SET = new Set([
|
|
832
|
+
"if",
|
|
833
|
+
"elseif",
|
|
834
|
+
"else",
|
|
835
|
+
"for",
|
|
836
|
+
]);
|
|
837
|
+
|
|
838
|
+
const DELIMITER = '.';
|
|
839
|
+
const WILDCARD = '*';
|
|
840
|
+
const MAX_WILDCARD_DEPTH = 128;
|
|
841
|
+
// data-wcs バインディング構文 `[prop][#mod]: [path][@state][|filter...]` の区切り文字(単一正本)。
|
|
842
|
+
// これらは「死守の壁(構文契約)」であり値は不変。manifest.syntax.delimiters で公開される。
|
|
843
|
+
const BINDING_SEPARATOR = ';'; // 複数バインディングの区切り
|
|
844
|
+
const PROP_VALUE_SEPARATOR = ':'; // 左辺(prop)と右辺(path)の区切り
|
|
845
|
+
const MODIFIER_SEPARATOR = '#'; // prop と修飾子の区切り
|
|
846
|
+
const STATE_NAME_SEPARATOR = '@'; // path と @stateName の区切り
|
|
847
|
+
const FILTER_SEPARATOR = '|'; // フィルタパイプの区切り
|
|
848
|
+
/**
|
|
849
|
+
* stackIndexByIndexName
|
|
850
|
+
* インデックス名からスタックインデックスへのマッピング
|
|
851
|
+
* $1 => 0
|
|
852
|
+
* $2 => 1
|
|
853
|
+
* :
|
|
854
|
+
* ${i + 1} => i
|
|
855
|
+
* i < MAX_WILDCARD_DEPTH
|
|
856
|
+
*/
|
|
857
|
+
const tmpIndexByIndexName = {};
|
|
858
|
+
for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
|
|
859
|
+
tmpIndexByIndexName[`$${i + 1}`] = i;
|
|
860
|
+
}
|
|
861
|
+
Object.freeze(tmpIndexByIndexName);
|
|
862
|
+
const STATE_CONNECTED_CALLBACK_NAME = "$connectedCallback";
|
|
863
|
+
const STATE_DISCONNECTED_CALLBACK_NAME = "$disconnectedCallback";
|
|
864
|
+
const STATE_UPDATED_CALLBACK_NAME = "$updatedCallback";
|
|
865
|
+
const WEBCOMPONENT_STATE_READY_CALLBACK_NAME = "$stateReadyCallback";
|
|
866
|
+
const STATE_BINDABLES_NAME = "$bindables";
|
|
867
|
+
const STATE_COMMAND_TOKENS_NAME = "$commandTokens";
|
|
868
|
+
const STATE_COMMAND_NAMESPACE_NAME = "$command";
|
|
869
|
+
const STATE_EVENT_TOKENS_NAME = "$eventTokens";
|
|
870
|
+
const STATE_ON_NAME = "$on";
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* manifest.ts — `<wcs-state>` の構文・フィルタ・予約名を機械可読な単一正本として公開する。
|
|
874
|
+
*
|
|
875
|
+
* 目的(route-a A2-1): vscode-wcs(wcstack-intellisense)が現在ハードコードで二重実装している
|
|
876
|
+
* 「フィルタ一覧・構文区切り・予約名」を、state 側の実装から導出した manifest に一本化し、
|
|
877
|
+
* 手作業同期によるドリフトを構造的に断つための土台。
|
|
878
|
+
*
|
|
879
|
+
* 設計:
|
|
880
|
+
* - `filters` は実装(builtinFilters の Record キー)から **自動導出**=実装が唯一の正本。
|
|
881
|
+
* - 構文・予約名は config / define.ts の定数から導出。
|
|
882
|
+
* - 将来 `dist/wcs-manifest.json` としてビルド時に書き出し、vscode-wcs がそれを読む形に発展させる。
|
|
883
|
+
* - ドリフト検出テスト(__tests__/manifest.test.ts)が、フィルタ集合の golden と実装の一致を CI で保証する。
|
|
884
|
+
*/
|
|
885
|
+
/** マニフェストのバージョン(構造を変えたら上げる)。 */
|
|
886
|
+
const WCS_MANIFEST_VERSION = 1;
|
|
887
|
+
/** 機械可読な単一正本を返す。vscode-wcs はこれを消費する想定。 */
|
|
888
|
+
function getWcsManifest() {
|
|
889
|
+
return {
|
|
890
|
+
version: WCS_MANIFEST_VERSION,
|
|
891
|
+
syntax: {
|
|
892
|
+
bindAttribute: config.bindAttributeName,
|
|
893
|
+
tagName: config.tagNames.state,
|
|
894
|
+
pathDelimiter: DELIMITER,
|
|
895
|
+
wildcard: WILDCARD,
|
|
896
|
+
delimiters: {
|
|
897
|
+
binding: BINDING_SEPARATOR,
|
|
898
|
+
propValue: PROP_VALUE_SEPARATOR,
|
|
899
|
+
modifier: MODIFIER_SEPARATOR,
|
|
900
|
+
stateName: STATE_NAME_SEPARATOR,
|
|
901
|
+
filter: FILTER_SEPARATOR,
|
|
902
|
+
},
|
|
903
|
+
// 正本 STRUCTURAL_BINDING_TYPE_SET から導出(手書きの二重定義を排除)。
|
|
904
|
+
structuralDirectives: Array.from(STRUCTURAL_BINDING_TYPE_SET),
|
|
905
|
+
},
|
|
906
|
+
// 実装(Record のキー)から自動導出。手リストを持たない=ドリフトの構造的排除。
|
|
907
|
+
filters: Object.keys(outputBuiltinFilters),
|
|
908
|
+
filterMeta: builtinFilterMeta,
|
|
909
|
+
reservedLifecycle: [
|
|
910
|
+
STATE_CONNECTED_CALLBACK_NAME,
|
|
911
|
+
STATE_DISCONNECTED_CALLBACK_NAME,
|
|
912
|
+
STATE_UPDATED_CALLBACK_NAME,
|
|
913
|
+
WEBCOMPONENT_STATE_READY_CALLBACK_NAME,
|
|
914
|
+
],
|
|
915
|
+
reservedStateApi: [
|
|
916
|
+
STATE_BINDABLES_NAME,
|
|
917
|
+
STATE_COMMAND_TOKENS_NAME,
|
|
918
|
+
STATE_COMMAND_NAMESPACE_NAME,
|
|
919
|
+
STATE_EVENT_TOKENS_NAME,
|
|
920
|
+
STATE_ON_NAME,
|
|
921
|
+
],
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
export { STRUCTURAL_BINDING_TYPE_SET, WCS_MANIFEST_VERSION, builtinFilterMeta, getWcsManifest };
|