@hyperfixi/core 3.1.1 → 3.3.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 +36 -17
- package/dist/bundle-generator/index.mjs +36 -17
- package/dist/bundle-generator/parser-templates.d.ts +1 -1
- package/dist/chunks/bridge-CI9SOl8u.js +2 -0
- package/dist/chunks/browser-modular-7CpI5VF2.js +2 -0
- package/dist/chunks/index-BwXDEK0m.js +2 -0
- package/dist/chunks/index-DQi2o8Lk.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 +938 -425
- package/dist/commands/index.mjs +938 -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 +1149 -485
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +1149 -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 +396 -153
- package/dist/parser/full-parser.mjs +396 -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 +535 -210
- package/dist/registry/index.mjs +535 -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-D7qrHhV0.js +0 -2
- package/dist/chunks/browser-modular-C4LFxfoS.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')) {
|
|
@@ -9154,6 +9417,15 @@ function parseToggleCommand(ctx, identifierNode) {
|
|
|
9154
9417
|
args.push(classArg.expression);
|
|
9155
9418
|
modifiers['as'] = literalModifier(mode);
|
|
9156
9419
|
}
|
|
9420
|
+
else if (classArg?.type === 'binaryExpression' &&
|
|
9421
|
+
classArg.operator === 'of' &&
|
|
9422
|
+
classArg.left?.type === 'selector' &&
|
|
9423
|
+
typeof classArg.left.value === 'string' &&
|
|
9424
|
+
classArg.left.value.startsWith('*') &&
|
|
9425
|
+
classArg.right) {
|
|
9426
|
+
args.push(classArg.left);
|
|
9427
|
+
modifiers['on'] = classArg.right;
|
|
9428
|
+
}
|
|
9157
9429
|
else if (classArg) {
|
|
9158
9430
|
args.push(classArg);
|
|
9159
9431
|
}
|
|
@@ -9331,11 +9603,17 @@ function parseSwapCommand(ctx, identifierNode) {
|
|
|
9331
9603
|
const targetExpr = isDelete ? ctx.parseExpression() : parseOneArgument(ctx, [KEYWORDS.WITH]);
|
|
9332
9604
|
if (targetExpr)
|
|
9333
9605
|
args.push(targetExpr);
|
|
9334
|
-
|
|
9606
|
+
const isMorph = identifierNode.name === 'morph';
|
|
9607
|
+
if (!isDelete &&
|
|
9608
|
+
(consumeOptionalKeyword(ctx, KEYWORDS.WITH) ||
|
|
9609
|
+
(isMorph && consumeOptionalKeyword(ctx, KEYWORDS.TO)))) {
|
|
9335
9610
|
const contentExpr = parseOneArgument(ctx, ['using']);
|
|
9336
9611
|
if (contentExpr)
|
|
9337
9612
|
modifiers['with'] = contentExpr;
|
|
9338
9613
|
}
|
|
9614
|
+
if (isMorph && modifiers['with'] === undefined) {
|
|
9615
|
+
ctx.addError("Expected 'to' and the content to morph into");
|
|
9616
|
+
}
|
|
9339
9617
|
return CommandNodeBuilder.fromIdentifier(identifierNode)
|
|
9340
9618
|
.withArgs(...args)
|
|
9341
9619
|
.withModifiers({ ...modifiers, ...parseViewTransitionTail(ctx) })
|
|
@@ -10096,6 +10374,8 @@ function atArgumentBoundary(ctx, grammar) {
|
|
|
10096
10374
|
const next = ctx.peek();
|
|
10097
10375
|
if (ctx.checkIsCommand() && ctx.peekAt(1)?.value === '(')
|
|
10098
10376
|
return false;
|
|
10377
|
+
if (isGluedBeepBang(next, ctx.peekAt(1)))
|
|
10378
|
+
return false;
|
|
10099
10379
|
if (isCommandBoundary(ctx, ['catch', 'finally', 'on']))
|
|
10100
10380
|
return true;
|
|
10101
10381
|
return isKeyword(next, [...grammar.markers]);
|
|
@@ -10127,10 +10407,13 @@ function parseDeclaredCommand(ctx, commandToken, name, grammar) {
|
|
|
10127
10407
|
}
|
|
10128
10408
|
}
|
|
10129
10409
|
const commaList = new Set(grammar.commaList ?? []);
|
|
10410
|
+
const namedArgs = new Set(grammar.namedArgs ?? []);
|
|
10130
10411
|
while (!ctx.isAtEnd() && isKeyword(ctx.peek(), [...grammar.markers])) {
|
|
10131
10412
|
const keyword = ctx.advance().value;
|
|
10132
10413
|
const key = ctx.resolveKeyword(keyword).toLowerCase();
|
|
10133
|
-
let value =
|
|
10414
|
+
let value = namedArgs.has(key) && isNakedNamedArgStart(ctx)
|
|
10415
|
+
? parseNakedNamedArgs(ctx, () => ctx.parseExpression(), name)
|
|
10416
|
+
: ctx.parseExpression();
|
|
10134
10417
|
if (value && commaList.has(key) && ctx.check(',')) {
|
|
10135
10418
|
const elements = [value];
|
|
10136
10419
|
while (ctx.match(',')) {
|
|
@@ -10295,8 +10578,8 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10295
10578
|
}
|
|
10296
10579
|
if (ctx.check('with') && !modifiers['with']) {
|
|
10297
10580
|
ctx.advance();
|
|
10298
|
-
if (
|
|
10299
|
-
modifiers['with'] =
|
|
10581
|
+
if (isNakedNamedArgStart(ctx)) {
|
|
10582
|
+
modifiers['with'] = parseNakedNamedArgs(ctx, () => ctx.parsePrimary(), 'fetch');
|
|
10300
10583
|
}
|
|
10301
10584
|
else {
|
|
10302
10585
|
modifiers['with'] = ctx.parsePrimary();
|
|
@@ -10331,45 +10614,6 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10331
10614
|
}
|
|
10332
10615
|
return builder.build();
|
|
10333
10616
|
}
|
|
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
10617
|
function findJsEndBoundary(ctx, startPos) {
|
|
10374
10618
|
const input = ctx.getInputSlice(startPos);
|
|
10375
10619
|
if (!input) {
|
|
@@ -10489,6 +10733,7 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10489
10733
|
const commands = [];
|
|
10490
10734
|
while (!ctx.isAtEnd()) {
|
|
10491
10735
|
if (ctx.checkIsCommand()) {
|
|
10736
|
+
const word = ctx.peek().value;
|
|
10492
10737
|
try {
|
|
10493
10738
|
ctx.advance();
|
|
10494
10739
|
const cmd = ctx.parseCommand();
|
|
@@ -10499,7 +10744,8 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10499
10744
|
break;
|
|
10500
10745
|
}
|
|
10501
10746
|
}
|
|
10502
|
-
catch {
|
|
10747
|
+
catch (error) {
|
|
10748
|
+
ctx.addError(`'${word}' in a tell body failed to parse: ${error instanceof Error ? error.message : String(error)}`);
|
|
10503
10749
|
break;
|
|
10504
10750
|
}
|
|
10505
10751
|
if (ctx.match(KEYWORDS.AND) || ctx.match(KEYWORDS.THEN)) {
|
|
@@ -10648,7 +10894,6 @@ const ONE_EXPR = (syntax) => ({
|
|
|
10648
10894
|
markers: [],
|
|
10649
10895
|
syntax,
|
|
10650
10896
|
});
|
|
10651
|
-
const BEEP = ONE_EXPR('beep! [<expression>, \u2026]');
|
|
10652
10897
|
const COMMAND_GRAMMAR = {
|
|
10653
10898
|
append: { positional: 'expression', markers: ['to'], syntax: 'append <value> [to <target>]' },
|
|
10654
10899
|
prepend: { positional: 'expression', markers: ['to'], syntax: 'prepend <value> [to <target>]' },
|
|
@@ -10659,8 +10904,7 @@ const COMMAND_GRAMMAR = {
|
|
|
10659
10904
|
syntax: 'make (a|an) <type> [from <args>] [called <name>]',
|
|
10660
10905
|
},
|
|
10661
10906
|
throw: { positional: 'primary', markers: [], syntax: 'throw <error>' },
|
|
10662
|
-
'beep!'
|
|
10663
|
-
beep: BEEP,
|
|
10907
|
+
beep: ONE_EXPR('beep! [<expression>, \u2026]'),
|
|
10664
10908
|
blur: ONE_EXPR('blur [<target>]'),
|
|
10665
10909
|
break: NONE,
|
|
10666
10910
|
breakpoint: NONE,
|
|
@@ -10684,7 +10928,8 @@ const COMMAND_GRAMMAR = {
|
|
|
10684
10928
|
render: {
|
|
10685
10929
|
positional: 'expression',
|
|
10686
10930
|
markers: ['with'],
|
|
10687
|
-
|
|
10931
|
+
namedArgs: ['with'],
|
|
10932
|
+
syntax: 'render <template> [with <name>: <value>, \u2026]',
|
|
10688
10933
|
},
|
|
10689
10934
|
reset: ONE_EXPR('reset [<form>]'),
|
|
10690
10935
|
return: ONE_EXPR('return [<value>]'),
|
|
@@ -11039,7 +11284,10 @@ class Parser {
|
|
|
11039
11284
|
const firstToken = this.peek();
|
|
11040
11285
|
const prefixEntry = Parser.PRATT_TABLE.get(firstToken.value);
|
|
11041
11286
|
let left;
|
|
11042
|
-
if (
|
|
11287
|
+
if (isGluedBeepBang(firstToken, this.tokens[this.current + 1])) {
|
|
11288
|
+
left = this.parseBeepExpression();
|
|
11289
|
+
}
|
|
11290
|
+
else if (prefixEntry?.prefix) {
|
|
11043
11291
|
const token = this.advance();
|
|
11044
11292
|
if (this.isAtEnd()) {
|
|
11045
11293
|
this.addError(`Expected expression after '${token.value}' operator`);
|
|
@@ -11059,6 +11307,9 @@ class Parser {
|
|
|
11059
11307
|
continue;
|
|
11060
11308
|
}
|
|
11061
11309
|
}
|
|
11310
|
+
if (nextToken.value === '*' && this.isSpacedStyleRef(this.current)) {
|
|
11311
|
+
break;
|
|
11312
|
+
}
|
|
11062
11313
|
const infixEntry = Parser.PRATT_TABLE.get(nextToken.value);
|
|
11063
11314
|
if (!infixEntry?.infix) {
|
|
11064
11315
|
if (STOP_TOKENS.has(nextToken.value) || STOP_DELIMITERS.has(nextToken.value)) {
|
|
@@ -11120,6 +11371,35 @@ class Parser {
|
|
|
11120
11371
|
this.prattCache.set(cacheKey, { node: left, endPos: this.current });
|
|
11121
11372
|
return left;
|
|
11122
11373
|
}
|
|
11374
|
+
parseBeepExpression() {
|
|
11375
|
+
const beepToken = this.advance();
|
|
11376
|
+
this.advance();
|
|
11377
|
+
if (this.isAtEnd()) {
|
|
11378
|
+
this.addError("Expected expression after 'beep!'");
|
|
11379
|
+
return this.createErrorNode();
|
|
11380
|
+
}
|
|
11381
|
+
const operand = this.parseExpressionPratt(Parser.BEEP_OPERAND_BP);
|
|
11382
|
+
return {
|
|
11383
|
+
type: 'unaryExpression',
|
|
11384
|
+
operator: 'beep!',
|
|
11385
|
+
operand,
|
|
11386
|
+
argument: operand,
|
|
11387
|
+
prefix: true,
|
|
11388
|
+
start: beepToken.start,
|
|
11389
|
+
end: this.previous().end,
|
|
11390
|
+
line: beepToken.line,
|
|
11391
|
+
column: beepToken.column,
|
|
11392
|
+
};
|
|
11393
|
+
}
|
|
11394
|
+
isStyleRefStar(i) {
|
|
11395
|
+
const star = this.tokens[i];
|
|
11396
|
+
const name = this.tokens[i + 1];
|
|
11397
|
+
return star?.value === '*' && !!name && name.start === star.end && isIdentifierLike(name);
|
|
11398
|
+
}
|
|
11399
|
+
isSpacedStyleRef(i) {
|
|
11400
|
+
const prev = this.tokens[i - 1];
|
|
11401
|
+
return this.isStyleRefStar(i) && !!prev && prev.end < this.tokens[i].start;
|
|
11402
|
+
}
|
|
11123
11403
|
tryParseStringPostfix(left, nextToken) {
|
|
11124
11404
|
const v = nextToken.value;
|
|
11125
11405
|
let unit = null;
|
|
@@ -11322,6 +11602,10 @@ class Parser {
|
|
|
11322
11602
|
const isStop = () => this.check('end') || extraStops.some(s => this.check(s));
|
|
11323
11603
|
debug.parse('\ud83d\udd04 parseCommandListUntilTerminator: Starting (extraStops:', extraStops.join(','), ')');
|
|
11324
11604
|
while (!this.isAtEnd() && !isStop()) {
|
|
11605
|
+
if (this.checkComment()) {
|
|
11606
|
+
this.advance();
|
|
11607
|
+
continue;
|
|
11608
|
+
}
|
|
11325
11609
|
debug.parse('\ud83d\udccd Loop iteration, current token:', this.peek().value, 'kind:', this.peek().kind);
|
|
11326
11610
|
let parsedCommand = false;
|
|
11327
11611
|
const isCommandToken = this.checkIsCommand();
|
|
@@ -11405,7 +11689,7 @@ class Parser {
|
|
|
11405
11689
|
debug.parse('\u2705 Found "end", consuming it');
|
|
11406
11690
|
this.advance();
|
|
11407
11691
|
}
|
|
11408
|
-
else {
|
|
11692
|
+
else if (!this.atEndOfInput()) {
|
|
11409
11693
|
debug.parse('\u274c ERROR: Expected "end" but got:', this.peek().value, 'at position:', this.peek().start);
|
|
11410
11694
|
throw new Error(`Expected "end" to close ${construct} block`);
|
|
11411
11695
|
}
|
|
@@ -11418,7 +11702,7 @@ class Parser {
|
|
|
11418
11702
|
if (this.check('end')) {
|
|
11419
11703
|
this.advance();
|
|
11420
11704
|
}
|
|
11421
|
-
else {
|
|
11705
|
+
else if (!this.atEndOfInput()) {
|
|
11422
11706
|
throw new Error('Expected "end" to close repeat block');
|
|
11423
11707
|
}
|
|
11424
11708
|
}
|
|
@@ -11434,7 +11718,10 @@ class Parser {
|
|
|
11434
11718
|
this.advance();
|
|
11435
11719
|
}
|
|
11436
11720
|
else if (terminator === '') {
|
|
11437
|
-
|
|
11721
|
+
if (!this.atEndOfInput()) {
|
|
11722
|
+
throw new Error('Expected "end", "else", "until", or "while" to close repeat block');
|
|
11723
|
+
}
|
|
11724
|
+
return { commands, terminator: 'end' };
|
|
11438
11725
|
}
|
|
11439
11726
|
return { commands, terminator };
|
|
11440
11727
|
}
|
|
@@ -12018,7 +12305,9 @@ class Parser {
|
|
|
12018
12305
|
parseTopLevelInitBlock() {
|
|
12019
12306
|
const pos = this.getPosition();
|
|
12020
12307
|
const initCommands = this.parseCommandBlock(['end']);
|
|
12021
|
-
this.
|
|
12308
|
+
if (!this.match('end') && !this.atEndOfInput() && !this.checkFeatureStart()) {
|
|
12309
|
+
this.consume('end', "Expected 'end' after init block");
|
|
12310
|
+
}
|
|
12022
12311
|
return {
|
|
12023
12312
|
type: 'initBlock',
|
|
12024
12313
|
commands: initCommands,
|
|
@@ -12194,10 +12483,29 @@ class Parser {
|
|
|
12194
12483
|
...(sourceExpr.column !== undefined && { column: sourceExpr.column }),
|
|
12195
12484
|
};
|
|
12196
12485
|
}
|
|
12486
|
+
isArgumentListOnly(open) {
|
|
12487
|
+
let depth = 0;
|
|
12488
|
+
for (let i = open; i < this.tokens.length; i++) {
|
|
12489
|
+
const token = this.tokens[i];
|
|
12490
|
+
if (token.kind !== 'operator')
|
|
12491
|
+
continue;
|
|
12492
|
+
if (token.value === '(' || token.value === '[' || token.value === '{')
|
|
12493
|
+
depth++;
|
|
12494
|
+
else if (token.value === ')' || token.value === ']' || token.value === '}') {
|
|
12495
|
+
if (--depth === 0)
|
|
12496
|
+
return i === open + 1;
|
|
12497
|
+
}
|
|
12498
|
+
else if (token.value === ',' && depth === 1)
|
|
12499
|
+
return true;
|
|
12500
|
+
}
|
|
12501
|
+
return false;
|
|
12502
|
+
}
|
|
12197
12503
|
tryParsePseudoCommand(callExpr, sourceExpr) {
|
|
12198
12504
|
const methodName = callExpr.callee.name;
|
|
12199
12505
|
const nextToken = this.peek();
|
|
12200
|
-
const
|
|
12506
|
+
const nextIsArticle = nextToken.value.toLowerCase() === 'the';
|
|
12507
|
+
const hasPseudoCommandPattern = nextIsArticle ||
|
|
12508
|
+
Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(nextToken.value.toLowerCase()) ||
|
|
12201
12509
|
(isIdentifier(nextToken) && !this.isCommand(nextToken.value)) ||
|
|
12202
12510
|
isContextVar(nextToken);
|
|
12203
12511
|
if (!hasPseudoCommandPattern) {
|
|
@@ -12223,7 +12531,10 @@ class Parser {
|
|
|
12223
12531
|
});
|
|
12224
12532
|
}
|
|
12225
12533
|
let preposition;
|
|
12226
|
-
if (
|
|
12534
|
+
if (nextIsArticle) {
|
|
12535
|
+
this.advance();
|
|
12536
|
+
}
|
|
12537
|
+
else if (Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(this.peek().value.toLowerCase())) {
|
|
12227
12538
|
preposition = this.advance().value.toLowerCase();
|
|
12228
12539
|
}
|
|
12229
12540
|
let targetExpr;
|
|
@@ -12387,10 +12698,22 @@ class Parser {
|
|
|
12387
12698
|
this.consume(']', "Expected ']' after event condition");
|
|
12388
12699
|
}
|
|
12389
12700
|
let target;
|
|
12701
|
+
let targetExpression;
|
|
12390
12702
|
if (this.match('from')) {
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12703
|
+
if (this.check('the'))
|
|
12704
|
+
this.advance();
|
|
12705
|
+
if (Parser.POSITIONAL_SOURCE_HEADS.has(this.peek().value.toLowerCase())) {
|
|
12706
|
+
const startIndex = this.current;
|
|
12707
|
+
targetExpression = this.parseExpression();
|
|
12708
|
+
target = this.tokens
|
|
12709
|
+
.slice(startIndex, this.current)
|
|
12710
|
+
.map(t => t.value)
|
|
12711
|
+
.join(' ');
|
|
12712
|
+
}
|
|
12713
|
+
else {
|
|
12714
|
+
target = this.advance().value;
|
|
12715
|
+
}
|
|
12716
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'from' target: ${target}`);
|
|
12394
12717
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
12395
12718
|
}
|
|
12396
12719
|
let attributeName;
|
|
@@ -12436,7 +12759,7 @@ class Parser {
|
|
|
12436
12759
|
const nextIsOpenParen = this.tokens[this.current + 1]?.value === '(';
|
|
12437
12760
|
const commandName = this.peek().value.toLowerCase();
|
|
12438
12761
|
const isSpecialBodyCommand = commandName === 'js' || commandName === 'tell';
|
|
12439
|
-
if (nextIsOpenParen && !isSpecialBodyCommand) {
|
|
12762
|
+
if (nextIsOpenParen && !isSpecialBodyCommand && this.isArgumentListOnly(this.current + 1)) {
|
|
12440
12763
|
let expr;
|
|
12441
12764
|
const savedError = this.error;
|
|
12442
12765
|
try {
|
|
@@ -12468,7 +12791,7 @@ class Parser {
|
|
|
12468
12791
|
}
|
|
12469
12792
|
}
|
|
12470
12793
|
}
|
|
12471
|
-
else if (this.checkIdentifier()) {
|
|
12794
|
+
else if (this.checkIdentifier() || this.checkEventNamedCall()) {
|
|
12472
12795
|
const token = this.peek();
|
|
12473
12796
|
if (this.isCommand(token.value)) {
|
|
12474
12797
|
const cmd = this.parseCommandWithErrorRecovery();
|
|
@@ -12577,6 +12900,7 @@ class Parser {
|
|
|
12577
12900
|
...(eventParams.length > 0 && { args: eventParams }),
|
|
12578
12901
|
...(condition && { condition: fromLegacyExpression(condition) }),
|
|
12579
12902
|
...(target && { target }),
|
|
12903
|
+
...(targetExpression && { targetExpression: fromLegacyExpression(targetExpression) }),
|
|
12580
12904
|
...(attributeName && { attributeName }),
|
|
12581
12905
|
...(watchTarget && { watchTarget: fromLegacyExpression(watchTarget) }),
|
|
12582
12906
|
...(customEventSource && { customEventSource }),
|
|
@@ -12832,10 +13156,9 @@ class Parser {
|
|
|
12832
13156
|
}
|
|
12833
13157
|
parseCommandCore() {
|
|
12834
13158
|
const commandToken = this.previous();
|
|
12835
|
-
|
|
13159
|
+
const commandName = commandToken.value;
|
|
12836
13160
|
if (commandName === 'beep' && this.check('!')) {
|
|
12837
13161
|
this.advance();
|
|
12838
|
-
commandName = 'beep!';
|
|
12839
13162
|
}
|
|
12840
13163
|
if (commandName === 'fetch') {
|
|
12841
13164
|
return parseFetchCommand(this.getContext(), commandToken);
|
|
@@ -12934,6 +13257,9 @@ class Parser {
|
|
|
12934
13257
|
args.push(this.parsePrimary());
|
|
12935
13258
|
}
|
|
12936
13259
|
const callNode = this.createCallExpression(createIdentifier(funcName, namePos), args);
|
|
13260
|
+
if (funcName === 'closest' && args.length > 0 && this.match('to')) {
|
|
13261
|
+
callNode.closestTo = this.parseExpression();
|
|
13262
|
+
}
|
|
12937
13263
|
if (funcName === 'next' || funcName === 'previous') {
|
|
12938
13264
|
const relativePositional = this.parseRelativePositionalModifiers();
|
|
12939
13265
|
if (relativePositional) {
|
|
@@ -12973,6 +13299,9 @@ class Parser {
|
|
|
12973
13299
|
}
|
|
12974
13300
|
parseTheXofY() {
|
|
12975
13301
|
const positionalKeywords = ['first', 'last', 'next', 'previous', 'random', 'closest'];
|
|
13302
|
+
if (this.isStyleRefStar(this.current)) {
|
|
13303
|
+
return this.parsePrimary();
|
|
13304
|
+
}
|
|
12976
13305
|
if (!this.checkIdentifier()) {
|
|
12977
13306
|
return this.createIdentifier('the');
|
|
12978
13307
|
}
|
|
@@ -12988,7 +13317,7 @@ class Parser {
|
|
|
12988
13317
|
return this.createIdentifier(propertyName);
|
|
12989
13318
|
}
|
|
12990
13319
|
this.advance();
|
|
12991
|
-
const target = this.
|
|
13320
|
+
const target = parseOfOperand(this.makePrattContext(), THE_OF_TARGET_BP);
|
|
12992
13321
|
return {
|
|
12993
13322
|
type: 'propertyOfExpression',
|
|
12994
13323
|
property: { type: 'identifier', name: propertyName },
|
|
@@ -13186,6 +13515,13 @@ class Parser {
|
|
|
13186
13515
|
checkLiteral() {
|
|
13187
13516
|
return this.checkPredicate(isLiteral);
|
|
13188
13517
|
}
|
|
13518
|
+
checkEventNamedCall() {
|
|
13519
|
+
if (this.isAtEnd() || !this.checkIdentifierLike() || this.checkIsCommand())
|
|
13520
|
+
return false;
|
|
13521
|
+
const token = this.peek();
|
|
13522
|
+
const next = this.tokens[this.current + 1];
|
|
13523
|
+
return next?.value === '(' && next.start === token.end;
|
|
13524
|
+
}
|
|
13189
13525
|
checkIdentifierLike() {
|
|
13190
13526
|
return this.checkPredicate(isIdentifierLike);
|
|
13191
13527
|
}
|
|
@@ -13294,6 +13630,22 @@ class Parser {
|
|
|
13294
13630
|
isAtEnd() {
|
|
13295
13631
|
return this.current >= this.tokens.length;
|
|
13296
13632
|
}
|
|
13633
|
+
atEndOfInput() {
|
|
13634
|
+
for (let i = this.current; i < this.tokens.length; i++) {
|
|
13635
|
+
if (!isComment(this.tokens[i]))
|
|
13636
|
+
return false;
|
|
13637
|
+
}
|
|
13638
|
+
return true;
|
|
13639
|
+
}
|
|
13640
|
+
checkFeatureStart() {
|
|
13641
|
+
if (this.isAtEnd())
|
|
13642
|
+
return false;
|
|
13643
|
+
const value = this.peek().value;
|
|
13644
|
+
return (value === 'init' ||
|
|
13645
|
+
value === 'on' ||
|
|
13646
|
+
value === 'def' ||
|
|
13647
|
+
getRegisteredFeature(value) !== undefined);
|
|
13648
|
+
}
|
|
13297
13649
|
peek() {
|
|
13298
13650
|
if (this.isAtEnd()) {
|
|
13299
13651
|
return { kind: 'unknown', value: '', start: 0, end: 0, line: 1, column: 1 };
|
|
@@ -13505,6 +13857,7 @@ class Parser {
|
|
|
13505
13857
|
match: this.match.bind(this),
|
|
13506
13858
|
matchOperator: this.matchOperator.bind(this),
|
|
13507
13859
|
isAtEnd: this.isAtEnd.bind(this),
|
|
13860
|
+
atEndOfInput: this.atEndOfInput.bind(this),
|
|
13508
13861
|
createIdentifier: this.createIdentifier.bind(this),
|
|
13509
13862
|
parseExpression: this.parseExpression.bind(this),
|
|
13510
13863
|
parsePrimary: this.parsePrimary.bind(this),
|
|
@@ -13555,7 +13908,15 @@ Parser.POSTFIX_UNARY_OPERATORS = new Set([
|
|
|
13555
13908
|
'ignoring case',
|
|
13556
13909
|
]);
|
|
13557
13910
|
Parser.PRATT_TABLE = PARSER_TABLE;
|
|
13911
|
+
Parser.BEEP_OPERAND_BP = 80;
|
|
13558
13912
|
Parser.PSEUDO_COMMAND_PREPOSITIONS = ['from', 'on', 'with', 'into', 'at', 'to'];
|
|
13913
|
+
Parser.POSITIONAL_SOURCE_HEADS = new Set([
|
|
13914
|
+
'closest',
|
|
13915
|
+
'next',
|
|
13916
|
+
'previous',
|
|
13917
|
+
'first',
|
|
13918
|
+
'last',
|
|
13919
|
+
]);
|
|
13559
13920
|
function parse(input, options) {
|
|
13560
13921
|
const tokens = tokenize(input);
|
|
13561
13922
|
const parser = new Parser(tokens, options, input);
|
|
@@ -13997,11 +14358,16 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
13997
14358
|
}
|
|
13998
14359
|
}
|
|
13999
14360
|
}
|
|
14000
|
-
if (leftNode?.type === 'selector' &&
|
|
14361
|
+
if (leftNode?.type === 'selector' &&
|
|
14362
|
+
typeof leftNode.value === 'string' &&
|
|
14363
|
+
(leftNode.fromQuery || (operator === 'in' && leftNode.value.startsWith('.')))) {
|
|
14001
14364
|
const root = await evaluateAST(node.right, context);
|
|
14002
14365
|
const scope = root && typeof root.querySelectorAll === 'function' ? root : null;
|
|
14003
14366
|
if (scope) {
|
|
14004
|
-
|
|
14367
|
+
const query = leftNode.fromQuery
|
|
14368
|
+
? leftNode.value
|
|
14369
|
+
: escapeSelectorForQuery(leftNode, leftNode.value);
|
|
14370
|
+
return Array.from(scope.querySelectorAll(query));
|
|
14005
14371
|
}
|
|
14006
14372
|
}
|
|
14007
14373
|
}
|
|
@@ -14013,6 +14379,12 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14013
14379
|
return getExpr(context, 'styleRef').evaluate(context, leftNode.value.slice(1), el);
|
|
14014
14380
|
}
|
|
14015
14381
|
if (operator === 'of') {
|
|
14382
|
+
if (leftNode?.type === 'attributeAccess') {
|
|
14383
|
+
const target = await evaluateAST(node.right, context);
|
|
14384
|
+
if (target == null)
|
|
14385
|
+
return undefined;
|
|
14386
|
+
return getExpr(context, 'possessive').evaluate(context, target, `@${leftNode.attributeName}`);
|
|
14387
|
+
}
|
|
14016
14388
|
const path = propertyPathOf(node.left);
|
|
14017
14389
|
if (path) {
|
|
14018
14390
|
const target = await evaluateAST(node.right, context);
|
|
@@ -14020,6 +14392,10 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14020
14392
|
for (const seg of path) {
|
|
14021
14393
|
if (cur == null)
|
|
14022
14394
|
return undefined;
|
|
14395
|
+
if (isMappableCollection(cur) && !(seg in cur)) {
|
|
14396
|
+
cur = await getExpr(context, 'possessive').evaluate(context, cur, seg);
|
|
14397
|
+
continue;
|
|
14398
|
+
}
|
|
14023
14399
|
cur = isElement(cur) ? getElementProperty$1(cur, seg) : cur[seg];
|
|
14024
14400
|
}
|
|
14025
14401
|
return typeof cur === 'function' ? cur.bind(target) : cur;
|
|
@@ -14044,26 +14420,21 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14044
14420
|
const R = node.ignoringCase ? applyCI(right) : right;
|
|
14045
14421
|
switch (operator) {
|
|
14046
14422
|
case '+': {
|
|
14047
|
-
let addLeft = left;
|
|
14048
|
-
let addRight = right;
|
|
14049
14423
|
if (node.coerceNumeric) {
|
|
14050
|
-
|
|
14051
|
-
addLeft = convertToNumber(addLeft);
|
|
14052
|
-
if (typeof addRight === 'string')
|
|
14053
|
-
addRight = convertToNumber(addRight);
|
|
14424
|
+
return counterValue(left) + counterAmount(right);
|
|
14054
14425
|
}
|
|
14055
|
-
if (typeof
|
|
14056
|
-
return String(
|
|
14426
|
+
if (typeof left === 'string' || typeof right === 'string') {
|
|
14427
|
+
return String(left ?? '') + String(right ?? '');
|
|
14057
14428
|
}
|
|
14058
|
-
if (Array.isArray(
|
|
14059
|
-
return Array.isArray(
|
|
14429
|
+
if (Array.isArray(left)) {
|
|
14430
|
+
return Array.isArray(right) ? [...left, ...right] : [...left, right];
|
|
14060
14431
|
}
|
|
14061
|
-
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, {
|
|
14062
|
-
left: addLeft,
|
|
14063
|
-
right: addRight,
|
|
14064
|
-
}));
|
|
14432
|
+
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, { left, right }));
|
|
14065
14433
|
}
|
|
14066
14434
|
case '-':
|
|
14435
|
+
if (node.coerceNumeric) {
|
|
14436
|
+
return counterValue(left) - counterAmount(right);
|
|
14437
|
+
}
|
|
14067
14438
|
return unwrapTypedResult(await getExpr(context, 'subtraction').evaluate(context, { left, right }));
|
|
14068
14439
|
case '*':
|
|
14069
14440
|
return unwrapTypedResult(await getExpr(context, 'multiplication').evaluate(context, { left, right }));
|
|
@@ -14321,9 +14692,8 @@ async function evaluatePropertyOfExpressionNode(node, context) {
|
|
|
14321
14692
|
}
|
|
14322
14693
|
const propertyName = propertyNode.name;
|
|
14323
14694
|
const target = await evaluateAST(node.target, context);
|
|
14324
|
-
if (target == null)
|
|
14325
|
-
|
|
14326
|
-
}
|
|
14695
|
+
if (target == null)
|
|
14696
|
+
return undefined;
|
|
14327
14697
|
return getExpr(context, 'possessive').evaluate(context, target, propertyName);
|
|
14328
14698
|
}
|
|
14329
14699
|
async function evaluateTemplateLiteralNode(node, context) {
|
|
@@ -14441,6 +14811,9 @@ async function evaluateUnaryExpression(node, context) {
|
|
|
14441
14811
|
case 'not':
|
|
14442
14812
|
case '!':
|
|
14443
14813
|
return logicalExpressions.not.evaluate(context, value);
|
|
14814
|
+
case 'beep!':
|
|
14815
|
+
beepValues(context.me, [value]);
|
|
14816
|
+
return value;
|
|
14444
14817
|
case 'no':
|
|
14445
14818
|
return logicalExpressions.no.evaluate(context, value);
|
|
14446
14819
|
case '-':
|
|
@@ -14530,6 +14903,10 @@ async function evaluateCallExpression(node, context) {
|
|
|
14530
14903
|
const args = await resolveCallArgs(node.arguments, funcName, context);
|
|
14531
14904
|
switch (funcName) {
|
|
14532
14905
|
case 'closest':
|
|
14906
|
+
if (node.closestTo) {
|
|
14907
|
+
const start = unwrapElement(await evaluateAST(node.closestTo, context)) ?? null;
|
|
14908
|
+
return referencesExpressions.closest.evaluate(context, args[0], start);
|
|
14909
|
+
}
|
|
14533
14910
|
return referencesExpressions.closest.evaluate(context, ...args);
|
|
14534
14911
|
case 'previous':
|
|
14535
14912
|
case 'next': {
|
|
@@ -15954,10 +16331,29 @@ const STRATEGY_KEYWORDS = {
|
|
|
15954
16331
|
innermorph: 'morph',
|
|
15955
16332
|
outermorph: 'morphOuter',
|
|
15956
16333
|
};
|
|
16334
|
+
function loneRootWithTag(content, tagName) {
|
|
16335
|
+
let root;
|
|
16336
|
+
if (typeof content === 'string') {
|
|
16337
|
+
const template = document.createElement('template');
|
|
16338
|
+
template.innerHTML = content;
|
|
16339
|
+
root = template.content.firstElementChild;
|
|
16340
|
+
if (!root || root.nextElementSibling)
|
|
16341
|
+
return null;
|
|
16342
|
+
}
|
|
16343
|
+
else {
|
|
16344
|
+
root = content.cloneNode(true);
|
|
16345
|
+
}
|
|
16346
|
+
return root.tagName === tagName && isHTMLElement$2(root) ? root : null;
|
|
16347
|
+
}
|
|
15957
16348
|
function executeSwap(target, content, strategy, morphOptions) {
|
|
15958
16349
|
const contentStr = content !== null && !isHTMLElement$2(content) ? content : '';
|
|
15959
16350
|
const contentEl = isHTMLElement$2(content) ? content : null;
|
|
15960
16351
|
switch (strategy) {
|
|
16352
|
+
case 'morphMerge': {
|
|
16353
|
+
const root = content !== null ? loneRootWithTag(content, target.tagName) : null;
|
|
16354
|
+
executeSwap(target, root ?? content, root ? 'morphOuter' : 'morph', morphOptions);
|
|
16355
|
+
break;
|
|
16356
|
+
}
|
|
15961
16357
|
case 'morph':
|
|
15962
16358
|
if (content !== null) {
|
|
15963
16359
|
try {
|
|
@@ -16247,7 +16643,7 @@ let MorphCommand = (() => {
|
|
|
16247
16643
|
if (args.length === 0 && modifiers.with === undefined) {
|
|
16248
16644
|
throw new Error('[HyperFixi] morph: command requires arguments');
|
|
16249
16645
|
}
|
|
16250
|
-
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : '
|
|
16646
|
+
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : 'morphMerge';
|
|
16251
16647
|
const useViewTransition = modifiers.viewTransition !== undefined;
|
|
16252
16648
|
const targetNode = modifiers.on !== undefined ? modifiers.on : args[0];
|
|
16253
16649
|
const contentNode = modifiers.with !== undefined
|
|
@@ -17537,6 +17933,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17537
17933
|
}
|
|
17538
17934
|
return { kind: 'property', target: property };
|
|
17539
17935
|
}
|
|
17936
|
+
if (options.ofAndObjectProperty) {
|
|
17937
|
+
const access = ofOrPossessiveAccess(n);
|
|
17938
|
+
if (access) {
|
|
17939
|
+
const owner = await evaluator.evaluate(access.owner, context);
|
|
17940
|
+
const element = Array.isArray(owner) ? owner[0] : owner;
|
|
17941
|
+
if (access.isOf && isHTMLElement$2(element)) {
|
|
17942
|
+
return { kind: 'property', target: { element, property: access.name } };
|
|
17943
|
+
}
|
|
17944
|
+
if (isObjectOwner(owner)) {
|
|
17945
|
+
return { kind: 'member', container: owner, property: access.name };
|
|
17946
|
+
}
|
|
17947
|
+
}
|
|
17948
|
+
}
|
|
17540
17949
|
if (options.bareReference &&
|
|
17541
17950
|
(nodeType === 'identifier' || nodeType === 'variable' || nodeType === 'symbol') &&
|
|
17542
17951
|
typeof n.name === 'string') {
|
|
@@ -17546,6 +17955,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17546
17955
|
}
|
|
17547
17956
|
return null;
|
|
17548
17957
|
}
|
|
17958
|
+
function ofOrPossessiveAccess(n) {
|
|
17959
|
+
const [owner, property, isOf] = n.type === 'possessiveExpression'
|
|
17960
|
+
? [n.object, n.property, false]
|
|
17961
|
+
: n.type === 'propertyOfExpression'
|
|
17962
|
+
? [n.target, n.property, false]
|
|
17963
|
+
: n.type === 'binaryExpression' && n.operator === 'of'
|
|
17964
|
+
? [n.right, n.left, true]
|
|
17965
|
+
: [undefined, undefined, false];
|
|
17966
|
+
const name = property?.name;
|
|
17967
|
+
if (!owner || typeof name !== 'string' || !/^[A-Za-z_$][\w$]*$/.test(name))
|
|
17968
|
+
return null;
|
|
17969
|
+
return { owner, name, isOf };
|
|
17970
|
+
}
|
|
17549
17971
|
|
|
17550
17972
|
function toSetInput(target, value) {
|
|
17551
17973
|
switch (target.kind) {
|
|
@@ -17567,10 +17989,18 @@ function toSetInput(target, value) {
|
|
|
17567
17989
|
property: target.target.property,
|
|
17568
17990
|
value,
|
|
17569
17991
|
};
|
|
17992
|
+
case 'member':
|
|
17993
|
+
return {
|
|
17994
|
+
type: 'member-assignment',
|
|
17995
|
+
container: target.container,
|
|
17996
|
+
property: target.property,
|
|
17997
|
+
value,
|
|
17998
|
+
};
|
|
17570
17999
|
default:
|
|
17571
18000
|
throw new Error(`set: unrequested write-target rung '${target.kind}'`);
|
|
17572
18001
|
}
|
|
17573
18002
|
}
|
|
18003
|
+
const SET_RUNGS = { nodeWriters: true, styleSplit: true, ofAndObjectProperty: true };
|
|
17574
18004
|
let SetCommand = (() => {
|
|
17575
18005
|
let _classDecorators = [command({ name: 'set' })];
|
|
17576
18006
|
let _classDescriptor;
|
|
@@ -17589,8 +18019,7 @@ let SetCommand = (() => {
|
|
|
17589
18019
|
const argScope = firstArg?.scope;
|
|
17590
18020
|
const writeTarget = await resolveWriteTarget(firstArg, evaluator, context, {
|
|
17591
18021
|
scopeElements: () => this.resolveTargets(raw.modifiers.on, evaluator, context),
|
|
17592
|
-
|
|
17593
|
-
styleSplit: true,
|
|
18022
|
+
...SET_RUNGS,
|
|
17594
18023
|
});
|
|
17595
18024
|
if (writeTarget) {
|
|
17596
18025
|
return toSetInput(writeTarget, await this.extractValue(raw, evaluator, context));
|
|
@@ -17916,12 +18345,30 @@ function getNodeType(node) {
|
|
|
17916
18345
|
return 'unknown';
|
|
17917
18346
|
return node.type || 'unknown';
|
|
17918
18347
|
}
|
|
18348
|
+
function propertyTarget(node) {
|
|
18349
|
+
const n = node;
|
|
18350
|
+
const owner = n.type === 'propertyOfExpression'
|
|
18351
|
+
? n.target
|
|
18352
|
+
: n.type === 'possessiveExpression' ||
|
|
18353
|
+
n.type === 'memberExpression' ||
|
|
18354
|
+
n.type === 'propertyAccess'
|
|
18355
|
+
? n.object
|
|
18356
|
+
: undefined;
|
|
18357
|
+
if (!owner || n.computed)
|
|
18358
|
+
return null;
|
|
18359
|
+
const p = n.property;
|
|
18360
|
+
const name = typeof p === 'string' ? p : typeof p?.name === 'string' ? p.name : undefined;
|
|
18361
|
+
if (!name || !/^[A-Za-z_$][\w$-]*$/.test(name))
|
|
18362
|
+
return null;
|
|
18363
|
+
return { owner, name };
|
|
18364
|
+
}
|
|
17919
18365
|
async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
17920
18366
|
if (!raw.args || raw.args.length === 0) {
|
|
17921
18367
|
throw new Error(`${commandName} command requires a target`);
|
|
17922
18368
|
}
|
|
17923
18369
|
const targetArg = raw.args[0];
|
|
17924
18370
|
let target;
|
|
18371
|
+
let property;
|
|
17925
18372
|
let extractedScope;
|
|
17926
18373
|
let customWrite;
|
|
17927
18374
|
const nodeType = getNodeType(targetArg);
|
|
@@ -17936,7 +18383,25 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17936
18383
|
}
|
|
17937
18384
|
else {
|
|
17938
18385
|
const writer = getRegisteredNodeWriter(nodeType);
|
|
17939
|
-
|
|
18386
|
+
const attribute = writer
|
|
18387
|
+
? null
|
|
18388
|
+
: await resolveAttributeWriteTarget(targetArg, evaluator, context, async () => context.me ? [context.me] : []);
|
|
18389
|
+
const prop = writer || attribute ? null : propertyTarget(targetArg);
|
|
18390
|
+
const owner = prop ? await evaluator.evaluate(prop.owner, context) : undefined;
|
|
18391
|
+
const ownerElement = Array.isArray(owner) ? owner[0] : owner;
|
|
18392
|
+
if (attribute?.elements[0]) {
|
|
18393
|
+
target = attribute.elements[0];
|
|
18394
|
+
property = `@${attribute.name}`;
|
|
18395
|
+
}
|
|
18396
|
+
else if (prop && isHTMLElement$2(ownerElement)) {
|
|
18397
|
+
target = ownerElement;
|
|
18398
|
+
property = prop.name;
|
|
18399
|
+
}
|
|
18400
|
+
else if (prop && isObjectOwner(owner)) {
|
|
18401
|
+
target = owner;
|
|
18402
|
+
property = prop.name;
|
|
18403
|
+
}
|
|
18404
|
+
else if (writer) {
|
|
17940
18405
|
const currentRaw = await evaluator.evaluate(targetArg, context);
|
|
17941
18406
|
const currentValue = typeof currentRaw === 'number'
|
|
17942
18407
|
? currentRaw
|
|
@@ -17974,24 +18439,22 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17974
18439
|
if (typeof evaluated === 'number') {
|
|
17975
18440
|
amount = evaluated;
|
|
17976
18441
|
}
|
|
18442
|
+
else if (evaluated == null) {
|
|
18443
|
+
amount = NaN;
|
|
18444
|
+
}
|
|
17977
18445
|
}
|
|
17978
18446
|
}
|
|
17979
18447
|
const byModifier = raw.modifiers?.by;
|
|
17980
18448
|
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
|
-
}
|
|
18449
|
+
const value = getNodeType(byModifier) === 'literal'
|
|
18450
|
+
? byModifier.value
|
|
18451
|
+
: await evaluator.evaluate(byModifier, context);
|
|
18452
|
+
amount = counterAmount(value);
|
|
17991
18453
|
}
|
|
17992
18454
|
return {
|
|
17993
18455
|
target,
|
|
17994
18456
|
amount,
|
|
18457
|
+
...(property && { property }),
|
|
17995
18458
|
...(scope && { scope }),
|
|
17996
18459
|
...(customWrite && { customWrite }),
|
|
17997
18460
|
};
|
|
@@ -18014,7 +18477,7 @@ let NumericModifyCommand = (() => {
|
|
|
18014
18477
|
async execute(input, context) {
|
|
18015
18478
|
const { target, property, scope, amount = 1, operation = 'increment', customWrite } = input;
|
|
18016
18479
|
if (customWrite) {
|
|
18017
|
-
const delta =
|
|
18480
|
+
const delta = amount;
|
|
18018
18481
|
const newValue = operation === 'increment'
|
|
18019
18482
|
? customWrite.currentValue + delta
|
|
18020
18483
|
: customWrite.currentValue - delta;
|
|
@@ -18028,8 +18491,7 @@ let NumericModifyCommand = (() => {
|
|
|
18028
18491
|
newValue = NaN;
|
|
18029
18492
|
}
|
|
18030
18493
|
else {
|
|
18031
|
-
|
|
18032
|
-
newValue = operation === 'increment' ? currentValue + delta : currentValue - delta;
|
|
18494
|
+
newValue = operation === 'increment' ? currentValue + amount : currentValue - amount;
|
|
18033
18495
|
}
|
|
18034
18496
|
setTargetValue(target, property, scope, newValue, context);
|
|
18035
18497
|
Object.assign(context, { it: newValue });
|
|
@@ -18845,17 +19307,7 @@ let BeepCommand = (() => {
|
|
|
18845
19307
|
this.debugContext(context);
|
|
18846
19308
|
return { expressionCount: 0, debugged: true, outputs: [] };
|
|
18847
19309
|
}
|
|
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();
|
|
19310
|
+
const outputs = beepValues(context.me, expressions);
|
|
18859
19311
|
return { expressionCount: expressions.length, debugged: true, outputs };
|
|
18860
19312
|
}
|
|
18861
19313
|
debugContext(context) {
|
|
@@ -18868,67 +19320,6 @@ let BeepCommand = (() => {
|
|
|
18868
19320
|
console.log('variables:', context.variables);
|
|
18869
19321
|
console.groupEnd();
|
|
18870
19322
|
}
|
|
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
19323
|
};
|
|
18933
19324
|
__setFunctionName(_classThis, "BeepCommand");
|
|
18934
19325
|
(() => {
|
|
@@ -19890,7 +20281,10 @@ function createUntilLoopConfig(conditionExpr, evaluateCondition, context, indexV
|
|
|
19890
20281
|
};
|
|
19891
20282
|
const config = {
|
|
19892
20283
|
type: 'until',
|
|
19893
|
-
shouldContinue: () =>
|
|
20284
|
+
shouldContinue: () => {
|
|
20285
|
+
const met = evaluateCondition(conditionExpr, context);
|
|
20286
|
+
return met instanceof Promise ? met.then(value => !value) : !met;
|
|
20287
|
+
},
|
|
19894
20288
|
};
|
|
19895
20289
|
return { config, iterCtx };
|
|
19896
20290
|
}
|
|
@@ -19939,6 +20333,18 @@ async function slotText(node, evaluator, context) {
|
|
|
19939
20333
|
const v = await evaluator.evaluate(node, context);
|
|
19940
20334
|
return typeof v === 'string' ? v : undefined;
|
|
19941
20335
|
}
|
|
20336
|
+
function isEventTarget(value) {
|
|
20337
|
+
return typeof value?.addEventListener === 'function';
|
|
20338
|
+
}
|
|
20339
|
+
async function evaluateLoopCondition(condition, context) {
|
|
20340
|
+
if (typeof condition === 'function')
|
|
20341
|
+
return Boolean(await condition());
|
|
20342
|
+
return evaluateCondition(condition, context);
|
|
20343
|
+
}
|
|
20344
|
+
function loopCount(value) {
|
|
20345
|
+
const count = Number(value);
|
|
20346
|
+
return Number.isNaN(count) ? 0 : count;
|
|
20347
|
+
}
|
|
19942
20348
|
let RepeatCommand = (() => {
|
|
19943
20349
|
let _classDecorators = [command({ name: 'repeat' })];
|
|
19944
20350
|
let _classDescriptor;
|
|
@@ -19996,17 +20402,24 @@ let RepeatCommand = (() => {
|
|
|
19996
20402
|
};
|
|
19997
20403
|
}
|
|
19998
20404
|
if (loopType === 'times' || m.times) {
|
|
19999
|
-
|
|
20000
|
-
const count = typeof countValue === 'number' ? countValue : parseInt(String(countValue), 10);
|
|
20001
|
-
if (isNaN(count))
|
|
20405
|
+
if (!m.times)
|
|
20002
20406
|
throw new Error('times loops require a count number');
|
|
20407
|
+
const count = loopCount(await evaluator.evaluate(m.times, context));
|
|
20003
20408
|
return { type: 'times', count, indexVariable, commands, elseCommands };
|
|
20004
20409
|
}
|
|
20005
20410
|
if (loopType === 'while' || m.while) {
|
|
20006
20411
|
const condition = m.while;
|
|
20007
20412
|
if (!condition)
|
|
20008
20413
|
throw new Error('while loops require a condition');
|
|
20009
|
-
|
|
20414
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20415
|
+
return {
|
|
20416
|
+
type: 'while',
|
|
20417
|
+
condition: check,
|
|
20418
|
+
indexVariable,
|
|
20419
|
+
commands,
|
|
20420
|
+
elseCommands,
|
|
20421
|
+
bottomTested,
|
|
20422
|
+
};
|
|
20010
20423
|
}
|
|
20011
20424
|
if (loopType === 'until-event' || m.event) {
|
|
20012
20425
|
const eventName = await text(m.event);
|
|
@@ -20024,7 +20437,7 @@ let RepeatCommand = (() => {
|
|
|
20024
20437
|
}
|
|
20025
20438
|
else {
|
|
20026
20439
|
const target = await evaluator.evaluate(m.from, context);
|
|
20027
|
-
if (target
|
|
20440
|
+
if (isEventTarget(target))
|
|
20028
20441
|
eventTarget = target;
|
|
20029
20442
|
else if (target === 'document')
|
|
20030
20443
|
eventTarget = document;
|
|
@@ -20045,7 +20458,15 @@ let RepeatCommand = (() => {
|
|
|
20045
20458
|
const condition = m.until;
|
|
20046
20459
|
if (!condition)
|
|
20047
20460
|
throw new Error('until loops require a condition');
|
|
20048
|
-
|
|
20461
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20462
|
+
return {
|
|
20463
|
+
type: 'until',
|
|
20464
|
+
condition: check,
|
|
20465
|
+
indexVariable,
|
|
20466
|
+
commands,
|
|
20467
|
+
elseCommands,
|
|
20468
|
+
bottomTested,
|
|
20469
|
+
};
|
|
20049
20470
|
}
|
|
20050
20471
|
if (loopType === 'forever') {
|
|
20051
20472
|
return { type: 'forever', indexVariable, commands, elseCommands };
|
|
@@ -20063,10 +20484,10 @@ let RepeatCommand = (() => {
|
|
|
20063
20484
|
({ config, iterCtx } = createTimesLoopConfig(count, indexVariable));
|
|
20064
20485
|
break;
|
|
20065
20486
|
case 'while':
|
|
20066
|
-
({ config, iterCtx } = createWhileLoopConfig(condition,
|
|
20487
|
+
({ config, iterCtx } = createWhileLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20067
20488
|
break;
|
|
20068
20489
|
case 'until':
|
|
20069
|
-
({ config, iterCtx } = createUntilLoopConfig(condition,
|
|
20490
|
+
({ config, iterCtx } = createUntilLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20070
20491
|
break;
|
|
20071
20492
|
case 'until-event':
|
|
20072
20493
|
({ config, iterCtx } = createUntilEventLoopConfig(eventName, eventTarget, indexVariable));
|
|
@@ -21097,6 +21518,29 @@ function namedPropertyOf(node) {
|
|
|
21097
21518
|
}
|
|
21098
21519
|
return null;
|
|
21099
21520
|
}
|
|
21521
|
+
const RESTORE_KEYWORDS = new Set(['initial', 'inherit', 'unset', 'revert']);
|
|
21522
|
+
function elementsOf(value) {
|
|
21523
|
+
if (Array.isArray(value) || isNodeList(value)) {
|
|
21524
|
+
return Array.from(value).filter(isHTMLElement$2);
|
|
21525
|
+
}
|
|
21526
|
+
return isHTMLElement$2(value) ? [value] : [];
|
|
21527
|
+
}
|
|
21528
|
+
async function valueOf(node, evaluator, context) {
|
|
21529
|
+
const value = await evaluator.evaluate(node, context);
|
|
21530
|
+
const name = node.name;
|
|
21531
|
+
if (value === undefined && node.type === 'identifier' && typeof name === 'string')
|
|
21532
|
+
return name;
|
|
21533
|
+
return value;
|
|
21534
|
+
}
|
|
21535
|
+
function longestTransitionMs(css) {
|
|
21536
|
+
let longest;
|
|
21537
|
+
for (const item of css.split(',')) {
|
|
21538
|
+
const times = [...item.matchAll(/(\d*\.?\d+)(ms|s)\b/g)].map(m => parseFloat(m[1]) * (m[2] === 's' ? 1000 : 1));
|
|
21539
|
+
if (times.length > 0)
|
|
21540
|
+
longest = Math.max(longest ?? 0, times[0] + (times[1] ?? 0));
|
|
21541
|
+
}
|
|
21542
|
+
return longest;
|
|
21543
|
+
}
|
|
21100
21544
|
let TransitionCommand = (() => {
|
|
21101
21545
|
let _classDecorators = [command({ name: 'transition' })];
|
|
21102
21546
|
let _classDescriptor;
|
|
@@ -21112,11 +21556,10 @@ let TransitionCommand = (() => {
|
|
|
21112
21556
|
let property;
|
|
21113
21557
|
let target;
|
|
21114
21558
|
const firstArg = await evaluator.evaluate(raw.args[0], context);
|
|
21115
|
-
const
|
|
21116
|
-
|
|
21117
|
-
if (isHTMLElement$2(firstAsElement) ||
|
|
21559
|
+
const owners = elementsOf(firstArg);
|
|
21560
|
+
if (owners.length > 0 ||
|
|
21118
21561
|
(typeof firstArg === 'string' && /^[#.]|^(?:me|it|you)$/.test(firstArg))) {
|
|
21119
|
-
target =
|
|
21562
|
+
target = owners.length === 1 ? owners[0] : owners.length > 1 ? owners : firstArg;
|
|
21120
21563
|
property = String(await evaluator.evaluate(raw.args[1], context));
|
|
21121
21564
|
}
|
|
21122
21565
|
else if (raw.args.length >= 2) {
|
|
@@ -21128,9 +21571,9 @@ let TransitionCommand = (() => {
|
|
|
21128
21571
|
throw new Error('transition requires a CSS property');
|
|
21129
21572
|
property = named.property;
|
|
21130
21573
|
if (named.objectNode !== undefined) {
|
|
21131
|
-
const owner =
|
|
21132
|
-
if (
|
|
21133
|
-
target = owner;
|
|
21574
|
+
const owner = elementsOf(await evaluator.evaluate(named.objectNode, context));
|
|
21575
|
+
if (owner.length > 0)
|
|
21576
|
+
target = owner.length === 1 ? owner[0] : owner;
|
|
21134
21577
|
}
|
|
21135
21578
|
}
|
|
21136
21579
|
else {
|
|
@@ -21141,60 +21584,131 @@ let TransitionCommand = (() => {
|
|
|
21141
21584
|
}
|
|
21142
21585
|
if (!raw.modifiers?.to)
|
|
21143
21586
|
throw new Error('transition requires "to <value>"');
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
value
|
|
21147
|
-
}
|
|
21148
|
-
const result = { property, value: value };
|
|
21587
|
+
const result = {
|
|
21588
|
+
property,
|
|
21589
|
+
value: await valueOf(raw.modifiers.to, evaluator, context),
|
|
21590
|
+
};
|
|
21149
21591
|
if (target !== undefined)
|
|
21150
21592
|
result.target = target;
|
|
21593
|
+
if (raw.modifiers?.from)
|
|
21594
|
+
result.from = await valueOf(raw.modifiers.from, evaluator, context);
|
|
21595
|
+
if (raw.modifiers?.pairs) {
|
|
21596
|
+
result.pairs = await this.laterPairs(raw.modifiers.pairs, evaluator, context);
|
|
21597
|
+
}
|
|
21151
21598
|
if (raw.modifiers?.over)
|
|
21152
21599
|
result.duration = await evaluator.evaluate(raw.modifiers.over, context);
|
|
21153
21600
|
if (raw.modifiers?.with)
|
|
21154
21601
|
result.timingFunction = String(await evaluator.evaluate(raw.modifiers.with, context));
|
|
21602
|
+
if (raw.modifiers?.using)
|
|
21603
|
+
result.using = String(await evaluator.evaluate(raw.modifiers.using, context));
|
|
21155
21604
|
return result;
|
|
21156
21605
|
}
|
|
21606
|
+
async laterPairs(node, evaluator, context) {
|
|
21607
|
+
const pairs = [];
|
|
21608
|
+
for (const pairNode of node.elements ?? []) {
|
|
21609
|
+
const fields = new Map();
|
|
21610
|
+
const properties = pairNode
|
|
21611
|
+
.properties ?? [];
|
|
21612
|
+
for (const { key, value } of properties) {
|
|
21613
|
+
if (typeof key.name === 'string')
|
|
21614
|
+
fields.set(key.name, value);
|
|
21615
|
+
}
|
|
21616
|
+
const propertyNode = fields.get('property');
|
|
21617
|
+
const toNode = fields.get('to');
|
|
21618
|
+
if (!propertyNode || !toNode)
|
|
21619
|
+
throw new Error('transition requires property and value');
|
|
21620
|
+
const pair = {
|
|
21621
|
+
property: String(await evaluator.evaluate(propertyNode, context)),
|
|
21622
|
+
value: await valueOf(toNode, evaluator, context),
|
|
21623
|
+
};
|
|
21624
|
+
const ownerNode = fields.get('owner');
|
|
21625
|
+
if (ownerNode) {
|
|
21626
|
+
const owners = elementsOf(await evaluator.evaluate(ownerNode, context));
|
|
21627
|
+
if (owners.length === 0)
|
|
21628
|
+
throw new Error('transition: target element not found');
|
|
21629
|
+
pair.target = owners.length === 1 ? owners[0] : owners;
|
|
21630
|
+
}
|
|
21631
|
+
const fromNode = fields.get('from');
|
|
21632
|
+
if (fromNode)
|
|
21633
|
+
pair.from = await valueOf(fromNode, evaluator, context);
|
|
21634
|
+
pairs.push(pair);
|
|
21635
|
+
}
|
|
21636
|
+
return pairs;
|
|
21637
|
+
}
|
|
21157
21638
|
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);
|
|
21639
|
+
const duration = parseDuration(input.duration, (input.using !== undefined && longestTransitionMs(input.using)) || 300);
|
|
21640
|
+
const timing = input.timingFunction || 'ease';
|
|
21641
|
+
const jobs = [];
|
|
21642
|
+
for (const pair of [input, ...(input.pairs ?? [])]) {
|
|
21643
|
+
let property = pair.property;
|
|
21644
|
+
if (property.startsWith('*'))
|
|
21645
|
+
property = property.substring(1);
|
|
21646
|
+
property = camelToKebab(property);
|
|
21647
|
+
const elements = Array.isArray(pair.target)
|
|
21648
|
+
? pair.target.filter(isHTMLElement$2)
|
|
21649
|
+
: [resolveElement(pair.target, context, 'transition')];
|
|
21650
|
+
for (const element of elements) {
|
|
21651
|
+
jobs.push({
|
|
21652
|
+
element,
|
|
21653
|
+
property,
|
|
21654
|
+
pair,
|
|
21655
|
+
fromValue: getComputedStyle(element).getPropertyValue(property),
|
|
21656
|
+
toValue: '',
|
|
21657
|
+
removeInlineAfter: false,
|
|
21658
|
+
});
|
|
21659
|
+
}
|
|
21190
21660
|
}
|
|
21661
|
+
if (jobs.length === 0)
|
|
21662
|
+
throw new Error('transition: target element not found');
|
|
21663
|
+
for (const job of jobs) {
|
|
21664
|
+
if (job.pair.from !== undefined) {
|
|
21665
|
+
job.element.style.setProperty(job.property, String(job.pair.from));
|
|
21666
|
+
}
|
|
21667
|
+
}
|
|
21668
|
+
for (const job of jobs)
|
|
21669
|
+
if (job.pair.from !== undefined)
|
|
21670
|
+
void job.element.offsetWidth;
|
|
21671
|
+
const originals = new Map();
|
|
21672
|
+
for (const job of jobs) {
|
|
21673
|
+
if (!originals.has(job.element))
|
|
21674
|
+
originals.set(job.element, job.element.style.transition);
|
|
21675
|
+
}
|
|
21676
|
+
for (const [element, original] of originals) {
|
|
21677
|
+
const own = jobs
|
|
21678
|
+
.filter(job => job.element === element)
|
|
21679
|
+
.map(job => `${job.property} ${duration}ms ${timing}`);
|
|
21680
|
+
element.style.transition = input.using ?? [original, ...own].filter(Boolean).join(', ');
|
|
21681
|
+
}
|
|
21682
|
+
for (const job of jobs) {
|
|
21683
|
+
const { element, property } = job;
|
|
21684
|
+
let toValue = String(job.pair.value);
|
|
21685
|
+
if (RESTORE_KEYWORDS.has(toValue)) {
|
|
21686
|
+
const currentInline = element.style.getPropertyValue(property);
|
|
21687
|
+
element.style.removeProperty(property);
|
|
21688
|
+
toValue = getComputedStyle(element).getPropertyValue(property);
|
|
21689
|
+
if (currentInline) {
|
|
21690
|
+
element.style.setProperty(property, currentInline);
|
|
21691
|
+
}
|
|
21692
|
+
job.removeInlineAfter = true;
|
|
21693
|
+
}
|
|
21694
|
+
job.toValue = toValue;
|
|
21695
|
+
element.style.setProperty(property, toValue);
|
|
21696
|
+
}
|
|
21697
|
+
const results = await Promise.all(jobs.map(job => waitForTransitionEnd(job.element, job.property, duration)));
|
|
21698
|
+
for (const [element, original] of originals)
|
|
21699
|
+
element.style.transition = original;
|
|
21700
|
+
for (const job of jobs) {
|
|
21701
|
+
if (job.removeInlineAfter)
|
|
21702
|
+
job.element.style.removeProperty(job.property);
|
|
21703
|
+
}
|
|
21704
|
+
const first = jobs[0];
|
|
21191
21705
|
return {
|
|
21192
|
-
element:
|
|
21193
|
-
property,
|
|
21194
|
-
fromValue,
|
|
21195
|
-
toValue,
|
|
21706
|
+
element: first.element,
|
|
21707
|
+
property: first.property,
|
|
21708
|
+
fromValue: first.fromValue,
|
|
21709
|
+
toValue: first.toValue,
|
|
21196
21710
|
duration,
|
|
21197
|
-
completed: result.completed,
|
|
21711
|
+
completed: results.every(result => result.completed),
|
|
21198
21712
|
};
|
|
21199
21713
|
}
|
|
21200
21714
|
};
|
|
@@ -21207,13 +21721,16 @@ let TransitionCommand = (() => {
|
|
|
21207
21721
|
})();
|
|
21208
21722
|
_classThis.metadata = commandMeta({
|
|
21209
21723
|
description: 'Animate CSS properties using CSS transitions',
|
|
21210
|
-
syntax: 'transition [<
|
|
21724
|
+
syntax: 'transition <property> [from <value>] to <value> [<property> \u2026 to <value>]\u2026 [over <duration>] [using <css> | with <timing>]',
|
|
21211
21725
|
examples: [
|
|
21212
21726
|
'transition opacity to 0.5',
|
|
21213
21727
|
'transition my *opacity to 0 over 200ms',
|
|
21214
21728
|
"transition #box's *opacity to 0 over 200ms",
|
|
21215
21729
|
'transition left to 100px over 500ms',
|
|
21216
21730
|
'transition background-color to red over 1s with ease-in-out',
|
|
21731
|
+
'transition *width to 100px *height to 50px over 300ms',
|
|
21732
|
+
'transition *opacity of #panel from 0 to 1 over 200ms',
|
|
21733
|
+
'transition my *opacity to 0 using "opacity 1s ease-in"',
|
|
21217
21734
|
],
|
|
21218
21735
|
sideEffects: ['style-change', 'timing'],
|
|
21219
21736
|
category: 'animation',
|
|
@@ -22339,16 +22856,12 @@ class RenderCommand {
|
|
|
22339
22856
|
}
|
|
22340
22857
|
RenderCommand.metadata = commandMeta({
|
|
22341
22858
|
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
|
-
],
|
|
22859
|
+
syntax: ['render <template>', 'render <template> with <name>: <value>, ...'],
|
|
22347
22860
|
examples: [
|
|
22348
22861
|
'render myTemplate',
|
|
22349
|
-
'render myTemplate with
|
|
22350
|
-
'render "<template>Hello ${name}!</template>" with
|
|
22351
|
-
'render template with
|
|
22862
|
+
'render myTemplate with name: "Alice"',
|
|
22863
|
+
'render "<template>Hello ${name}!</template>" with name: "World"',
|
|
22864
|
+
'render template with items: data',
|
|
22352
22865
|
],
|
|
22353
22866
|
category: 'templates',
|
|
22354
22867
|
compatibility: 'standard',
|