@hyperfixi/core 3.1.0 → 3.2.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/README.md +28 -36
- package/dist/ast/command-slots.d.ts +1 -1
- package/dist/ast/nodes.d.ts +2 -0
- package/dist/ast-utils/index.cjs +193 -48
- package/dist/ast-utils/index.mjs +193 -48
- package/dist/ast-utils/interchange/types.d.ts +19 -1
- package/dist/behaviors/index.cjs +19 -0
- package/dist/behaviors/index.mjs +19 -0
- package/dist/bundle-generator/index.cjs +24 -9
- package/dist/bundle-generator/index.mjs +24 -9
- package/dist/bundle-generator/parser-templates.d.ts +1 -1
- package/dist/chunks/bridge-Cnj8dQFV.js +2 -0
- package/dist/chunks/browser-modular-BNDYF6Dq.js +2 -0
- package/dist/chunks/index-DQi2o8Lk.js +2 -0
- package/dist/chunks/index-LLuwEQp0.js +2 -0
- package/dist/chunks/index-uCOQ8Qn0.js +2 -0
- package/dist/commands/animation/transition.d.ts +12 -6
- package/dist/commands/helpers/loop-executor.d.ts +2 -2
- package/dist/commands/helpers/numeric-target-parser.d.ts +1 -1
- package/dist/commands/helpers/variable-access.d.ts +5 -2
- package/dist/commands/helpers/write-target.d.ts +5 -0
- package/dist/commands/index.cjs +929 -425
- package/dist/commands/index.mjs +929 -425
- package/dist/commands/templates/render.d.ts +4 -4
- package/dist/commands/utility/beep.d.ts +0 -3
- package/dist/expressions/index.cjs +7 -13
- package/dist/expressions/index.mjs +7 -13
- package/dist/htmx/i18n-hooks.d.ts +4 -1
- package/dist/hyperfixi-browser-classic-i18n.js +1 -1
- package/dist/hyperfixi-browser.js +1 -1
- package/dist/hyperfixi-classic-i18n.js +1 -1
- package/dist/hyperfixi-hx-v4.js +1 -1
- package/dist/hyperfixi-hx.js +1 -1
- package/dist/hyperfixi-hybrid-complete.js +1 -1
- package/dist/hyperfixi-hybrid-hx.js +1 -1
- package/dist/hyperfixi-multilingual.js +1 -1
- package/dist/hyperfixi.js +1 -1
- package/dist/hyperfixi.mjs +1 -1
- package/dist/index.cjs +1140 -485
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +1140 -485
- package/dist/lib/swap-executor.d.ts +1 -1
- package/dist/lokascript-browser-classic-i18n.js +1 -1
- package/dist/lokascript-browser.js +1 -1
- package/dist/lokascript-hybrid-complete.js +1 -1
- package/dist/lokascript-hybrid-hx.js +1 -1
- package/dist/lokascript-multilingual.js +1 -1
- package/dist/metadata.cjs +9 -9
- package/dist/metadata.d.ts +1 -1
- package/dist/metadata.mjs +9 -9
- package/dist/parser/command-grammar.d.ts +1 -0
- package/dist/parser/full-parser.cjs +387 -153
- package/dist/parser/full-parser.mjs +387 -153
- package/dist/parser/helpers/parsing-helpers.d.ts +3 -0
- package/dist/parser/hybrid/index.cjs +3 -0
- package/dist/parser/hybrid/index.mjs +3 -0
- package/dist/parser/hybrid/parser-core.cjs +3 -0
- package/dist/parser/hybrid/parser-core.mjs +3 -0
- package/dist/parser/hybrid-parser.cjs +3 -0
- package/dist/parser/hybrid-parser.mjs +3 -0
- package/dist/parser/parser-types.d.ts +2 -0
- package/dist/parser/parser.d.ts +9 -0
- package/dist/parser/pratt-parser.d.ts +2 -0
- package/dist/registry/index.cjs +526 -210
- package/dist/registry/index.mjs +526 -210
- package/dist/utils/beep.d.ts +8 -0
- package/dist/version.d.ts +1 -1
- package/package.json +21 -18
- package/vocab/htmx/ar.js +22 -20
- package/vocab/htmx/bn.js +21 -5
- package/vocab/htmx/de.js +33 -10
- package/vocab/htmx/en.js +4 -1
- package/vocab/htmx/es.js +28 -9
- package/vocab/htmx/fr.js +28 -8
- package/vocab/htmx/he.js +22 -1
- package/vocab/htmx/hi.js +28 -7
- package/vocab/htmx/id.js +29 -10
- package/vocab/htmx/it.js +26 -5
- package/vocab/htmx/ja.js +36 -11
- package/vocab/htmx/ko.js +27 -6
- package/vocab/htmx/ms.js +24 -1
- package/vocab/htmx/pl.js +27 -7
- package/vocab/htmx/pt.js +30 -9
- package/vocab/htmx/qu.js +32 -9
- package/vocab/htmx/ru.js +28 -6
- package/vocab/htmx/sw.js +28 -8
- package/vocab/htmx/th.js +19 -1
- package/vocab/htmx/tl.js +24 -1
- package/vocab/htmx/tr.js +34 -8
- package/vocab/htmx/uk.js +28 -6
- package/vocab/htmx/vi.js +27 -19
- package/vocab/htmx/zh.js +28 -9
- package/dist/chunks/bridge-DylVo1oZ.js +0 -2
- package/dist/chunks/browser-modular-sLPMdxR7.js +0 -2
- package/dist/chunks/index-C7lqD4mo.js +0 -2
- package/dist/chunks/index-CAPhqA6k.js +0 -2
- package/dist/chunks/index-CLdRyZaP.js +0 -2
package/dist/commands/index.cjs
CHANGED
|
@@ -537,6 +537,75 @@ function parseAttributeWithValue(expression) {
|
|
|
537
537
|
return { name: result.name, value: result.value ?? '' };
|
|
538
538
|
}
|
|
539
539
|
|
|
540
|
+
function _parseDurationComponents(value) {
|
|
541
|
+
const trimmed = value.trim();
|
|
542
|
+
const match = trimmed.match(/^(\d+(?:\.\d+)?)\s*(s|ms|sec|seconds?|milliseconds?)?$/i);
|
|
543
|
+
if (!match) {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
const number = parseFloat(match[1]);
|
|
547
|
+
const unit = (match[2] || 'ms').toLowerCase();
|
|
548
|
+
if (unit === 'ms' || unit === 'millisecond' || unit === 'milliseconds') {
|
|
549
|
+
return { number, milliseconds: Math.floor(number) };
|
|
550
|
+
}
|
|
551
|
+
else if (unit === 's' || unit === 'sec' || unit === 'second' || unit === 'seconds') {
|
|
552
|
+
return { number, milliseconds: Math.floor(number * 1000) };
|
|
553
|
+
}
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
function parseDuration(value, defaultMs = 300) {
|
|
557
|
+
if (typeof value === 'number') {
|
|
558
|
+
return Math.max(0, Math.floor(value));
|
|
559
|
+
}
|
|
560
|
+
if (typeof value === 'string') {
|
|
561
|
+
const result = _parseDurationComponents(value);
|
|
562
|
+
return result ? result.milliseconds : defaultMs;
|
|
563
|
+
}
|
|
564
|
+
return defaultMs;
|
|
565
|
+
}
|
|
566
|
+
function parseDurationStrict(value) {
|
|
567
|
+
if (typeof value === 'number') {
|
|
568
|
+
if (value < 0)
|
|
569
|
+
throw new Error('Duration must be >= 0');
|
|
570
|
+
return Math.floor(value);
|
|
571
|
+
}
|
|
572
|
+
if (typeof value === 'string') {
|
|
573
|
+
const result = _parseDurationComponents(value);
|
|
574
|
+
if (!result) {
|
|
575
|
+
throw new Error(`Invalid duration format: "${value}"`);
|
|
576
|
+
}
|
|
577
|
+
return result.milliseconds;
|
|
578
|
+
}
|
|
579
|
+
throw new Error(`Invalid duration type: ${typeof value}`);
|
|
580
|
+
}
|
|
581
|
+
function parseCSSDurations(durationString) {
|
|
582
|
+
if (!durationString || durationString === 'none') {
|
|
583
|
+
return [0];
|
|
584
|
+
}
|
|
585
|
+
return durationString.split(',').map(duration => {
|
|
586
|
+
const value = parseFloat(duration.trim());
|
|
587
|
+
if (isNaN(value))
|
|
588
|
+
return 0;
|
|
589
|
+
if (duration.includes('s') && !duration.includes('ms')) {
|
|
590
|
+
return value * 1000;
|
|
591
|
+
}
|
|
592
|
+
return value;
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
function calculateMaxAnimationTime(durations, delays) {
|
|
596
|
+
let maxTime = 0;
|
|
597
|
+
for (let i = 0; i < durations.length; i++) {
|
|
598
|
+
const duration = durations[i] || 0;
|
|
599
|
+
const delay = delays[i] || 0;
|
|
600
|
+
const totalTime = duration + delay;
|
|
601
|
+
maxTime = Math.max(maxTime, totalTime);
|
|
602
|
+
}
|
|
603
|
+
return maxTime;
|
|
604
|
+
}
|
|
605
|
+
function camelToKebab(str) {
|
|
606
|
+
return str.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
607
|
+
}
|
|
608
|
+
|
|
540
609
|
function batchApply(targets, operation) {
|
|
541
610
|
for (const element of targets) {
|
|
542
611
|
operation(element);
|
|
@@ -602,15 +671,18 @@ function toggleAttribute(element, name, value) {
|
|
|
602
671
|
}
|
|
603
672
|
}
|
|
604
673
|
}
|
|
674
|
+
function toCssPropertyName(property) {
|
|
675
|
+
return property.startsWith('--') ? property : camelToKebab(property);
|
|
676
|
+
}
|
|
605
677
|
function batchSetStyles(targets, styles) {
|
|
606
678
|
const entries = Object.entries(styles);
|
|
607
679
|
return batchApplyItems(targets, entries, (element, [property, value]) => {
|
|
608
|
-
element.style.setProperty(property, value);
|
|
680
|
+
element.style.setProperty(toCssPropertyName(property), value);
|
|
609
681
|
});
|
|
610
682
|
}
|
|
611
683
|
function batchRemoveStyles(targets, properties) {
|
|
612
684
|
return batchApplyItems(targets, properties, (element, property) => {
|
|
613
|
-
element.style.removeProperty(property);
|
|
685
|
+
element.style.removeProperty(toCssPropertyName(property));
|
|
614
686
|
});
|
|
615
687
|
}
|
|
616
688
|
|
|
@@ -1345,75 +1417,6 @@ let RemoveCommand = (() => {
|
|
|
1345
1417
|
})();
|
|
1346
1418
|
const createRemoveCommand = createFactory(RemoveCommand);
|
|
1347
1419
|
|
|
1348
|
-
function _parseDurationComponents(value) {
|
|
1349
|
-
const trimmed = value.trim();
|
|
1350
|
-
const match = trimmed.match(/^(\d+(?:\.\d+)?)\s*(s|ms|sec|seconds?|milliseconds?)?$/i);
|
|
1351
|
-
if (!match) {
|
|
1352
|
-
return null;
|
|
1353
|
-
}
|
|
1354
|
-
const number = parseFloat(match[1]);
|
|
1355
|
-
const unit = (match[2] || 'ms').toLowerCase();
|
|
1356
|
-
if (unit === 'ms' || unit === 'millisecond' || unit === 'milliseconds') {
|
|
1357
|
-
return { number, milliseconds: Math.floor(number) };
|
|
1358
|
-
}
|
|
1359
|
-
else if (unit === 's' || unit === 'sec' || unit === 'second' || unit === 'seconds') {
|
|
1360
|
-
return { number, milliseconds: Math.floor(number * 1000) };
|
|
1361
|
-
}
|
|
1362
|
-
return null;
|
|
1363
|
-
}
|
|
1364
|
-
function parseDuration(value, defaultMs = 300) {
|
|
1365
|
-
if (typeof value === 'number') {
|
|
1366
|
-
return Math.max(0, Math.floor(value));
|
|
1367
|
-
}
|
|
1368
|
-
if (typeof value === 'string') {
|
|
1369
|
-
const result = _parseDurationComponents(value);
|
|
1370
|
-
return result ? result.milliseconds : defaultMs;
|
|
1371
|
-
}
|
|
1372
|
-
return defaultMs;
|
|
1373
|
-
}
|
|
1374
|
-
function parseDurationStrict(value) {
|
|
1375
|
-
if (typeof value === 'number') {
|
|
1376
|
-
if (value < 0)
|
|
1377
|
-
throw new Error('Duration must be >= 0');
|
|
1378
|
-
return Math.floor(value);
|
|
1379
|
-
}
|
|
1380
|
-
if (typeof value === 'string') {
|
|
1381
|
-
const result = _parseDurationComponents(value);
|
|
1382
|
-
if (!result) {
|
|
1383
|
-
throw new Error(`Invalid duration format: "${value}"`);
|
|
1384
|
-
}
|
|
1385
|
-
return result.milliseconds;
|
|
1386
|
-
}
|
|
1387
|
-
throw new Error(`Invalid duration type: ${typeof value}`);
|
|
1388
|
-
}
|
|
1389
|
-
function parseCSSDurations(durationString) {
|
|
1390
|
-
if (!durationString || durationString === 'none') {
|
|
1391
|
-
return [0];
|
|
1392
|
-
}
|
|
1393
|
-
return durationString.split(',').map(duration => {
|
|
1394
|
-
const value = parseFloat(duration.trim());
|
|
1395
|
-
if (isNaN(value))
|
|
1396
|
-
return 0;
|
|
1397
|
-
if (duration.includes('s') && !duration.includes('ms')) {
|
|
1398
|
-
return value * 1000;
|
|
1399
|
-
}
|
|
1400
|
-
return value;
|
|
1401
|
-
});
|
|
1402
|
-
}
|
|
1403
|
-
function calculateMaxAnimationTime(durations, delays) {
|
|
1404
|
-
let maxTime = 0;
|
|
1405
|
-
for (let i = 0; i < durations.length; i++) {
|
|
1406
|
-
const duration = durations[i] || 0;
|
|
1407
|
-
const delay = delays[i] || 0;
|
|
1408
|
-
const totalTime = duration + delay;
|
|
1409
|
-
maxTime = Math.max(maxTime, totalTime);
|
|
1410
|
-
}
|
|
1411
|
-
return maxTime;
|
|
1412
|
-
}
|
|
1413
|
-
function camelToKebab(str) {
|
|
1414
|
-
return str.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
1420
|
function detectSmartElementType(elements) {
|
|
1418
1421
|
if (elements.length === 0)
|
|
1419
1422
|
return null;
|
|
@@ -1879,13 +1882,6 @@ function isFunction(value) {
|
|
|
1879
1882
|
function isInputElement$1(el) {
|
|
1880
1883
|
return (el !== null && typeof el === 'object' && 'tagName' in el && el.tagName === 'INPUT');
|
|
1881
1884
|
}
|
|
1882
|
-
function isFormElement$1(el) {
|
|
1883
|
-
if (el === null || typeof el !== 'object' || !('tagName' in el)) {
|
|
1884
|
-
return false;
|
|
1885
|
-
}
|
|
1886
|
-
const tag = el.tagName;
|
|
1887
|
-
return tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA';
|
|
1888
|
-
}
|
|
1889
1885
|
function isHTMLElement$1(el) {
|
|
1890
1886
|
return (el !== null &&
|
|
1891
1887
|
typeof el === 'object' &&
|
|
@@ -1945,7 +1941,7 @@ const SPECIAL_DOM_PROPERTIES = {
|
|
|
1945
1941
|
innertext: el => el.textContent?.trim(),
|
|
1946
1942
|
innerHTML: el => el.innerHTML,
|
|
1947
1943
|
outerhtml: el => el.outerHTML,
|
|
1948
|
-
value: el => (
|
|
1944
|
+
value: el => ('value' in el ? el.value : undefined),
|
|
1949
1945
|
checked: el => (isInputElement$1(el) ? el.checked : undefined),
|
|
1950
1946
|
disabled: el => ('disabled' in el ? el.disabled : undefined),
|
|
1951
1947
|
selected: el => (isOptionElement$1(el) ? el.selected : undefined),
|
|
@@ -2815,7 +2811,11 @@ let PutCommand = (() => {
|
|
|
2815
2811
|
}
|
|
2816
2812
|
if (isInsertableNode(v))
|
|
2817
2813
|
return v;
|
|
2818
|
-
|
|
2814
|
+
if (v == null)
|
|
2815
|
+
return 'null';
|
|
2816
|
+
if (Array.isArray(v))
|
|
2817
|
+
return arrayFragment(v);
|
|
2818
|
+
return String(v);
|
|
2819
2819
|
}
|
|
2820
2820
|
looksLikeCss(s) {
|
|
2821
2821
|
if (!s)
|
|
@@ -2900,6 +2900,19 @@ let PutCommand = (() => {
|
|
|
2900
2900
|
})();
|
|
2901
2901
|
return PutCommand = _classThis;
|
|
2902
2902
|
})();
|
|
2903
|
+
function arrayFragment(items) {
|
|
2904
|
+
const fragment = document.createDocumentFragment();
|
|
2905
|
+
for (const item of items) {
|
|
2906
|
+
if (isInsertableNode(item)) {
|
|
2907
|
+
fragment.append(item);
|
|
2908
|
+
continue;
|
|
2909
|
+
}
|
|
2910
|
+
const template = document.createElement('template');
|
|
2911
|
+
template.innerHTML = item === null ? '' : String(item);
|
|
2912
|
+
fragment.append(template.content);
|
|
2913
|
+
}
|
|
2914
|
+
return fragment;
|
|
2915
|
+
}
|
|
2903
2916
|
const createPutCommand = createFactory(PutCommand);
|
|
2904
2917
|
|
|
2905
2918
|
const GLOBAL_WRITE_HOOKS = new Set();
|
|
@@ -3022,6 +3035,16 @@ function convertToNumber(value) {
|
|
|
3022
3035
|
}
|
|
3023
3036
|
return 0;
|
|
3024
3037
|
}
|
|
3038
|
+
function counterAmount(value) {
|
|
3039
|
+
return typeof value === 'number' ? value : parseFloat(String(value));
|
|
3040
|
+
}
|
|
3041
|
+
function counterValue(value) {
|
|
3042
|
+
if (isHTMLElement$2(value)) {
|
|
3043
|
+
const element = value;
|
|
3044
|
+
return counterValue(element.value || element.textContent);
|
|
3045
|
+
}
|
|
3046
|
+
return value ? counterAmount(value) : 0;
|
|
3047
|
+
}
|
|
3025
3048
|
function getVariableValue(name, context, preferredScope) {
|
|
3026
3049
|
if (preferredScope === 'element') {
|
|
3027
3050
|
return getElementVar(context, name);
|
|
@@ -3126,35 +3149,39 @@ function setElementPropertyValue(propertyPath, value, context) {
|
|
|
3126
3149
|
element[property] = value;
|
|
3127
3150
|
}
|
|
3128
3151
|
}
|
|
3152
|
+
function isObjectOwner(value) {
|
|
3153
|
+
return (typeof value === 'object' && value !== null && !Array.isArray(value) && !isHTMLElement$2(value));
|
|
3154
|
+
}
|
|
3129
3155
|
function getCurrentNumericValue(target, property, scope, context) {
|
|
3130
3156
|
if (typeof target === 'number') {
|
|
3131
3157
|
return target;
|
|
3132
3158
|
}
|
|
3133
3159
|
if (isHTMLElement$2(target)) {
|
|
3134
3160
|
const element = target;
|
|
3161
|
+
if (property?.startsWith('@'))
|
|
3162
|
+
return counterValue(element.getAttribute(property.slice(1)));
|
|
3135
3163
|
if (property) {
|
|
3136
3164
|
if (property.startsWith('data-') ||
|
|
3137
3165
|
['id', 'class', 'title', 'alt', 'src', 'href'].includes(property)) {
|
|
3138
|
-
|
|
3139
|
-
return convertToNumber(value);
|
|
3166
|
+
return counterValue(element.getAttribute(property));
|
|
3140
3167
|
}
|
|
3141
3168
|
else {
|
|
3142
|
-
|
|
3143
|
-
return convertToNumber(value);
|
|
3169
|
+
return counterValue(element[property]);
|
|
3144
3170
|
}
|
|
3145
3171
|
}
|
|
3146
3172
|
else {
|
|
3147
|
-
|
|
3148
|
-
return convertToNumber(value);
|
|
3173
|
+
return counterValue(element);
|
|
3149
3174
|
}
|
|
3150
3175
|
}
|
|
3176
|
+
if (property && isObjectOwner(target)) {
|
|
3177
|
+
return counterValue(target[property]);
|
|
3178
|
+
}
|
|
3151
3179
|
if (typeof target === 'string') {
|
|
3152
3180
|
if (scope === 'element') {
|
|
3153
|
-
return
|
|
3181
|
+
return counterValue(getVariableValue(target, context, 'element'));
|
|
3154
3182
|
}
|
|
3155
3183
|
if (scope === 'global') {
|
|
3156
|
-
|
|
3157
|
-
return convertToNumber(value);
|
|
3184
|
+
return counterValue(getVariableValue(target, context, 'global'));
|
|
3158
3185
|
}
|
|
3159
3186
|
if (target.includes('.')) {
|
|
3160
3187
|
return getElementPropertyValue(target, context);
|
|
@@ -3168,14 +3195,17 @@ function getCurrentNumericValue(target, property, scope, context) {
|
|
|
3168
3195
|
else if (target === 'you' && context.you) {
|
|
3169
3196
|
return convertToNumber(context.you.value || 0);
|
|
3170
3197
|
}
|
|
3171
|
-
|
|
3172
|
-
return convertToNumber(value);
|
|
3198
|
+
return counterValue(getVariableValue(target, context));
|
|
3173
3199
|
}
|
|
3174
|
-
return
|
|
3200
|
+
return counterValue(target);
|
|
3175
3201
|
}
|
|
3176
3202
|
function setTargetValue(target, property, scope, newValue, context) {
|
|
3177
3203
|
if (isHTMLElement$2(target)) {
|
|
3178
3204
|
const element = target;
|
|
3205
|
+
if (property?.startsWith('@')) {
|
|
3206
|
+
element.setAttribute(property.slice(1), String(newValue));
|
|
3207
|
+
return;
|
|
3208
|
+
}
|
|
3179
3209
|
if (property) {
|
|
3180
3210
|
if (property.startsWith('data-') ||
|
|
3181
3211
|
['id', 'class', 'title', 'alt', 'src', 'href'].includes(property)) {
|
|
@@ -3195,6 +3225,10 @@ function setTargetValue(target, property, scope, newValue, context) {
|
|
|
3195
3225
|
}
|
|
3196
3226
|
return;
|
|
3197
3227
|
}
|
|
3228
|
+
if (property && isObjectOwner(target)) {
|
|
3229
|
+
target[property] = newValue;
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3198
3232
|
if (typeof target === 'string') {
|
|
3199
3233
|
if (scope === 'element') {
|
|
3200
3234
|
setVariableValue(target, newValue, context, 'element');
|
|
@@ -3969,6 +4003,39 @@ function makeTypeCheckHandler(negated) {
|
|
|
3969
4003
|
};
|
|
3970
4004
|
};
|
|
3971
4005
|
}
|
|
4006
|
+
const OF_OPERAND_BP = 70;
|
|
4007
|
+
function parseOfOperand(ctx, minBp = OF_OPERAND_BP) {
|
|
4008
|
+
let right = ctx.parseExpr(minBp);
|
|
4009
|
+
if (ctx.peek()?.value === 'in') {
|
|
4010
|
+
const inToken = ctx.advance();
|
|
4011
|
+
const scope = ctx.parseExpr(minBp);
|
|
4012
|
+
right = {
|
|
4013
|
+
type: 'binaryExpression',
|
|
4014
|
+
operator: 'in',
|
|
4015
|
+
left: right,
|
|
4016
|
+
right: scope,
|
|
4017
|
+
start: right.start,
|
|
4018
|
+
end: scope.end ?? inToken.end,
|
|
4019
|
+
line: right.line ?? inToken.line,
|
|
4020
|
+
column: right.column ?? inToken.column,
|
|
4021
|
+
};
|
|
4022
|
+
}
|
|
4023
|
+
return right;
|
|
4024
|
+
}
|
|
4025
|
+
const THE_OF_TARGET_BP = OF_OPERAND_BP + 1;
|
|
4026
|
+
function ofHandler(left, token, ctx) {
|
|
4027
|
+
const right = parseOfOperand(ctx);
|
|
4028
|
+
return {
|
|
4029
|
+
type: 'binaryExpression',
|
|
4030
|
+
operator: token.value,
|
|
4031
|
+
left,
|
|
4032
|
+
right,
|
|
4033
|
+
start: left.start,
|
|
4034
|
+
end: right.end ?? token.end,
|
|
4035
|
+
line: left.line ?? token.line,
|
|
4036
|
+
column: left.column ?? token.column,
|
|
4037
|
+
};
|
|
4038
|
+
}
|
|
3972
4039
|
const PARSER_COMPARISON_FRAGMENT = new Map([
|
|
3973
4040
|
['===', leftAssoc(30)],
|
|
3974
4041
|
['!==', leftAssoc(30)],
|
|
@@ -4013,7 +4080,7 @@ const PARSER_COMPARISON_FRAGMENT = new Map([
|
|
|
4013
4080
|
['is greater than or equal to', leftAssoc(30)],
|
|
4014
4081
|
['is less than or equal to', leftAssoc(30)],
|
|
4015
4082
|
['in', leftAssoc(30)],
|
|
4016
|
-
['of',
|
|
4083
|
+
['of', { infix: { bp: [90, OF_OPERAND_BP], handler: ofHandler } }],
|
|
4017
4084
|
['really', leftAssoc(30)],
|
|
4018
4085
|
[
|
|
4019
4086
|
'exists',
|
|
@@ -4104,6 +4171,89 @@ function getRegisteredNodeWriter(type) {
|
|
|
4104
4171
|
return NODE_WRITERS.get(type);
|
|
4105
4172
|
}
|
|
4106
4173
|
|
|
4174
|
+
function beepValues(me, values) {
|
|
4175
|
+
const outputs = values.map(describeBeepValue);
|
|
4176
|
+
const shown = outputs.filter(output => announce(me, output.value));
|
|
4177
|
+
if (shown.length === 0)
|
|
4178
|
+
return outputs;
|
|
4179
|
+
console.group('\ud83d\udd14 beep! Debug Output');
|
|
4180
|
+
for (const output of shown) {
|
|
4181
|
+
console.log(`Value:`, output.value);
|
|
4182
|
+
console.log(`Type:`, output.type);
|
|
4183
|
+
console.log(`Representation:`, output.representation);
|
|
4184
|
+
console.log('---');
|
|
4185
|
+
}
|
|
4186
|
+
console.groupEnd();
|
|
4187
|
+
return outputs;
|
|
4188
|
+
}
|
|
4189
|
+
function announce(me, value) {
|
|
4190
|
+
const target = me;
|
|
4191
|
+
if (typeof CustomEvent !== 'function' || typeof target?.dispatchEvent !== 'function')
|
|
4192
|
+
return true;
|
|
4193
|
+
return target.dispatchEvent(new CustomEvent('hyperscript:beep', {
|
|
4194
|
+
bubbles: true,
|
|
4195
|
+
cancelable: true,
|
|
4196
|
+
detail: { element: me, value },
|
|
4197
|
+
}));
|
|
4198
|
+
}
|
|
4199
|
+
function describeBeepValue(value) {
|
|
4200
|
+
return { value, type: typeOf(value), representation: representationOf(value) };
|
|
4201
|
+
}
|
|
4202
|
+
function typeOf(value) {
|
|
4203
|
+
if (value === null)
|
|
4204
|
+
return 'null';
|
|
4205
|
+
if (value === undefined)
|
|
4206
|
+
return 'undefined';
|
|
4207
|
+
if (Array.isArray(value))
|
|
4208
|
+
return 'array';
|
|
4209
|
+
if (isHTMLElement$2(value))
|
|
4210
|
+
return 'HTMLElement';
|
|
4211
|
+
if (typeof Element !== 'undefined' && value instanceof Element)
|
|
4212
|
+
return 'Element';
|
|
4213
|
+
if (typeof Node !== 'undefined' && value instanceof Node)
|
|
4214
|
+
return 'Node';
|
|
4215
|
+
if (value instanceof Error)
|
|
4216
|
+
return 'Error';
|
|
4217
|
+
if (value instanceof Date)
|
|
4218
|
+
return 'Date';
|
|
4219
|
+
if (value instanceof RegExp)
|
|
4220
|
+
return 'RegExp';
|
|
4221
|
+
return typeof value;
|
|
4222
|
+
}
|
|
4223
|
+
function representationOf(value) {
|
|
4224
|
+
if (value === null)
|
|
4225
|
+
return 'null';
|
|
4226
|
+
if (value === undefined)
|
|
4227
|
+
return 'undefined';
|
|
4228
|
+
if (Array.isArray(value)) {
|
|
4229
|
+
return `Array(${value.length}) [${value
|
|
4230
|
+
.slice(0, 3)
|
|
4231
|
+
.map(v => representationOf(v))
|
|
4232
|
+
.join(', ')}${value.length > 3 ? '...' : ''}]`;
|
|
4233
|
+
}
|
|
4234
|
+
if (isHTMLElement$2(value)) {
|
|
4235
|
+
const el = value;
|
|
4236
|
+
const tag = el.tagName.toLowerCase();
|
|
4237
|
+
const id = el.id ? `#${el.id}` : '';
|
|
4238
|
+
const classes = el.className ? `.${el.className.split(' ').join('.')}` : '';
|
|
4239
|
+
return `<${tag}${id}${classes}/>`;
|
|
4240
|
+
}
|
|
4241
|
+
if (value instanceof Error)
|
|
4242
|
+
return `Error: ${value.message}`;
|
|
4243
|
+
if (typeof value === 'string')
|
|
4244
|
+
return value.length > 50 ? `"${value.substring(0, 47)}..."` : `"${value}"`;
|
|
4245
|
+
if (typeof value === 'object') {
|
|
4246
|
+
try {
|
|
4247
|
+
const keys = Object.keys(value);
|
|
4248
|
+
return `Object {${keys.slice(0, 3).join(', ')}${keys.length > 3 ? '...' : ''}}`;
|
|
4249
|
+
}
|
|
4250
|
+
catch {
|
|
4251
|
+
return '[Object]';
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
return String(value);
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4107
4257
|
const NUMBER_WORDS = {
|
|
4108
4258
|
1: 'one',
|
|
4109
4259
|
2: 'two',
|
|
@@ -4705,14 +4855,15 @@ const closestExpression = {
|
|
|
4705
4855
|
if (typeof selector !== 'string') {
|
|
4706
4856
|
throw new Error('closest requires a string selector');
|
|
4707
4857
|
}
|
|
4708
|
-
|
|
4858
|
+
const start = args.length > 1 ? args[1] : context.me;
|
|
4859
|
+
if (!(start instanceof Element)) {
|
|
4709
4860
|
return null;
|
|
4710
4861
|
}
|
|
4711
|
-
return
|
|
4862
|
+
return start.closest(selector);
|
|
4712
4863
|
},
|
|
4713
4864
|
validate(args) {
|
|
4714
|
-
if (args.length !== 1) {
|
|
4715
|
-
return 'closest requires
|
|
4865
|
+
if (args.length !== 1 && args.length !== 2) {
|
|
4866
|
+
return 'closest requires a selector and, optionally, the element to start from';
|
|
4716
4867
|
}
|
|
4717
4868
|
const arg = args[0];
|
|
4718
4869
|
if (typeof arg === 'string')
|
|
@@ -7098,7 +7249,7 @@ const isEmptyExpression = {
|
|
|
7098
7249
|
else if (value instanceof Node || value instanceof Element)
|
|
7099
7250
|
result = false;
|
|
7100
7251
|
else if (isObject(value))
|
|
7101
|
-
result =
|
|
7252
|
+
result = value.length === 0;
|
|
7102
7253
|
else
|
|
7103
7254
|
result = false;
|
|
7104
7255
|
return result;
|
|
@@ -8175,6 +8326,48 @@ function parseMaybeNamedArgument(ctx) {
|
|
|
8175
8326
|
const value = ctx.parseExpression();
|
|
8176
8327
|
return name !== undefined ? { name, value } : { value };
|
|
8177
8328
|
}
|
|
8329
|
+
function isNakedNamedArgStart(ctx) {
|
|
8330
|
+
if (ctx.check('{'))
|
|
8331
|
+
return false;
|
|
8332
|
+
if (!ctx.checkIdentifierLike())
|
|
8333
|
+
return false;
|
|
8334
|
+
const next = ctx.peekAt(1);
|
|
8335
|
+
return next !== null && next.value === ':';
|
|
8336
|
+
}
|
|
8337
|
+
function parseNakedNamedArgs(ctx, parseValue, command) {
|
|
8338
|
+
const properties = [];
|
|
8339
|
+
const startPos = ctx.getPosition();
|
|
8340
|
+
do {
|
|
8341
|
+
if (!ctx.checkIdentifierLike())
|
|
8342
|
+
break;
|
|
8343
|
+
const keyToken = ctx.advance();
|
|
8344
|
+
const key = {
|
|
8345
|
+
type: 'identifier',
|
|
8346
|
+
name: keyToken.value,
|
|
8347
|
+
start: keyToken.start,
|
|
8348
|
+
end: keyToken.end,
|
|
8349
|
+
line: keyToken.line,
|
|
8350
|
+
column: keyToken.column,
|
|
8351
|
+
};
|
|
8352
|
+
ctx.consume(':', `Expected ':' after property name in ${command} named arguments`);
|
|
8353
|
+
const value = parseValue();
|
|
8354
|
+
if (value) {
|
|
8355
|
+
properties.push({ key, value });
|
|
8356
|
+
}
|
|
8357
|
+
} while (ctx.match(',') && !ctx.isAtEnd());
|
|
8358
|
+
const endPos = ctx.getPosition();
|
|
8359
|
+
return {
|
|
8360
|
+
type: 'objectLiteral',
|
|
8361
|
+
properties,
|
|
8362
|
+
start: startPos.start,
|
|
8363
|
+
end: endPos.end,
|
|
8364
|
+
line: startPos.line,
|
|
8365
|
+
column: startPos.column,
|
|
8366
|
+
};
|
|
8367
|
+
}
|
|
8368
|
+
function isGluedBeepBang(beep, bang) {
|
|
8369
|
+
return beep?.value === 'beep' && bang?.value === '!' && bang.start === beep.end;
|
|
8370
|
+
}
|
|
8178
8371
|
|
|
8179
8372
|
class CommandNodeBuilder {
|
|
8180
8373
|
constructor(name) {
|
|
@@ -8376,6 +8569,8 @@ function parseTriggerCommand(ctx, identifierNode) {
|
|
|
8376
8569
|
const modifiers = {};
|
|
8377
8570
|
while (!isCommandBoundary(ctx)) {
|
|
8378
8571
|
if (ctx.check(KEYWORDS.ON) || ctx.check(KEYWORDS.TO)) {
|
|
8572
|
+
if (modifiers['on'])
|
|
8573
|
+
break;
|
|
8379
8574
|
ctx.advance();
|
|
8380
8575
|
const target = parseOneArgument(ctx, [KEYWORDS.WITH]);
|
|
8381
8576
|
if (target)
|
|
@@ -8516,6 +8711,9 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
8516
8711
|
ctx.advance();
|
|
8517
8712
|
loopType = KEYWORDS.FOREVER;
|
|
8518
8713
|
}
|
|
8714
|
+
else if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
|
|
8715
|
+
loopType = KEYWORDS.FOREVER;
|
|
8716
|
+
}
|
|
8519
8717
|
else {
|
|
8520
8718
|
times = ctx.parseExpression();
|
|
8521
8719
|
if (ctx.check(KEYWORDS.TIMES)) {
|
|
@@ -8558,10 +8756,12 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
8558
8756
|
loopType = result.terminator;
|
|
8559
8757
|
ctx.advance();
|
|
8560
8758
|
condition = ctx.parseExpression();
|
|
8561
|
-
if (
|
|
8759
|
+
if (ctx.check('end')) {
|
|
8760
|
+
ctx.advance();
|
|
8761
|
+
}
|
|
8762
|
+
else if (!ctx.atEndOfInput()) {
|
|
8562
8763
|
throw new Error('Expected "end" to close repeat block');
|
|
8563
8764
|
}
|
|
8564
|
-
ctx.advance();
|
|
8565
8765
|
}
|
|
8566
8766
|
}
|
|
8567
8767
|
else {
|
|
@@ -8807,7 +9007,7 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
8807
9007
|
}));
|
|
8808
9008
|
}
|
|
8809
9009
|
}
|
|
8810
|
-
if (!consumedElseIf && !ctx.
|
|
9010
|
+
if (!consumedElseIf && !ctx.atEndOfInput()) {
|
|
8811
9011
|
ctx.consume(KEYWORDS.END, "Expected 'end' after if block");
|
|
8812
9012
|
}
|
|
8813
9013
|
}
|
|
@@ -8832,7 +9032,6 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
8832
9032
|
.build();
|
|
8833
9033
|
}
|
|
8834
9034
|
function parseForCommand(ctx, commandToken) {
|
|
8835
|
-
const args = [];
|
|
8836
9035
|
let variable = null;
|
|
8837
9036
|
let collection = null;
|
|
8838
9037
|
if (ctx.check(KEYWORDS.EACH)) {
|
|
@@ -8875,31 +9074,22 @@ function parseForCommand(ctx, commandToken) {
|
|
|
8875
9074
|
}
|
|
8876
9075
|
}
|
|
8877
9076
|
const commands = ctx.parseCommandListUntilEnd('for');
|
|
8878
|
-
|
|
8879
|
-
type: 'identifier',
|
|
8880
|
-
name: 'for',
|
|
8881
|
-
start: commandToken.start,
|
|
8882
|
-
end: commandToken.end,
|
|
8883
|
-
line: commandToken.line,
|
|
8884
|
-
column: commandToken.column,
|
|
8885
|
-
});
|
|
8886
|
-
const forPos = {
|
|
9077
|
+
const pos = {
|
|
8887
9078
|
start: commandToken.start,
|
|
8888
9079
|
end: commandToken.end,
|
|
8889
9080
|
line: commandToken.line,
|
|
8890
9081
|
column: commandToken.column,
|
|
8891
9082
|
};
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
}
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
.withArgs(...args)
|
|
9083
|
+
const modifiers = {
|
|
9084
|
+
loopType: toLegacyExpression(createStringLiteral(KEYWORDS.FOR, pos)),
|
|
9085
|
+
for: toLegacyExpression(createStringLiteral(variable, pos)),
|
|
9086
|
+
in: collection,
|
|
9087
|
+
};
|
|
9088
|
+
if (indexVariable)
|
|
9089
|
+
modifiers['index'] = toLegacyExpression(createStringLiteral(indexVariable, pos));
|
|
9090
|
+
return CommandNodeBuilder.from({ ...commandToken, value: 'repeat' })
|
|
9091
|
+
.withArgs(createBlock(commands, { ...pos, end: pos.end || 0 }))
|
|
9092
|
+
.withModifiers(modifiers)
|
|
8903
9093
|
.endingAt(ctx.getPosition())
|
|
8904
9094
|
.build();
|
|
8905
9095
|
}
|
|
@@ -8955,86 +9145,159 @@ function parseMeasureCommand(ctx, identifierNode) {
|
|
|
8955
9145
|
}
|
|
8956
9146
|
return builder.build();
|
|
8957
9147
|
}
|
|
8958
|
-
const
|
|
9148
|
+
const CONTEXT_REFS = new Set(['me', 'it', 'you', 'result']);
|
|
8959
9149
|
function parseTransitionCommand(ctx, commandToken) {
|
|
8960
|
-
const
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
const
|
|
8965
|
-
const
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
if (
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
target = parsed.object;
|
|
8976
|
-
property = {
|
|
8977
|
-
type: 'string',
|
|
8978
|
-
value: parsed.property.name,
|
|
8979
|
-
start: leadToken.start || 0,
|
|
8980
|
-
end: ctx.getPosition().end,
|
|
8981
|
-
line: leadToken.line,
|
|
8982
|
-
column: leadToken.column,
|
|
8983
|
-
};
|
|
9150
|
+
const pairs = [];
|
|
9151
|
+
do {
|
|
9152
|
+
pairs.push(parseTransitionPair(ctx));
|
|
9153
|
+
} while (startsAnotherPair(ctx));
|
|
9154
|
+
const [first, ...rest] = pairs;
|
|
9155
|
+
const args = first.owner ? [first.owner, first.property] : [first.property];
|
|
9156
|
+
const modifiers = { to: first.to };
|
|
9157
|
+
if (first.from)
|
|
9158
|
+
modifiers['from'] = first.from;
|
|
9159
|
+
if (rest.length > 0)
|
|
9160
|
+
modifiers['pairs'] = pairsNode(rest);
|
|
9161
|
+
for (let i = 0; i < 3 && !ctx.isAtEnd(); i++) {
|
|
9162
|
+
if (ctx.check('over') && !modifiers['over']) {
|
|
9163
|
+
ctx.advance();
|
|
9164
|
+
modifiers['over'] = ctx.parseExpression();
|
|
8984
9165
|
}
|
|
8985
|
-
else {
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
ctx.advance();
|
|
9166
|
+
else if (ctx.check('using') && !modifiers['using']) {
|
|
9167
|
+
ctx.advance();
|
|
9168
|
+
modifiers['using'] = ctx.parseExpression();
|
|
8989
9169
|
}
|
|
8990
|
-
|
|
8991
|
-
const firstToken = ctx.peek();
|
|
8992
|
-
if (!property && (isIdentifierLike(firstToken) || firstToken.value === '*')) {
|
|
8993
|
-
let propertyValue = '';
|
|
8994
|
-
if (ctx.check('*')) {
|
|
8995
|
-
propertyValue = '*';
|
|
9170
|
+
else if (ctx.check(KEYWORDS.WITH) && !modifiers['with']) {
|
|
8996
9171
|
ctx.advance();
|
|
9172
|
+
modifiers['with'] = ctx.parsePrimary();
|
|
8997
9173
|
}
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
propertyValue += hyphenatedName;
|
|
9001
|
-
property = {
|
|
9002
|
-
type: 'string',
|
|
9003
|
-
value: propertyValue,
|
|
9004
|
-
start: firstToken.start || 0,
|
|
9005
|
-
end: ctx.getPosition().end,
|
|
9006
|
-
line: firstToken.line,
|
|
9007
|
-
column: firstToken.column,
|
|
9008
|
-
};
|
|
9174
|
+
else {
|
|
9175
|
+
break;
|
|
9009
9176
|
}
|
|
9010
9177
|
}
|
|
9011
|
-
|
|
9012
|
-
|
|
9178
|
+
return CommandNodeBuilder.from(commandToken)
|
|
9179
|
+
.withArgs(...args)
|
|
9180
|
+
.withModifiers(modifiers)
|
|
9181
|
+
.endingAt(ctx.getPosition())
|
|
9182
|
+
.build();
|
|
9183
|
+
}
|
|
9184
|
+
function parseTransitionPair(ctx) {
|
|
9185
|
+
const { owner, property } = parseTransitionProperty(ctx);
|
|
9186
|
+
let from = null;
|
|
9187
|
+
if (ctx.check('from')) {
|
|
9188
|
+
ctx.advance();
|
|
9189
|
+
from = ctx.parseExpression();
|
|
9013
9190
|
}
|
|
9014
|
-
if (target)
|
|
9015
|
-
args.push(target);
|
|
9016
|
-
args.push(property);
|
|
9017
9191
|
if (!ctx.check(KEYWORDS.TO)) {
|
|
9018
9192
|
throw new Error('Expected "to" keyword after property in transition command');
|
|
9019
9193
|
}
|
|
9020
9194
|
ctx.advance();
|
|
9021
|
-
const
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9195
|
+
const to = ctx.parseExpression();
|
|
9196
|
+
return { owner, property, from, to };
|
|
9197
|
+
}
|
|
9198
|
+
function parseTransitionProperty(ctx) {
|
|
9199
|
+
const lead = ctx.peek();
|
|
9200
|
+
if (!lead || isKeyword(lead, [KEYWORDS.TO, 'from'])) {
|
|
9201
|
+
throw new Error('Transition command requires a CSS property');
|
|
9027
9202
|
}
|
|
9028
|
-
|
|
9203
|
+
const expr = ctx.parseExpression();
|
|
9204
|
+
const split = splitStyleExpression(expr);
|
|
9205
|
+
if (split)
|
|
9206
|
+
return { owner: split.owner, property: propertyNode(split.name, lead, ctx) };
|
|
9207
|
+
let name = '';
|
|
9208
|
+
if (ctx.check('*')) {
|
|
9209
|
+
name = '*';
|
|
9029
9210
|
ctx.advance();
|
|
9030
|
-
const timingFunction = ctx.parsePrimary();
|
|
9031
|
-
modifiers['with'] = timingFunction;
|
|
9032
9211
|
}
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9212
|
+
const hyphenated = parseHyphenatedName(ctx);
|
|
9213
|
+
if (!hyphenated)
|
|
9214
|
+
throw new Error('Transition command requires a CSS property');
|
|
9215
|
+
return { owner: expr, property: propertyNode(name + hyphenated, lead, ctx) };
|
|
9216
|
+
}
|
|
9217
|
+
function splitStyleExpression(node) {
|
|
9218
|
+
const n = node;
|
|
9219
|
+
switch (n.type) {
|
|
9220
|
+
case 'selector':
|
|
9221
|
+
return typeof n.value === 'string' && n.value.startsWith('*')
|
|
9222
|
+
? { owner: null, name: n.value }
|
|
9223
|
+
: null;
|
|
9224
|
+
case 'identifier':
|
|
9225
|
+
return typeof n.name === 'string' && !CONTEXT_REFS.has(n.name)
|
|
9226
|
+
? { owner: null, name: n.name }
|
|
9227
|
+
: null;
|
|
9228
|
+
case 'possessiveExpression':
|
|
9229
|
+
case 'memberExpression':
|
|
9230
|
+
return !n.computed && n.object && typeof n.property?.name === 'string'
|
|
9231
|
+
? { owner: n.object, name: n.property.name }
|
|
9232
|
+
: null;
|
|
9233
|
+
case 'binaryExpression': {
|
|
9234
|
+
if (n.operator !== 'of' || !n.left || !n.right)
|
|
9235
|
+
return null;
|
|
9236
|
+
const inner = splitStyleExpression(n.left);
|
|
9237
|
+
return inner && !inner.owner ? { owner: n.right, name: inner.name } : null;
|
|
9238
|
+
}
|
|
9239
|
+
case 'propertyOfExpression':
|
|
9240
|
+
return n.target && typeof n.property?.name === 'string'
|
|
9241
|
+
? { owner: n.target, name: n.property.name }
|
|
9242
|
+
: null;
|
|
9243
|
+
default:
|
|
9244
|
+
return null;
|
|
9245
|
+
}
|
|
9246
|
+
}
|
|
9247
|
+
function propertyNode(name, lead, ctx) {
|
|
9248
|
+
return {
|
|
9249
|
+
type: 'string',
|
|
9250
|
+
value: name,
|
|
9251
|
+
start: lead.start || 0,
|
|
9252
|
+
end: ctx.getPosition().end,
|
|
9253
|
+
line: lead.line,
|
|
9254
|
+
column: lead.column,
|
|
9255
|
+
};
|
|
9256
|
+
}
|
|
9257
|
+
function startsAnotherPair(ctx) {
|
|
9258
|
+
if (ctx.isAtEnd() || isComment(ctx.peek()))
|
|
9259
|
+
return false;
|
|
9260
|
+
if (isKeyword(ctx.peek(), ['over', 'using', KEYWORDS.WITH]))
|
|
9261
|
+
return false;
|
|
9262
|
+
return !isCommandBoundary(ctx, ['catch', 'finally', 'on']);
|
|
9263
|
+
}
|
|
9264
|
+
function pairsNode(pairs) {
|
|
9265
|
+
const field = (name, value) => ({
|
|
9266
|
+
key: {
|
|
9267
|
+
type: 'identifier',
|
|
9268
|
+
name,
|
|
9269
|
+
start: value.start,
|
|
9270
|
+
end: value.end,
|
|
9271
|
+
line: value.line,
|
|
9272
|
+
column: value.column,
|
|
9273
|
+
},
|
|
9274
|
+
value,
|
|
9275
|
+
});
|
|
9276
|
+
const elements = pairs.map(pair => {
|
|
9277
|
+
const properties = [field('property', pair.property), field('to', pair.to)];
|
|
9278
|
+
if (pair.owner)
|
|
9279
|
+
properties.push(field('owner', pair.owner));
|
|
9280
|
+
if (pair.from)
|
|
9281
|
+
properties.push(field('from', pair.from));
|
|
9282
|
+
return {
|
|
9283
|
+
type: 'objectLiteral',
|
|
9284
|
+
properties,
|
|
9285
|
+
start: (pair.owner ?? pair.property).start,
|
|
9286
|
+
end: pair.to.end,
|
|
9287
|
+
line: (pair.owner ?? pair.property).line,
|
|
9288
|
+
column: (pair.owner ?? pair.property).column,
|
|
9289
|
+
};
|
|
9290
|
+
});
|
|
9291
|
+
const firstEl = elements[0];
|
|
9292
|
+
const lastEl = elements[elements.length - 1];
|
|
9293
|
+
return {
|
|
9294
|
+
type: 'arrayLiteral',
|
|
9295
|
+
elements,
|
|
9296
|
+
start: firstEl.start,
|
|
9297
|
+
end: lastEl.end,
|
|
9298
|
+
line: firstEl.line,
|
|
9299
|
+
column: firstEl.column,
|
|
9300
|
+
};
|
|
9038
9301
|
}
|
|
9039
9302
|
function parseStartCommand(ctx, identifierNode) {
|
|
9040
9303
|
if (!ctx.match('view')) {
|
|
@@ -9331,11 +9594,17 @@ function parseSwapCommand(ctx, identifierNode) {
|
|
|
9331
9594
|
const targetExpr = isDelete ? ctx.parseExpression() : parseOneArgument(ctx, [KEYWORDS.WITH]);
|
|
9332
9595
|
if (targetExpr)
|
|
9333
9596
|
args.push(targetExpr);
|
|
9334
|
-
|
|
9597
|
+
const isMorph = identifierNode.name === 'morph';
|
|
9598
|
+
if (!isDelete &&
|
|
9599
|
+
(consumeOptionalKeyword(ctx, KEYWORDS.WITH) ||
|
|
9600
|
+
(isMorph && consumeOptionalKeyword(ctx, KEYWORDS.TO)))) {
|
|
9335
9601
|
const contentExpr = parseOneArgument(ctx, ['using']);
|
|
9336
9602
|
if (contentExpr)
|
|
9337
9603
|
modifiers['with'] = contentExpr;
|
|
9338
9604
|
}
|
|
9605
|
+
if (isMorph && modifiers['with'] === undefined) {
|
|
9606
|
+
ctx.addError("Expected 'to' and the content to morph into");
|
|
9607
|
+
}
|
|
9339
9608
|
return CommandNodeBuilder.fromIdentifier(identifierNode)
|
|
9340
9609
|
.withArgs(...args)
|
|
9341
9610
|
.withModifiers({ ...modifiers, ...parseViewTransitionTail(ctx) })
|
|
@@ -10096,6 +10365,8 @@ function atArgumentBoundary(ctx, grammar) {
|
|
|
10096
10365
|
const next = ctx.peek();
|
|
10097
10366
|
if (ctx.checkIsCommand() && ctx.peekAt(1)?.value === '(')
|
|
10098
10367
|
return false;
|
|
10368
|
+
if (isGluedBeepBang(next, ctx.peekAt(1)))
|
|
10369
|
+
return false;
|
|
10099
10370
|
if (isCommandBoundary(ctx, ['catch', 'finally', 'on']))
|
|
10100
10371
|
return true;
|
|
10101
10372
|
return isKeyword(next, [...grammar.markers]);
|
|
@@ -10127,10 +10398,13 @@ function parseDeclaredCommand(ctx, commandToken, name, grammar) {
|
|
|
10127
10398
|
}
|
|
10128
10399
|
}
|
|
10129
10400
|
const commaList = new Set(grammar.commaList ?? []);
|
|
10401
|
+
const namedArgs = new Set(grammar.namedArgs ?? []);
|
|
10130
10402
|
while (!ctx.isAtEnd() && isKeyword(ctx.peek(), [...grammar.markers])) {
|
|
10131
10403
|
const keyword = ctx.advance().value;
|
|
10132
10404
|
const key = ctx.resolveKeyword(keyword).toLowerCase();
|
|
10133
|
-
let value =
|
|
10405
|
+
let value = namedArgs.has(key) && isNakedNamedArgStart(ctx)
|
|
10406
|
+
? parseNakedNamedArgs(ctx, () => ctx.parseExpression(), name)
|
|
10407
|
+
: ctx.parseExpression();
|
|
10134
10408
|
if (value && commaList.has(key) && ctx.check(',')) {
|
|
10135
10409
|
const elements = [value];
|
|
10136
10410
|
while (ctx.match(',')) {
|
|
@@ -10295,8 +10569,8 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10295
10569
|
}
|
|
10296
10570
|
if (ctx.check('with') && !modifiers['with']) {
|
|
10297
10571
|
ctx.advance();
|
|
10298
|
-
if (
|
|
10299
|
-
modifiers['with'] =
|
|
10572
|
+
if (isNakedNamedArgStart(ctx)) {
|
|
10573
|
+
modifiers['with'] = parseNakedNamedArgs(ctx, () => ctx.parsePrimary(), 'fetch');
|
|
10300
10574
|
}
|
|
10301
10575
|
else {
|
|
10302
10576
|
modifiers['with'] = ctx.parsePrimary();
|
|
@@ -10331,45 +10605,6 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10331
10605
|
}
|
|
10332
10606
|
return builder.build();
|
|
10333
10607
|
}
|
|
10334
|
-
function isFetchNakedNamedArgStart(ctx) {
|
|
10335
|
-
if (ctx.check('{'))
|
|
10336
|
-
return false;
|
|
10337
|
-
if (!ctx.checkIdentifierLike())
|
|
10338
|
-
return false;
|
|
10339
|
-
const next = ctx.peekAt(1);
|
|
10340
|
-
return next !== null && next.value === ':';
|
|
10341
|
-
}
|
|
10342
|
-
function parseFetchNakedNamedArgs(ctx) {
|
|
10343
|
-
const properties = [];
|
|
10344
|
-
const startPos = ctx.getPosition();
|
|
10345
|
-
do {
|
|
10346
|
-
if (!ctx.checkIdentifierLike())
|
|
10347
|
-
break;
|
|
10348
|
-
const keyToken = ctx.advance();
|
|
10349
|
-
const key = {
|
|
10350
|
-
type: 'identifier',
|
|
10351
|
-
name: keyToken.value,
|
|
10352
|
-
start: keyToken.start,
|
|
10353
|
-
end: keyToken.end,
|
|
10354
|
-
line: keyToken.line,
|
|
10355
|
-
column: keyToken.column,
|
|
10356
|
-
};
|
|
10357
|
-
ctx.consume(':', "Expected ':' after property name in fetch named arguments");
|
|
10358
|
-
const value = ctx.parsePrimary();
|
|
10359
|
-
if (value) {
|
|
10360
|
-
properties.push({ key, value });
|
|
10361
|
-
}
|
|
10362
|
-
} while (ctx.match(',') && !ctx.isAtEnd());
|
|
10363
|
-
const endPos = ctx.getPosition();
|
|
10364
|
-
return {
|
|
10365
|
-
type: 'objectLiteral',
|
|
10366
|
-
properties,
|
|
10367
|
-
start: startPos.start,
|
|
10368
|
-
end: endPos.end,
|
|
10369
|
-
line: startPos.line,
|
|
10370
|
-
column: startPos.column,
|
|
10371
|
-
};
|
|
10372
|
-
}
|
|
10373
10608
|
function findJsEndBoundary(ctx, startPos) {
|
|
10374
10609
|
const input = ctx.getInputSlice(startPos);
|
|
10375
10610
|
if (!input) {
|
|
@@ -10489,6 +10724,7 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10489
10724
|
const commands = [];
|
|
10490
10725
|
while (!ctx.isAtEnd()) {
|
|
10491
10726
|
if (ctx.checkIsCommand()) {
|
|
10727
|
+
const word = ctx.peek().value;
|
|
10492
10728
|
try {
|
|
10493
10729
|
ctx.advance();
|
|
10494
10730
|
const cmd = ctx.parseCommand();
|
|
@@ -10499,7 +10735,8 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10499
10735
|
break;
|
|
10500
10736
|
}
|
|
10501
10737
|
}
|
|
10502
|
-
catch {
|
|
10738
|
+
catch (error) {
|
|
10739
|
+
ctx.addError(`'${word}' in a tell body failed to parse: ${error instanceof Error ? error.message : String(error)}`);
|
|
10503
10740
|
break;
|
|
10504
10741
|
}
|
|
10505
10742
|
if (ctx.match(KEYWORDS.AND) || ctx.match(KEYWORDS.THEN)) {
|
|
@@ -10648,7 +10885,6 @@ const ONE_EXPR = (syntax) => ({
|
|
|
10648
10885
|
markers: [],
|
|
10649
10886
|
syntax,
|
|
10650
10887
|
});
|
|
10651
|
-
const BEEP = ONE_EXPR('beep! [<expression>, \u2026]');
|
|
10652
10888
|
const COMMAND_GRAMMAR = {
|
|
10653
10889
|
append: { positional: 'expression', markers: ['to'], syntax: 'append <value> [to <target>]' },
|
|
10654
10890
|
prepend: { positional: 'expression', markers: ['to'], syntax: 'prepend <value> [to <target>]' },
|
|
@@ -10659,8 +10895,7 @@ const COMMAND_GRAMMAR = {
|
|
|
10659
10895
|
syntax: 'make (a|an) <type> [from <args>] [called <name>]',
|
|
10660
10896
|
},
|
|
10661
10897
|
throw: { positional: 'primary', markers: [], syntax: 'throw <error>' },
|
|
10662
|
-
'beep!'
|
|
10663
|
-
beep: BEEP,
|
|
10898
|
+
beep: ONE_EXPR('beep! [<expression>, \u2026]'),
|
|
10664
10899
|
blur: ONE_EXPR('blur [<target>]'),
|
|
10665
10900
|
break: NONE,
|
|
10666
10901
|
breakpoint: NONE,
|
|
@@ -10684,7 +10919,8 @@ const COMMAND_GRAMMAR = {
|
|
|
10684
10919
|
render: {
|
|
10685
10920
|
positional: 'expression',
|
|
10686
10921
|
markers: ['with'],
|
|
10687
|
-
|
|
10922
|
+
namedArgs: ['with'],
|
|
10923
|
+
syntax: 'render <template> [with <name>: <value>, \u2026]',
|
|
10688
10924
|
},
|
|
10689
10925
|
reset: ONE_EXPR('reset [<form>]'),
|
|
10690
10926
|
return: ONE_EXPR('return [<value>]'),
|
|
@@ -11039,7 +11275,10 @@ class Parser {
|
|
|
11039
11275
|
const firstToken = this.peek();
|
|
11040
11276
|
const prefixEntry = Parser.PRATT_TABLE.get(firstToken.value);
|
|
11041
11277
|
let left;
|
|
11042
|
-
if (
|
|
11278
|
+
if (isGluedBeepBang(firstToken, this.tokens[this.current + 1])) {
|
|
11279
|
+
left = this.parseBeepExpression();
|
|
11280
|
+
}
|
|
11281
|
+
else if (prefixEntry?.prefix) {
|
|
11043
11282
|
const token = this.advance();
|
|
11044
11283
|
if (this.isAtEnd()) {
|
|
11045
11284
|
this.addError(`Expected expression after '${token.value}' operator`);
|
|
@@ -11059,6 +11298,9 @@ class Parser {
|
|
|
11059
11298
|
continue;
|
|
11060
11299
|
}
|
|
11061
11300
|
}
|
|
11301
|
+
if (nextToken.value === '*' && this.isSpacedStyleRef(this.current)) {
|
|
11302
|
+
break;
|
|
11303
|
+
}
|
|
11062
11304
|
const infixEntry = Parser.PRATT_TABLE.get(nextToken.value);
|
|
11063
11305
|
if (!infixEntry?.infix) {
|
|
11064
11306
|
if (STOP_TOKENS.has(nextToken.value) || STOP_DELIMITERS.has(nextToken.value)) {
|
|
@@ -11120,6 +11362,35 @@ class Parser {
|
|
|
11120
11362
|
this.prattCache.set(cacheKey, { node: left, endPos: this.current });
|
|
11121
11363
|
return left;
|
|
11122
11364
|
}
|
|
11365
|
+
parseBeepExpression() {
|
|
11366
|
+
const beepToken = this.advance();
|
|
11367
|
+
this.advance();
|
|
11368
|
+
if (this.isAtEnd()) {
|
|
11369
|
+
this.addError("Expected expression after 'beep!'");
|
|
11370
|
+
return this.createErrorNode();
|
|
11371
|
+
}
|
|
11372
|
+
const operand = this.parseExpressionPratt(Parser.BEEP_OPERAND_BP);
|
|
11373
|
+
return {
|
|
11374
|
+
type: 'unaryExpression',
|
|
11375
|
+
operator: 'beep!',
|
|
11376
|
+
operand,
|
|
11377
|
+
argument: operand,
|
|
11378
|
+
prefix: true,
|
|
11379
|
+
start: beepToken.start,
|
|
11380
|
+
end: this.previous().end,
|
|
11381
|
+
line: beepToken.line,
|
|
11382
|
+
column: beepToken.column,
|
|
11383
|
+
};
|
|
11384
|
+
}
|
|
11385
|
+
isStyleRefStar(i) {
|
|
11386
|
+
const star = this.tokens[i];
|
|
11387
|
+
const name = this.tokens[i + 1];
|
|
11388
|
+
return star?.value === '*' && !!name && name.start === star.end && isIdentifierLike(name);
|
|
11389
|
+
}
|
|
11390
|
+
isSpacedStyleRef(i) {
|
|
11391
|
+
const prev = this.tokens[i - 1];
|
|
11392
|
+
return this.isStyleRefStar(i) && !!prev && prev.end < this.tokens[i].start;
|
|
11393
|
+
}
|
|
11123
11394
|
tryParseStringPostfix(left, nextToken) {
|
|
11124
11395
|
const v = nextToken.value;
|
|
11125
11396
|
let unit = null;
|
|
@@ -11322,6 +11593,10 @@ class Parser {
|
|
|
11322
11593
|
const isStop = () => this.check('end') || extraStops.some(s => this.check(s));
|
|
11323
11594
|
debug.parse('\ud83d\udd04 parseCommandListUntilTerminator: Starting (extraStops:', extraStops.join(','), ')');
|
|
11324
11595
|
while (!this.isAtEnd() && !isStop()) {
|
|
11596
|
+
if (this.checkComment()) {
|
|
11597
|
+
this.advance();
|
|
11598
|
+
continue;
|
|
11599
|
+
}
|
|
11325
11600
|
debug.parse('\ud83d\udccd Loop iteration, current token:', this.peek().value, 'kind:', this.peek().kind);
|
|
11326
11601
|
let parsedCommand = false;
|
|
11327
11602
|
const isCommandToken = this.checkIsCommand();
|
|
@@ -11405,7 +11680,7 @@ class Parser {
|
|
|
11405
11680
|
debug.parse('\u2705 Found "end", consuming it');
|
|
11406
11681
|
this.advance();
|
|
11407
11682
|
}
|
|
11408
|
-
else {
|
|
11683
|
+
else if (!this.atEndOfInput()) {
|
|
11409
11684
|
debug.parse('\u274c ERROR: Expected "end" but got:', this.peek().value, 'at position:', this.peek().start);
|
|
11410
11685
|
throw new Error(`Expected "end" to close ${construct} block`);
|
|
11411
11686
|
}
|
|
@@ -11418,7 +11693,7 @@ class Parser {
|
|
|
11418
11693
|
if (this.check('end')) {
|
|
11419
11694
|
this.advance();
|
|
11420
11695
|
}
|
|
11421
|
-
else {
|
|
11696
|
+
else if (!this.atEndOfInput()) {
|
|
11422
11697
|
throw new Error('Expected "end" to close repeat block');
|
|
11423
11698
|
}
|
|
11424
11699
|
}
|
|
@@ -11434,7 +11709,10 @@ class Parser {
|
|
|
11434
11709
|
this.advance();
|
|
11435
11710
|
}
|
|
11436
11711
|
else if (terminator === '') {
|
|
11437
|
-
|
|
11712
|
+
if (!this.atEndOfInput()) {
|
|
11713
|
+
throw new Error('Expected "end", "else", "until", or "while" to close repeat block');
|
|
11714
|
+
}
|
|
11715
|
+
return { commands, terminator: 'end' };
|
|
11438
11716
|
}
|
|
11439
11717
|
return { commands, terminator };
|
|
11440
11718
|
}
|
|
@@ -12018,7 +12296,9 @@ class Parser {
|
|
|
12018
12296
|
parseTopLevelInitBlock() {
|
|
12019
12297
|
const pos = this.getPosition();
|
|
12020
12298
|
const initCommands = this.parseCommandBlock(['end']);
|
|
12021
|
-
this.
|
|
12299
|
+
if (!this.match('end') && !this.atEndOfInput() && !this.checkFeatureStart()) {
|
|
12300
|
+
this.consume('end', "Expected 'end' after init block");
|
|
12301
|
+
}
|
|
12022
12302
|
return {
|
|
12023
12303
|
type: 'initBlock',
|
|
12024
12304
|
commands: initCommands,
|
|
@@ -12194,10 +12474,29 @@ class Parser {
|
|
|
12194
12474
|
...(sourceExpr.column !== undefined && { column: sourceExpr.column }),
|
|
12195
12475
|
};
|
|
12196
12476
|
}
|
|
12477
|
+
isArgumentListOnly(open) {
|
|
12478
|
+
let depth = 0;
|
|
12479
|
+
for (let i = open; i < this.tokens.length; i++) {
|
|
12480
|
+
const token = this.tokens[i];
|
|
12481
|
+
if (token.kind !== 'operator')
|
|
12482
|
+
continue;
|
|
12483
|
+
if (token.value === '(' || token.value === '[' || token.value === '{')
|
|
12484
|
+
depth++;
|
|
12485
|
+
else if (token.value === ')' || token.value === ']' || token.value === '}') {
|
|
12486
|
+
if (--depth === 0)
|
|
12487
|
+
return i === open + 1;
|
|
12488
|
+
}
|
|
12489
|
+
else if (token.value === ',' && depth === 1)
|
|
12490
|
+
return true;
|
|
12491
|
+
}
|
|
12492
|
+
return false;
|
|
12493
|
+
}
|
|
12197
12494
|
tryParsePseudoCommand(callExpr, sourceExpr) {
|
|
12198
12495
|
const methodName = callExpr.callee.name;
|
|
12199
12496
|
const nextToken = this.peek();
|
|
12200
|
-
const
|
|
12497
|
+
const nextIsArticle = nextToken.value.toLowerCase() === 'the';
|
|
12498
|
+
const hasPseudoCommandPattern = nextIsArticle ||
|
|
12499
|
+
Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(nextToken.value.toLowerCase()) ||
|
|
12201
12500
|
(isIdentifier(nextToken) && !this.isCommand(nextToken.value)) ||
|
|
12202
12501
|
isContextVar(nextToken);
|
|
12203
12502
|
if (!hasPseudoCommandPattern) {
|
|
@@ -12223,7 +12522,10 @@ class Parser {
|
|
|
12223
12522
|
});
|
|
12224
12523
|
}
|
|
12225
12524
|
let preposition;
|
|
12226
|
-
if (
|
|
12525
|
+
if (nextIsArticle) {
|
|
12526
|
+
this.advance();
|
|
12527
|
+
}
|
|
12528
|
+
else if (Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(this.peek().value.toLowerCase())) {
|
|
12227
12529
|
preposition = this.advance().value.toLowerCase();
|
|
12228
12530
|
}
|
|
12229
12531
|
let targetExpr;
|
|
@@ -12387,10 +12689,22 @@ class Parser {
|
|
|
12387
12689
|
this.consume(']', "Expected ']' after event condition");
|
|
12388
12690
|
}
|
|
12389
12691
|
let target;
|
|
12692
|
+
let targetExpression;
|
|
12390
12693
|
if (this.match('from')) {
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12694
|
+
if (this.check('the'))
|
|
12695
|
+
this.advance();
|
|
12696
|
+
if (Parser.POSITIONAL_SOURCE_HEADS.has(this.peek().value.toLowerCase())) {
|
|
12697
|
+
const startIndex = this.current;
|
|
12698
|
+
targetExpression = this.parseExpression();
|
|
12699
|
+
target = this.tokens
|
|
12700
|
+
.slice(startIndex, this.current)
|
|
12701
|
+
.map(t => t.value)
|
|
12702
|
+
.join(' ');
|
|
12703
|
+
}
|
|
12704
|
+
else {
|
|
12705
|
+
target = this.advance().value;
|
|
12706
|
+
}
|
|
12707
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'from' target: ${target}`);
|
|
12394
12708
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
12395
12709
|
}
|
|
12396
12710
|
let attributeName;
|
|
@@ -12436,7 +12750,7 @@ class Parser {
|
|
|
12436
12750
|
const nextIsOpenParen = this.tokens[this.current + 1]?.value === '(';
|
|
12437
12751
|
const commandName = this.peek().value.toLowerCase();
|
|
12438
12752
|
const isSpecialBodyCommand = commandName === 'js' || commandName === 'tell';
|
|
12439
|
-
if (nextIsOpenParen && !isSpecialBodyCommand) {
|
|
12753
|
+
if (nextIsOpenParen && !isSpecialBodyCommand && this.isArgumentListOnly(this.current + 1)) {
|
|
12440
12754
|
let expr;
|
|
12441
12755
|
const savedError = this.error;
|
|
12442
12756
|
try {
|
|
@@ -12468,7 +12782,7 @@ class Parser {
|
|
|
12468
12782
|
}
|
|
12469
12783
|
}
|
|
12470
12784
|
}
|
|
12471
|
-
else if (this.checkIdentifier()) {
|
|
12785
|
+
else if (this.checkIdentifier() || this.checkEventNamedCall()) {
|
|
12472
12786
|
const token = this.peek();
|
|
12473
12787
|
if (this.isCommand(token.value)) {
|
|
12474
12788
|
const cmd = this.parseCommandWithErrorRecovery();
|
|
@@ -12577,6 +12891,7 @@ class Parser {
|
|
|
12577
12891
|
...(eventParams.length > 0 && { args: eventParams }),
|
|
12578
12892
|
...(condition && { condition: fromLegacyExpression(condition) }),
|
|
12579
12893
|
...(target && { target }),
|
|
12894
|
+
...(targetExpression && { targetExpression: fromLegacyExpression(targetExpression) }),
|
|
12580
12895
|
...(attributeName && { attributeName }),
|
|
12581
12896
|
...(watchTarget && { watchTarget: fromLegacyExpression(watchTarget) }),
|
|
12582
12897
|
...(customEventSource && { customEventSource }),
|
|
@@ -12832,10 +13147,9 @@ class Parser {
|
|
|
12832
13147
|
}
|
|
12833
13148
|
parseCommandCore() {
|
|
12834
13149
|
const commandToken = this.previous();
|
|
12835
|
-
|
|
13150
|
+
const commandName = commandToken.value;
|
|
12836
13151
|
if (commandName === 'beep' && this.check('!')) {
|
|
12837
13152
|
this.advance();
|
|
12838
|
-
commandName = 'beep!';
|
|
12839
13153
|
}
|
|
12840
13154
|
if (commandName === 'fetch') {
|
|
12841
13155
|
return parseFetchCommand(this.getContext(), commandToken);
|
|
@@ -12934,6 +13248,9 @@ class Parser {
|
|
|
12934
13248
|
args.push(this.parsePrimary());
|
|
12935
13249
|
}
|
|
12936
13250
|
const callNode = this.createCallExpression(createIdentifier(funcName, namePos), args);
|
|
13251
|
+
if (funcName === 'closest' && args.length > 0 && this.match('to')) {
|
|
13252
|
+
callNode.closestTo = this.parseExpression();
|
|
13253
|
+
}
|
|
12937
13254
|
if (funcName === 'next' || funcName === 'previous') {
|
|
12938
13255
|
const relativePositional = this.parseRelativePositionalModifiers();
|
|
12939
13256
|
if (relativePositional) {
|
|
@@ -12973,6 +13290,9 @@ class Parser {
|
|
|
12973
13290
|
}
|
|
12974
13291
|
parseTheXofY() {
|
|
12975
13292
|
const positionalKeywords = ['first', 'last', 'next', 'previous', 'random', 'closest'];
|
|
13293
|
+
if (this.isStyleRefStar(this.current)) {
|
|
13294
|
+
return this.parsePrimary();
|
|
13295
|
+
}
|
|
12976
13296
|
if (!this.checkIdentifier()) {
|
|
12977
13297
|
return this.createIdentifier('the');
|
|
12978
13298
|
}
|
|
@@ -12988,7 +13308,7 @@ class Parser {
|
|
|
12988
13308
|
return this.createIdentifier(propertyName);
|
|
12989
13309
|
}
|
|
12990
13310
|
this.advance();
|
|
12991
|
-
const target = this.
|
|
13311
|
+
const target = parseOfOperand(this.makePrattContext(), THE_OF_TARGET_BP);
|
|
12992
13312
|
return {
|
|
12993
13313
|
type: 'propertyOfExpression',
|
|
12994
13314
|
property: { type: 'identifier', name: propertyName },
|
|
@@ -13186,6 +13506,13 @@ class Parser {
|
|
|
13186
13506
|
checkLiteral() {
|
|
13187
13507
|
return this.checkPredicate(isLiteral);
|
|
13188
13508
|
}
|
|
13509
|
+
checkEventNamedCall() {
|
|
13510
|
+
if (this.isAtEnd() || !this.checkIdentifierLike() || this.checkIsCommand())
|
|
13511
|
+
return false;
|
|
13512
|
+
const token = this.peek();
|
|
13513
|
+
const next = this.tokens[this.current + 1];
|
|
13514
|
+
return next?.value === '(' && next.start === token.end;
|
|
13515
|
+
}
|
|
13189
13516
|
checkIdentifierLike() {
|
|
13190
13517
|
return this.checkPredicate(isIdentifierLike);
|
|
13191
13518
|
}
|
|
@@ -13294,6 +13621,22 @@ class Parser {
|
|
|
13294
13621
|
isAtEnd() {
|
|
13295
13622
|
return this.current >= this.tokens.length;
|
|
13296
13623
|
}
|
|
13624
|
+
atEndOfInput() {
|
|
13625
|
+
for (let i = this.current; i < this.tokens.length; i++) {
|
|
13626
|
+
if (!isComment(this.tokens[i]))
|
|
13627
|
+
return false;
|
|
13628
|
+
}
|
|
13629
|
+
return true;
|
|
13630
|
+
}
|
|
13631
|
+
checkFeatureStart() {
|
|
13632
|
+
if (this.isAtEnd())
|
|
13633
|
+
return false;
|
|
13634
|
+
const value = this.peek().value;
|
|
13635
|
+
return (value === 'init' ||
|
|
13636
|
+
value === 'on' ||
|
|
13637
|
+
value === 'def' ||
|
|
13638
|
+
getRegisteredFeature(value) !== undefined);
|
|
13639
|
+
}
|
|
13297
13640
|
peek() {
|
|
13298
13641
|
if (this.isAtEnd()) {
|
|
13299
13642
|
return { kind: 'unknown', value: '', start: 0, end: 0, line: 1, column: 1 };
|
|
@@ -13505,6 +13848,7 @@ class Parser {
|
|
|
13505
13848
|
match: this.match.bind(this),
|
|
13506
13849
|
matchOperator: this.matchOperator.bind(this),
|
|
13507
13850
|
isAtEnd: this.isAtEnd.bind(this),
|
|
13851
|
+
atEndOfInput: this.atEndOfInput.bind(this),
|
|
13508
13852
|
createIdentifier: this.createIdentifier.bind(this),
|
|
13509
13853
|
parseExpression: this.parseExpression.bind(this),
|
|
13510
13854
|
parsePrimary: this.parsePrimary.bind(this),
|
|
@@ -13555,7 +13899,15 @@ Parser.POSTFIX_UNARY_OPERATORS = new Set([
|
|
|
13555
13899
|
'ignoring case',
|
|
13556
13900
|
]);
|
|
13557
13901
|
Parser.PRATT_TABLE = PARSER_TABLE;
|
|
13902
|
+
Parser.BEEP_OPERAND_BP = 80;
|
|
13558
13903
|
Parser.PSEUDO_COMMAND_PREPOSITIONS = ['from', 'on', 'with', 'into', 'at', 'to'];
|
|
13904
|
+
Parser.POSITIONAL_SOURCE_HEADS = new Set([
|
|
13905
|
+
'closest',
|
|
13906
|
+
'next',
|
|
13907
|
+
'previous',
|
|
13908
|
+
'first',
|
|
13909
|
+
'last',
|
|
13910
|
+
]);
|
|
13559
13911
|
function parse(input, options) {
|
|
13560
13912
|
const tokens = tokenize(input);
|
|
13561
13913
|
const parser = new Parser(tokens, options, input);
|
|
@@ -13997,11 +14349,16 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
13997
14349
|
}
|
|
13998
14350
|
}
|
|
13999
14351
|
}
|
|
14000
|
-
if (leftNode?.type === 'selector' &&
|
|
14352
|
+
if (leftNode?.type === 'selector' &&
|
|
14353
|
+
typeof leftNode.value === 'string' &&
|
|
14354
|
+
(leftNode.fromQuery || (operator === 'in' && leftNode.value.startsWith('.')))) {
|
|
14001
14355
|
const root = await evaluateAST(node.right, context);
|
|
14002
14356
|
const scope = root && typeof root.querySelectorAll === 'function' ? root : null;
|
|
14003
14357
|
if (scope) {
|
|
14004
|
-
|
|
14358
|
+
const query = leftNode.fromQuery
|
|
14359
|
+
? leftNode.value
|
|
14360
|
+
: escapeSelectorForQuery(leftNode, leftNode.value);
|
|
14361
|
+
return Array.from(scope.querySelectorAll(query));
|
|
14005
14362
|
}
|
|
14006
14363
|
}
|
|
14007
14364
|
}
|
|
@@ -14013,6 +14370,12 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14013
14370
|
return getExpr(context, 'styleRef').evaluate(context, leftNode.value.slice(1), el);
|
|
14014
14371
|
}
|
|
14015
14372
|
if (operator === 'of') {
|
|
14373
|
+
if (leftNode?.type === 'attributeAccess') {
|
|
14374
|
+
const target = await evaluateAST(node.right, context);
|
|
14375
|
+
if (target == null)
|
|
14376
|
+
return undefined;
|
|
14377
|
+
return getExpr(context, 'possessive').evaluate(context, target, `@${leftNode.attributeName}`);
|
|
14378
|
+
}
|
|
14016
14379
|
const path = propertyPathOf(node.left);
|
|
14017
14380
|
if (path) {
|
|
14018
14381
|
const target = await evaluateAST(node.right, context);
|
|
@@ -14020,6 +14383,10 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14020
14383
|
for (const seg of path) {
|
|
14021
14384
|
if (cur == null)
|
|
14022
14385
|
return undefined;
|
|
14386
|
+
if (isMappableCollection(cur) && !(seg in cur)) {
|
|
14387
|
+
cur = await getExpr(context, 'possessive').evaluate(context, cur, seg);
|
|
14388
|
+
continue;
|
|
14389
|
+
}
|
|
14023
14390
|
cur = isElement(cur) ? getElementProperty$1(cur, seg) : cur[seg];
|
|
14024
14391
|
}
|
|
14025
14392
|
return typeof cur === 'function' ? cur.bind(target) : cur;
|
|
@@ -14044,26 +14411,21 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14044
14411
|
const R = node.ignoringCase ? applyCI(right) : right;
|
|
14045
14412
|
switch (operator) {
|
|
14046
14413
|
case '+': {
|
|
14047
|
-
let addLeft = left;
|
|
14048
|
-
let addRight = right;
|
|
14049
14414
|
if (node.coerceNumeric) {
|
|
14050
|
-
|
|
14051
|
-
addLeft = convertToNumber(addLeft);
|
|
14052
|
-
if (typeof addRight === 'string')
|
|
14053
|
-
addRight = convertToNumber(addRight);
|
|
14415
|
+
return counterValue(left) + counterAmount(right);
|
|
14054
14416
|
}
|
|
14055
|
-
if (typeof
|
|
14056
|
-
return String(
|
|
14417
|
+
if (typeof left === 'string' || typeof right === 'string') {
|
|
14418
|
+
return String(left ?? '') + String(right ?? '');
|
|
14057
14419
|
}
|
|
14058
|
-
if (Array.isArray(
|
|
14059
|
-
return Array.isArray(
|
|
14420
|
+
if (Array.isArray(left)) {
|
|
14421
|
+
return Array.isArray(right) ? [...left, ...right] : [...left, right];
|
|
14060
14422
|
}
|
|
14061
|
-
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, {
|
|
14062
|
-
left: addLeft,
|
|
14063
|
-
right: addRight,
|
|
14064
|
-
}));
|
|
14423
|
+
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, { left, right }));
|
|
14065
14424
|
}
|
|
14066
14425
|
case '-':
|
|
14426
|
+
if (node.coerceNumeric) {
|
|
14427
|
+
return counterValue(left) - counterAmount(right);
|
|
14428
|
+
}
|
|
14067
14429
|
return unwrapTypedResult(await getExpr(context, 'subtraction').evaluate(context, { left, right }));
|
|
14068
14430
|
case '*':
|
|
14069
14431
|
return unwrapTypedResult(await getExpr(context, 'multiplication').evaluate(context, { left, right }));
|
|
@@ -14321,9 +14683,8 @@ async function evaluatePropertyOfExpressionNode(node, context) {
|
|
|
14321
14683
|
}
|
|
14322
14684
|
const propertyName = propertyNode.name;
|
|
14323
14685
|
const target = await evaluateAST(node.target, context);
|
|
14324
|
-
if (target == null)
|
|
14325
|
-
|
|
14326
|
-
}
|
|
14686
|
+
if (target == null)
|
|
14687
|
+
return undefined;
|
|
14327
14688
|
return getExpr(context, 'possessive').evaluate(context, target, propertyName);
|
|
14328
14689
|
}
|
|
14329
14690
|
async function evaluateTemplateLiteralNode(node, context) {
|
|
@@ -14441,6 +14802,9 @@ async function evaluateUnaryExpression(node, context) {
|
|
|
14441
14802
|
case 'not':
|
|
14442
14803
|
case '!':
|
|
14443
14804
|
return logicalExpressions.not.evaluate(context, value);
|
|
14805
|
+
case 'beep!':
|
|
14806
|
+
beepValues(context.me, [value]);
|
|
14807
|
+
return value;
|
|
14444
14808
|
case 'no':
|
|
14445
14809
|
return logicalExpressions.no.evaluate(context, value);
|
|
14446
14810
|
case '-':
|
|
@@ -14530,6 +14894,10 @@ async function evaluateCallExpression(node, context) {
|
|
|
14530
14894
|
const args = await resolveCallArgs(node.arguments, funcName, context);
|
|
14531
14895
|
switch (funcName) {
|
|
14532
14896
|
case 'closest':
|
|
14897
|
+
if (node.closestTo) {
|
|
14898
|
+
const start = unwrapElement(await evaluateAST(node.closestTo, context)) ?? null;
|
|
14899
|
+
return referencesExpressions.closest.evaluate(context, args[0], start);
|
|
14900
|
+
}
|
|
14533
14901
|
return referencesExpressions.closest.evaluate(context, ...args);
|
|
14534
14902
|
case 'previous':
|
|
14535
14903
|
case 'next': {
|
|
@@ -15954,10 +16322,29 @@ const STRATEGY_KEYWORDS = {
|
|
|
15954
16322
|
innermorph: 'morph',
|
|
15955
16323
|
outermorph: 'morphOuter',
|
|
15956
16324
|
};
|
|
16325
|
+
function loneRootWithTag(content, tagName) {
|
|
16326
|
+
let root;
|
|
16327
|
+
if (typeof content === 'string') {
|
|
16328
|
+
const template = document.createElement('template');
|
|
16329
|
+
template.innerHTML = content;
|
|
16330
|
+
root = template.content.firstElementChild;
|
|
16331
|
+
if (!root || root.nextElementSibling)
|
|
16332
|
+
return null;
|
|
16333
|
+
}
|
|
16334
|
+
else {
|
|
16335
|
+
root = content.cloneNode(true);
|
|
16336
|
+
}
|
|
16337
|
+
return root.tagName === tagName && isHTMLElement$2(root) ? root : null;
|
|
16338
|
+
}
|
|
15957
16339
|
function executeSwap(target, content, strategy, morphOptions) {
|
|
15958
16340
|
const contentStr = content !== null && !isHTMLElement$2(content) ? content : '';
|
|
15959
16341
|
const contentEl = isHTMLElement$2(content) ? content : null;
|
|
15960
16342
|
switch (strategy) {
|
|
16343
|
+
case 'morphMerge': {
|
|
16344
|
+
const root = content !== null ? loneRootWithTag(content, target.tagName) : null;
|
|
16345
|
+
executeSwap(target, root ?? content, root ? 'morphOuter' : 'morph', morphOptions);
|
|
16346
|
+
break;
|
|
16347
|
+
}
|
|
15961
16348
|
case 'morph':
|
|
15962
16349
|
if (content !== null) {
|
|
15963
16350
|
try {
|
|
@@ -16247,7 +16634,7 @@ let MorphCommand = (() => {
|
|
|
16247
16634
|
if (args.length === 0 && modifiers.with === undefined) {
|
|
16248
16635
|
throw new Error('[HyperFixi] morph: command requires arguments');
|
|
16249
16636
|
}
|
|
16250
|
-
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : '
|
|
16637
|
+
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : 'morphMerge';
|
|
16251
16638
|
const useViewTransition = modifiers.viewTransition !== undefined;
|
|
16252
16639
|
const targetNode = modifiers.on !== undefined ? modifiers.on : args[0];
|
|
16253
16640
|
const contentNode = modifiers.with !== undefined
|
|
@@ -17537,6 +17924,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17537
17924
|
}
|
|
17538
17925
|
return { kind: 'property', target: property };
|
|
17539
17926
|
}
|
|
17927
|
+
if (options.ofAndObjectProperty) {
|
|
17928
|
+
const access = ofOrPossessiveAccess(n);
|
|
17929
|
+
if (access) {
|
|
17930
|
+
const owner = await evaluator.evaluate(access.owner, context);
|
|
17931
|
+
const element = Array.isArray(owner) ? owner[0] : owner;
|
|
17932
|
+
if (access.isOf && isHTMLElement$2(element)) {
|
|
17933
|
+
return { kind: 'property', target: { element, property: access.name } };
|
|
17934
|
+
}
|
|
17935
|
+
if (isObjectOwner(owner)) {
|
|
17936
|
+
return { kind: 'member', container: owner, property: access.name };
|
|
17937
|
+
}
|
|
17938
|
+
}
|
|
17939
|
+
}
|
|
17540
17940
|
if (options.bareReference &&
|
|
17541
17941
|
(nodeType === 'identifier' || nodeType === 'variable' || nodeType === 'symbol') &&
|
|
17542
17942
|
typeof n.name === 'string') {
|
|
@@ -17546,6 +17946,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17546
17946
|
}
|
|
17547
17947
|
return null;
|
|
17548
17948
|
}
|
|
17949
|
+
function ofOrPossessiveAccess(n) {
|
|
17950
|
+
const [owner, property, isOf] = n.type === 'possessiveExpression'
|
|
17951
|
+
? [n.object, n.property, false]
|
|
17952
|
+
: n.type === 'propertyOfExpression'
|
|
17953
|
+
? [n.target, n.property, false]
|
|
17954
|
+
: n.type === 'binaryExpression' && n.operator === 'of'
|
|
17955
|
+
? [n.right, n.left, true]
|
|
17956
|
+
: [undefined, undefined, false];
|
|
17957
|
+
const name = property?.name;
|
|
17958
|
+
if (!owner || typeof name !== 'string' || !/^[A-Za-z_$][\w$]*$/.test(name))
|
|
17959
|
+
return null;
|
|
17960
|
+
return { owner, name, isOf };
|
|
17961
|
+
}
|
|
17549
17962
|
|
|
17550
17963
|
function toSetInput(target, value) {
|
|
17551
17964
|
switch (target.kind) {
|
|
@@ -17567,10 +17980,18 @@ function toSetInput(target, value) {
|
|
|
17567
17980
|
property: target.target.property,
|
|
17568
17981
|
value,
|
|
17569
17982
|
};
|
|
17983
|
+
case 'member':
|
|
17984
|
+
return {
|
|
17985
|
+
type: 'member-assignment',
|
|
17986
|
+
container: target.container,
|
|
17987
|
+
property: target.property,
|
|
17988
|
+
value,
|
|
17989
|
+
};
|
|
17570
17990
|
default:
|
|
17571
17991
|
throw new Error(`set: unrequested write-target rung '${target.kind}'`);
|
|
17572
17992
|
}
|
|
17573
17993
|
}
|
|
17994
|
+
const SET_RUNGS = { nodeWriters: true, styleSplit: true, ofAndObjectProperty: true };
|
|
17574
17995
|
let SetCommand = (() => {
|
|
17575
17996
|
let _classDecorators = [command({ name: 'set' })];
|
|
17576
17997
|
let _classDescriptor;
|
|
@@ -17589,8 +18010,7 @@ let SetCommand = (() => {
|
|
|
17589
18010
|
const argScope = firstArg?.scope;
|
|
17590
18011
|
const writeTarget = await resolveWriteTarget(firstArg, evaluator, context, {
|
|
17591
18012
|
scopeElements: () => this.resolveTargets(raw.modifiers.on, evaluator, context),
|
|
17592
|
-
|
|
17593
|
-
styleSplit: true,
|
|
18013
|
+
...SET_RUNGS,
|
|
17594
18014
|
});
|
|
17595
18015
|
if (writeTarget) {
|
|
17596
18016
|
return toSetInput(writeTarget, await this.extractValue(raw, evaluator, context));
|
|
@@ -17916,12 +18336,30 @@ function getNodeType(node) {
|
|
|
17916
18336
|
return 'unknown';
|
|
17917
18337
|
return node.type || 'unknown';
|
|
17918
18338
|
}
|
|
18339
|
+
function propertyTarget(node) {
|
|
18340
|
+
const n = node;
|
|
18341
|
+
const owner = n.type === 'propertyOfExpression'
|
|
18342
|
+
? n.target
|
|
18343
|
+
: n.type === 'possessiveExpression' ||
|
|
18344
|
+
n.type === 'memberExpression' ||
|
|
18345
|
+
n.type === 'propertyAccess'
|
|
18346
|
+
? n.object
|
|
18347
|
+
: undefined;
|
|
18348
|
+
if (!owner || n.computed)
|
|
18349
|
+
return null;
|
|
18350
|
+
const p = n.property;
|
|
18351
|
+
const name = typeof p === 'string' ? p : typeof p?.name === 'string' ? p.name : undefined;
|
|
18352
|
+
if (!name || !/^[A-Za-z_$][\w$-]*$/.test(name))
|
|
18353
|
+
return null;
|
|
18354
|
+
return { owner, name };
|
|
18355
|
+
}
|
|
17919
18356
|
async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
17920
18357
|
if (!raw.args || raw.args.length === 0) {
|
|
17921
18358
|
throw new Error(`${commandName} command requires a target`);
|
|
17922
18359
|
}
|
|
17923
18360
|
const targetArg = raw.args[0];
|
|
17924
18361
|
let target;
|
|
18362
|
+
let property;
|
|
17925
18363
|
let extractedScope;
|
|
17926
18364
|
let customWrite;
|
|
17927
18365
|
const nodeType = getNodeType(targetArg);
|
|
@@ -17936,7 +18374,25 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17936
18374
|
}
|
|
17937
18375
|
else {
|
|
17938
18376
|
const writer = getRegisteredNodeWriter(nodeType);
|
|
17939
|
-
|
|
18377
|
+
const attribute = writer
|
|
18378
|
+
? null
|
|
18379
|
+
: await resolveAttributeWriteTarget(targetArg, evaluator, context, async () => context.me ? [context.me] : []);
|
|
18380
|
+
const prop = writer || attribute ? null : propertyTarget(targetArg);
|
|
18381
|
+
const owner = prop ? await evaluator.evaluate(prop.owner, context) : undefined;
|
|
18382
|
+
const ownerElement = Array.isArray(owner) ? owner[0] : owner;
|
|
18383
|
+
if (attribute?.elements[0]) {
|
|
18384
|
+
target = attribute.elements[0];
|
|
18385
|
+
property = `@${attribute.name}`;
|
|
18386
|
+
}
|
|
18387
|
+
else if (prop && isHTMLElement$2(ownerElement)) {
|
|
18388
|
+
target = ownerElement;
|
|
18389
|
+
property = prop.name;
|
|
18390
|
+
}
|
|
18391
|
+
else if (prop && isObjectOwner(owner)) {
|
|
18392
|
+
target = owner;
|
|
18393
|
+
property = prop.name;
|
|
18394
|
+
}
|
|
18395
|
+
else if (writer) {
|
|
17940
18396
|
const currentRaw = await evaluator.evaluate(targetArg, context);
|
|
17941
18397
|
const currentValue = typeof currentRaw === 'number'
|
|
17942
18398
|
? currentRaw
|
|
@@ -17974,24 +18430,22 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17974
18430
|
if (typeof evaluated === 'number') {
|
|
17975
18431
|
amount = evaluated;
|
|
17976
18432
|
}
|
|
18433
|
+
else if (evaluated == null) {
|
|
18434
|
+
amount = NaN;
|
|
18435
|
+
}
|
|
17977
18436
|
}
|
|
17978
18437
|
}
|
|
17979
18438
|
const byModifier = raw.modifiers?.by;
|
|
17980
18439
|
if (byModifier) {
|
|
17981
|
-
const
|
|
17982
|
-
|
|
17983
|
-
|
|
17984
|
-
|
|
17985
|
-
else if (getNodeType(byModifier) !== 'literal') {
|
|
17986
|
-
const evaluated = await evaluator.evaluate(byModifier, context);
|
|
17987
|
-
if (typeof evaluated === 'number') {
|
|
17988
|
-
amount = evaluated;
|
|
17989
|
-
}
|
|
17990
|
-
}
|
|
18440
|
+
const value = getNodeType(byModifier) === 'literal'
|
|
18441
|
+
? byModifier.value
|
|
18442
|
+
: await evaluator.evaluate(byModifier, context);
|
|
18443
|
+
amount = counterAmount(value);
|
|
17991
18444
|
}
|
|
17992
18445
|
return {
|
|
17993
18446
|
target,
|
|
17994
18447
|
amount,
|
|
18448
|
+
...(property && { property }),
|
|
17995
18449
|
...(scope && { scope }),
|
|
17996
18450
|
...(customWrite && { customWrite }),
|
|
17997
18451
|
};
|
|
@@ -18014,7 +18468,7 @@ let NumericModifyCommand = (() => {
|
|
|
18014
18468
|
async execute(input, context) {
|
|
18015
18469
|
const { target, property, scope, amount = 1, operation = 'increment', customWrite } = input;
|
|
18016
18470
|
if (customWrite) {
|
|
18017
|
-
const delta =
|
|
18471
|
+
const delta = amount;
|
|
18018
18472
|
const newValue = operation === 'increment'
|
|
18019
18473
|
? customWrite.currentValue + delta
|
|
18020
18474
|
: customWrite.currentValue - delta;
|
|
@@ -18028,8 +18482,7 @@ let NumericModifyCommand = (() => {
|
|
|
18028
18482
|
newValue = NaN;
|
|
18029
18483
|
}
|
|
18030
18484
|
else {
|
|
18031
|
-
|
|
18032
|
-
newValue = operation === 'increment' ? currentValue + delta : currentValue - delta;
|
|
18485
|
+
newValue = operation === 'increment' ? currentValue + amount : currentValue - amount;
|
|
18033
18486
|
}
|
|
18034
18487
|
setTargetValue(target, property, scope, newValue, context);
|
|
18035
18488
|
Object.assign(context, { it: newValue });
|
|
@@ -18845,17 +19298,7 @@ let BeepCommand = (() => {
|
|
|
18845
19298
|
this.debugContext(context);
|
|
18846
19299
|
return { expressionCount: 0, debugged: true, outputs: [] };
|
|
18847
19300
|
}
|
|
18848
|
-
const outputs =
|
|
18849
|
-
console.group('\ud83d\udd14 beep! Debug Output');
|
|
18850
|
-
for (const expression of expressions) {
|
|
18851
|
-
const output = this.debugExpression(expression);
|
|
18852
|
-
outputs.push(output);
|
|
18853
|
-
console.log(`Value:`, expression);
|
|
18854
|
-
console.log(`Type:`, output.type);
|
|
18855
|
-
console.log(`Representation:`, output.representation);
|
|
18856
|
-
console.log('---');
|
|
18857
|
-
}
|
|
18858
|
-
console.groupEnd();
|
|
19301
|
+
const outputs = beepValues(context.me, expressions);
|
|
18859
19302
|
return { expressionCount: expressions.length, debugged: true, outputs };
|
|
18860
19303
|
}
|
|
18861
19304
|
debugContext(context) {
|
|
@@ -18868,67 +19311,6 @@ let BeepCommand = (() => {
|
|
|
18868
19311
|
console.log('variables:', context.variables);
|
|
18869
19312
|
console.groupEnd();
|
|
18870
19313
|
}
|
|
18871
|
-
debugExpression(expression) {
|
|
18872
|
-
return {
|
|
18873
|
-
value: expression,
|
|
18874
|
-
type: this.getType(expression),
|
|
18875
|
-
representation: this.getRepresentation(expression),
|
|
18876
|
-
};
|
|
18877
|
-
}
|
|
18878
|
-
getType(value) {
|
|
18879
|
-
if (value === null)
|
|
18880
|
-
return 'null';
|
|
18881
|
-
if (value === undefined)
|
|
18882
|
-
return 'undefined';
|
|
18883
|
-
if (Array.isArray(value))
|
|
18884
|
-
return 'array';
|
|
18885
|
-
if (isHTMLElement$2(value))
|
|
18886
|
-
return 'HTMLElement';
|
|
18887
|
-
if (value instanceof Element)
|
|
18888
|
-
return 'Element';
|
|
18889
|
-
if (value instanceof Node)
|
|
18890
|
-
return 'Node';
|
|
18891
|
-
if (value instanceof Error)
|
|
18892
|
-
return 'Error';
|
|
18893
|
-
if (value instanceof Date)
|
|
18894
|
-
return 'Date';
|
|
18895
|
-
if (value instanceof RegExp)
|
|
18896
|
-
return 'RegExp';
|
|
18897
|
-
return typeof value;
|
|
18898
|
-
}
|
|
18899
|
-
getRepresentation(value) {
|
|
18900
|
-
if (value === null)
|
|
18901
|
-
return 'null';
|
|
18902
|
-
if (value === undefined)
|
|
18903
|
-
return 'undefined';
|
|
18904
|
-
if (Array.isArray(value)) {
|
|
18905
|
-
return `Array(${value.length}) [${value
|
|
18906
|
-
.slice(0, 3)
|
|
18907
|
-
.map(v => this.getRepresentation(v))
|
|
18908
|
-
.join(', ')}${value.length > 3 ? '...' : ''}]`;
|
|
18909
|
-
}
|
|
18910
|
-
if (isHTMLElement$2(value)) {
|
|
18911
|
-
const el = value;
|
|
18912
|
-
const tag = el.tagName.toLowerCase();
|
|
18913
|
-
const id = el.id ? `#${el.id}` : '';
|
|
18914
|
-
const classes = el.className ? `.${el.className.split(' ').join('.')}` : '';
|
|
18915
|
-
return `<${tag}${id}${classes}/>`;
|
|
18916
|
-
}
|
|
18917
|
-
if (value instanceof Error)
|
|
18918
|
-
return `Error: ${value.message}`;
|
|
18919
|
-
if (typeof value === 'string')
|
|
18920
|
-
return value.length > 50 ? `"${value.substring(0, 47)}..."` : `"${value}"`;
|
|
18921
|
-
if (typeof value === 'object') {
|
|
18922
|
-
try {
|
|
18923
|
-
const keys = Object.keys(value);
|
|
18924
|
-
return `Object {${keys.slice(0, 3).join(', ')}${keys.length > 3 ? '...' : ''}}`;
|
|
18925
|
-
}
|
|
18926
|
-
catch {
|
|
18927
|
-
return '[Object]';
|
|
18928
|
-
}
|
|
18929
|
-
}
|
|
18930
|
-
return String(value);
|
|
18931
|
-
}
|
|
18932
19314
|
};
|
|
18933
19315
|
__setFunctionName(_classThis, "BeepCommand");
|
|
18934
19316
|
(() => {
|
|
@@ -19890,7 +20272,10 @@ function createUntilLoopConfig(conditionExpr, evaluateCondition, context, indexV
|
|
|
19890
20272
|
};
|
|
19891
20273
|
const config = {
|
|
19892
20274
|
type: 'until',
|
|
19893
|
-
shouldContinue: () =>
|
|
20275
|
+
shouldContinue: () => {
|
|
20276
|
+
const met = evaluateCondition(conditionExpr, context);
|
|
20277
|
+
return met instanceof Promise ? met.then(value => !value) : !met;
|
|
20278
|
+
},
|
|
19894
20279
|
};
|
|
19895
20280
|
return { config, iterCtx };
|
|
19896
20281
|
}
|
|
@@ -19939,6 +20324,18 @@ async function slotText(node, evaluator, context) {
|
|
|
19939
20324
|
const v = await evaluator.evaluate(node, context);
|
|
19940
20325
|
return typeof v === 'string' ? v : undefined;
|
|
19941
20326
|
}
|
|
20327
|
+
function isEventTarget(value) {
|
|
20328
|
+
return typeof value?.addEventListener === 'function';
|
|
20329
|
+
}
|
|
20330
|
+
async function evaluateLoopCondition(condition, context) {
|
|
20331
|
+
if (typeof condition === 'function')
|
|
20332
|
+
return Boolean(await condition());
|
|
20333
|
+
return evaluateCondition(condition, context);
|
|
20334
|
+
}
|
|
20335
|
+
function loopCount(value) {
|
|
20336
|
+
const count = Number(value);
|
|
20337
|
+
return Number.isNaN(count) ? 0 : count;
|
|
20338
|
+
}
|
|
19942
20339
|
let RepeatCommand = (() => {
|
|
19943
20340
|
let _classDecorators = [command({ name: 'repeat' })];
|
|
19944
20341
|
let _classDescriptor;
|
|
@@ -19996,17 +20393,24 @@ let RepeatCommand = (() => {
|
|
|
19996
20393
|
};
|
|
19997
20394
|
}
|
|
19998
20395
|
if (loopType === 'times' || m.times) {
|
|
19999
|
-
|
|
20000
|
-
const count = typeof countValue === 'number' ? countValue : parseInt(String(countValue), 10);
|
|
20001
|
-
if (isNaN(count))
|
|
20396
|
+
if (!m.times)
|
|
20002
20397
|
throw new Error('times loops require a count number');
|
|
20398
|
+
const count = loopCount(await evaluator.evaluate(m.times, context));
|
|
20003
20399
|
return { type: 'times', count, indexVariable, commands, elseCommands };
|
|
20004
20400
|
}
|
|
20005
20401
|
if (loopType === 'while' || m.while) {
|
|
20006
20402
|
const condition = m.while;
|
|
20007
20403
|
if (!condition)
|
|
20008
20404
|
throw new Error('while loops require a condition');
|
|
20009
|
-
|
|
20405
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20406
|
+
return {
|
|
20407
|
+
type: 'while',
|
|
20408
|
+
condition: check,
|
|
20409
|
+
indexVariable,
|
|
20410
|
+
commands,
|
|
20411
|
+
elseCommands,
|
|
20412
|
+
bottomTested,
|
|
20413
|
+
};
|
|
20010
20414
|
}
|
|
20011
20415
|
if (loopType === 'until-event' || m.event) {
|
|
20012
20416
|
const eventName = await text(m.event);
|
|
@@ -20024,7 +20428,7 @@ let RepeatCommand = (() => {
|
|
|
20024
20428
|
}
|
|
20025
20429
|
else {
|
|
20026
20430
|
const target = await evaluator.evaluate(m.from, context);
|
|
20027
|
-
if (target
|
|
20431
|
+
if (isEventTarget(target))
|
|
20028
20432
|
eventTarget = target;
|
|
20029
20433
|
else if (target === 'document')
|
|
20030
20434
|
eventTarget = document;
|
|
@@ -20045,7 +20449,15 @@ let RepeatCommand = (() => {
|
|
|
20045
20449
|
const condition = m.until;
|
|
20046
20450
|
if (!condition)
|
|
20047
20451
|
throw new Error('until loops require a condition');
|
|
20048
|
-
|
|
20452
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20453
|
+
return {
|
|
20454
|
+
type: 'until',
|
|
20455
|
+
condition: check,
|
|
20456
|
+
indexVariable,
|
|
20457
|
+
commands,
|
|
20458
|
+
elseCommands,
|
|
20459
|
+
bottomTested,
|
|
20460
|
+
};
|
|
20049
20461
|
}
|
|
20050
20462
|
if (loopType === 'forever') {
|
|
20051
20463
|
return { type: 'forever', indexVariable, commands, elseCommands };
|
|
@@ -20063,10 +20475,10 @@ let RepeatCommand = (() => {
|
|
|
20063
20475
|
({ config, iterCtx } = createTimesLoopConfig(count, indexVariable));
|
|
20064
20476
|
break;
|
|
20065
20477
|
case 'while':
|
|
20066
|
-
({ config, iterCtx } = createWhileLoopConfig(condition,
|
|
20478
|
+
({ config, iterCtx } = createWhileLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20067
20479
|
break;
|
|
20068
20480
|
case 'until':
|
|
20069
|
-
({ config, iterCtx } = createUntilLoopConfig(condition,
|
|
20481
|
+
({ config, iterCtx } = createUntilLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20070
20482
|
break;
|
|
20071
20483
|
case 'until-event':
|
|
20072
20484
|
({ config, iterCtx } = createUntilEventLoopConfig(eventName, eventTarget, indexVariable));
|
|
@@ -21097,6 +21509,29 @@ function namedPropertyOf(node) {
|
|
|
21097
21509
|
}
|
|
21098
21510
|
return null;
|
|
21099
21511
|
}
|
|
21512
|
+
const RESTORE_KEYWORDS = new Set(['initial', 'inherit', 'unset', 'revert']);
|
|
21513
|
+
function elementsOf(value) {
|
|
21514
|
+
if (Array.isArray(value) || isNodeList(value)) {
|
|
21515
|
+
return Array.from(value).filter(isHTMLElement$2);
|
|
21516
|
+
}
|
|
21517
|
+
return isHTMLElement$2(value) ? [value] : [];
|
|
21518
|
+
}
|
|
21519
|
+
async function valueOf(node, evaluator, context) {
|
|
21520
|
+
const value = await evaluator.evaluate(node, context);
|
|
21521
|
+
const name = node.name;
|
|
21522
|
+
if (value === undefined && node.type === 'identifier' && typeof name === 'string')
|
|
21523
|
+
return name;
|
|
21524
|
+
return value;
|
|
21525
|
+
}
|
|
21526
|
+
function longestTransitionMs(css) {
|
|
21527
|
+
let longest;
|
|
21528
|
+
for (const item of css.split(',')) {
|
|
21529
|
+
const times = [...item.matchAll(/(\d*\.?\d+)(ms|s)\b/g)].map(m => parseFloat(m[1]) * (m[2] === 's' ? 1000 : 1));
|
|
21530
|
+
if (times.length > 0)
|
|
21531
|
+
longest = Math.max(longest ?? 0, times[0] + (times[1] ?? 0));
|
|
21532
|
+
}
|
|
21533
|
+
return longest;
|
|
21534
|
+
}
|
|
21100
21535
|
let TransitionCommand = (() => {
|
|
21101
21536
|
let _classDecorators = [command({ name: 'transition' })];
|
|
21102
21537
|
let _classDescriptor;
|
|
@@ -21112,11 +21547,10 @@ let TransitionCommand = (() => {
|
|
|
21112
21547
|
let property;
|
|
21113
21548
|
let target;
|
|
21114
21549
|
const firstArg = await evaluator.evaluate(raw.args[0], context);
|
|
21115
|
-
const
|
|
21116
|
-
|
|
21117
|
-
if (isHTMLElement$2(firstAsElement) ||
|
|
21550
|
+
const owners = elementsOf(firstArg);
|
|
21551
|
+
if (owners.length > 0 ||
|
|
21118
21552
|
(typeof firstArg === 'string' && /^[#.]|^(?:me|it|you)$/.test(firstArg))) {
|
|
21119
|
-
target =
|
|
21553
|
+
target = owners.length === 1 ? owners[0] : owners.length > 1 ? owners : firstArg;
|
|
21120
21554
|
property = String(await evaluator.evaluate(raw.args[1], context));
|
|
21121
21555
|
}
|
|
21122
21556
|
else if (raw.args.length >= 2) {
|
|
@@ -21128,9 +21562,9 @@ let TransitionCommand = (() => {
|
|
|
21128
21562
|
throw new Error('transition requires a CSS property');
|
|
21129
21563
|
property = named.property;
|
|
21130
21564
|
if (named.objectNode !== undefined) {
|
|
21131
|
-
const owner =
|
|
21132
|
-
if (
|
|
21133
|
-
target = owner;
|
|
21565
|
+
const owner = elementsOf(await evaluator.evaluate(named.objectNode, context));
|
|
21566
|
+
if (owner.length > 0)
|
|
21567
|
+
target = owner.length === 1 ? owner[0] : owner;
|
|
21134
21568
|
}
|
|
21135
21569
|
}
|
|
21136
21570
|
else {
|
|
@@ -21141,60 +21575,131 @@ let TransitionCommand = (() => {
|
|
|
21141
21575
|
}
|
|
21142
21576
|
if (!raw.modifiers?.to)
|
|
21143
21577
|
throw new Error('transition requires "to <value>"');
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
value
|
|
21147
|
-
}
|
|
21148
|
-
const result = { property, value: value };
|
|
21578
|
+
const result = {
|
|
21579
|
+
property,
|
|
21580
|
+
value: await valueOf(raw.modifiers.to, evaluator, context),
|
|
21581
|
+
};
|
|
21149
21582
|
if (target !== undefined)
|
|
21150
21583
|
result.target = target;
|
|
21584
|
+
if (raw.modifiers?.from)
|
|
21585
|
+
result.from = await valueOf(raw.modifiers.from, evaluator, context);
|
|
21586
|
+
if (raw.modifiers?.pairs) {
|
|
21587
|
+
result.pairs = await this.laterPairs(raw.modifiers.pairs, evaluator, context);
|
|
21588
|
+
}
|
|
21151
21589
|
if (raw.modifiers?.over)
|
|
21152
21590
|
result.duration = await evaluator.evaluate(raw.modifiers.over, context);
|
|
21153
21591
|
if (raw.modifiers?.with)
|
|
21154
21592
|
result.timingFunction = String(await evaluator.evaluate(raw.modifiers.with, context));
|
|
21593
|
+
if (raw.modifiers?.using)
|
|
21594
|
+
result.using = String(await evaluator.evaluate(raw.modifiers.using, context));
|
|
21155
21595
|
return result;
|
|
21156
21596
|
}
|
|
21597
|
+
async laterPairs(node, evaluator, context) {
|
|
21598
|
+
const pairs = [];
|
|
21599
|
+
for (const pairNode of node.elements ?? []) {
|
|
21600
|
+
const fields = new Map();
|
|
21601
|
+
const properties = pairNode
|
|
21602
|
+
.properties ?? [];
|
|
21603
|
+
for (const { key, value } of properties) {
|
|
21604
|
+
if (typeof key.name === 'string')
|
|
21605
|
+
fields.set(key.name, value);
|
|
21606
|
+
}
|
|
21607
|
+
const propertyNode = fields.get('property');
|
|
21608
|
+
const toNode = fields.get('to');
|
|
21609
|
+
if (!propertyNode || !toNode)
|
|
21610
|
+
throw new Error('transition requires property and value');
|
|
21611
|
+
const pair = {
|
|
21612
|
+
property: String(await evaluator.evaluate(propertyNode, context)),
|
|
21613
|
+
value: await valueOf(toNode, evaluator, context),
|
|
21614
|
+
};
|
|
21615
|
+
const ownerNode = fields.get('owner');
|
|
21616
|
+
if (ownerNode) {
|
|
21617
|
+
const owners = elementsOf(await evaluator.evaluate(ownerNode, context));
|
|
21618
|
+
if (owners.length === 0)
|
|
21619
|
+
throw new Error('transition: target element not found');
|
|
21620
|
+
pair.target = owners.length === 1 ? owners[0] : owners;
|
|
21621
|
+
}
|
|
21622
|
+
const fromNode = fields.get('from');
|
|
21623
|
+
if (fromNode)
|
|
21624
|
+
pair.from = await valueOf(fromNode, evaluator, context);
|
|
21625
|
+
pairs.push(pair);
|
|
21626
|
+
}
|
|
21627
|
+
return pairs;
|
|
21628
|
+
}
|
|
21157
21629
|
async execute(input, context) {
|
|
21158
|
-
|
|
21159
|
-
const
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21164
|
-
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
toValue = getComputedStyle(targetElement).getPropertyValue(property);
|
|
21180
|
-
if (currentInline) {
|
|
21181
|
-
targetElement.style.setProperty(property, currentInline);
|
|
21182
|
-
}
|
|
21183
|
-
removeInlineAfter = true;
|
|
21184
|
-
}
|
|
21185
|
-
targetElement.style.setProperty(property, toValue);
|
|
21186
|
-
const result = await waitForTransitionEnd(targetElement, property, duration);
|
|
21187
|
-
targetElement.style.transition = originalTransition;
|
|
21188
|
-
if (removeInlineAfter) {
|
|
21189
|
-
targetElement.style.removeProperty(property);
|
|
21630
|
+
const duration = parseDuration(input.duration, (input.using !== undefined && longestTransitionMs(input.using)) || 300);
|
|
21631
|
+
const timing = input.timingFunction || 'ease';
|
|
21632
|
+
const jobs = [];
|
|
21633
|
+
for (const pair of [input, ...(input.pairs ?? [])]) {
|
|
21634
|
+
let property = pair.property;
|
|
21635
|
+
if (property.startsWith('*'))
|
|
21636
|
+
property = property.substring(1);
|
|
21637
|
+
property = camelToKebab(property);
|
|
21638
|
+
const elements = Array.isArray(pair.target)
|
|
21639
|
+
? pair.target.filter(isHTMLElement$2)
|
|
21640
|
+
: [resolveElement(pair.target, context, 'transition')];
|
|
21641
|
+
for (const element of elements) {
|
|
21642
|
+
jobs.push({
|
|
21643
|
+
element,
|
|
21644
|
+
property,
|
|
21645
|
+
pair,
|
|
21646
|
+
fromValue: getComputedStyle(element).getPropertyValue(property),
|
|
21647
|
+
toValue: '',
|
|
21648
|
+
removeInlineAfter: false,
|
|
21649
|
+
});
|
|
21650
|
+
}
|
|
21190
21651
|
}
|
|
21652
|
+
if (jobs.length === 0)
|
|
21653
|
+
throw new Error('transition: target element not found');
|
|
21654
|
+
for (const job of jobs) {
|
|
21655
|
+
if (job.pair.from !== undefined) {
|
|
21656
|
+
job.element.style.setProperty(job.property, String(job.pair.from));
|
|
21657
|
+
}
|
|
21658
|
+
}
|
|
21659
|
+
for (const job of jobs)
|
|
21660
|
+
if (job.pair.from !== undefined)
|
|
21661
|
+
void job.element.offsetWidth;
|
|
21662
|
+
const originals = new Map();
|
|
21663
|
+
for (const job of jobs) {
|
|
21664
|
+
if (!originals.has(job.element))
|
|
21665
|
+
originals.set(job.element, job.element.style.transition);
|
|
21666
|
+
}
|
|
21667
|
+
for (const [element, original] of originals) {
|
|
21668
|
+
const own = jobs
|
|
21669
|
+
.filter(job => job.element === element)
|
|
21670
|
+
.map(job => `${job.property} ${duration}ms ${timing}`);
|
|
21671
|
+
element.style.transition = input.using ?? [original, ...own].filter(Boolean).join(', ');
|
|
21672
|
+
}
|
|
21673
|
+
for (const job of jobs) {
|
|
21674
|
+
const { element, property } = job;
|
|
21675
|
+
let toValue = String(job.pair.value);
|
|
21676
|
+
if (RESTORE_KEYWORDS.has(toValue)) {
|
|
21677
|
+
const currentInline = element.style.getPropertyValue(property);
|
|
21678
|
+
element.style.removeProperty(property);
|
|
21679
|
+
toValue = getComputedStyle(element).getPropertyValue(property);
|
|
21680
|
+
if (currentInline) {
|
|
21681
|
+
element.style.setProperty(property, currentInline);
|
|
21682
|
+
}
|
|
21683
|
+
job.removeInlineAfter = true;
|
|
21684
|
+
}
|
|
21685
|
+
job.toValue = toValue;
|
|
21686
|
+
element.style.setProperty(property, toValue);
|
|
21687
|
+
}
|
|
21688
|
+
const results = await Promise.all(jobs.map(job => waitForTransitionEnd(job.element, job.property, duration)));
|
|
21689
|
+
for (const [element, original] of originals)
|
|
21690
|
+
element.style.transition = original;
|
|
21691
|
+
for (const job of jobs) {
|
|
21692
|
+
if (job.removeInlineAfter)
|
|
21693
|
+
job.element.style.removeProperty(job.property);
|
|
21694
|
+
}
|
|
21695
|
+
const first = jobs[0];
|
|
21191
21696
|
return {
|
|
21192
|
-
element:
|
|
21193
|
-
property,
|
|
21194
|
-
fromValue,
|
|
21195
|
-
toValue,
|
|
21697
|
+
element: first.element,
|
|
21698
|
+
property: first.property,
|
|
21699
|
+
fromValue: first.fromValue,
|
|
21700
|
+
toValue: first.toValue,
|
|
21196
21701
|
duration,
|
|
21197
|
-
completed: result.completed,
|
|
21702
|
+
completed: results.every(result => result.completed),
|
|
21198
21703
|
};
|
|
21199
21704
|
}
|
|
21200
21705
|
};
|
|
@@ -21207,13 +21712,16 @@ let TransitionCommand = (() => {
|
|
|
21207
21712
|
})();
|
|
21208
21713
|
_classThis.metadata = commandMeta({
|
|
21209
21714
|
description: 'Animate CSS properties using CSS transitions',
|
|
21210
|
-
syntax: 'transition [<
|
|
21715
|
+
syntax: 'transition <property> [from <value>] to <value> [<property> \u2026 to <value>]\u2026 [over <duration>] [using <css> | with <timing>]',
|
|
21211
21716
|
examples: [
|
|
21212
21717
|
'transition opacity to 0.5',
|
|
21213
21718
|
'transition my *opacity to 0 over 200ms',
|
|
21214
21719
|
"transition #box's *opacity to 0 over 200ms",
|
|
21215
21720
|
'transition left to 100px over 500ms',
|
|
21216
21721
|
'transition background-color to red over 1s with ease-in-out',
|
|
21722
|
+
'transition *width to 100px *height to 50px over 300ms',
|
|
21723
|
+
'transition *opacity of #panel from 0 to 1 over 200ms',
|
|
21724
|
+
'transition my *opacity to 0 using "opacity 1s ease-in"',
|
|
21217
21725
|
],
|
|
21218
21726
|
sideEffects: ['style-change', 'timing'],
|
|
21219
21727
|
category: 'animation',
|
|
@@ -22339,16 +22847,12 @@ class RenderCommand {
|
|
|
22339
22847
|
}
|
|
22340
22848
|
RenderCommand.metadata = commandMeta({
|
|
22341
22849
|
description: 'Render templates with @if, @else, and @repeat directives',
|
|
22342
|
-
syntax: [
|
|
22343
|
-
'render <template>',
|
|
22344
|
-
'render <template> with <variables>',
|
|
22345
|
-
'render <template> with (key: value, ...)',
|
|
22346
|
-
],
|
|
22850
|
+
syntax: ['render <template>', 'render <template> with <name>: <value>, ...'],
|
|
22347
22851
|
examples: [
|
|
22348
22852
|
'render myTemplate',
|
|
22349
|
-
'render myTemplate with
|
|
22350
|
-
'render "<template>Hello ${name}!</template>" with
|
|
22351
|
-
'render template with
|
|
22853
|
+
'render myTemplate with name: "Alice"',
|
|
22854
|
+
'render "<template>Hello ${name}!</template>" with name: "World"',
|
|
22855
|
+
'render template with items: data',
|
|
22352
22856
|
],
|
|
22353
22857
|
category: 'templates',
|
|
22354
22858
|
compatibility: 'standard',
|