@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.mjs
CHANGED
|
@@ -535,6 +535,75 @@ function parseAttributeWithValue(expression) {
|
|
|
535
535
|
return { name: result.name, value: result.value ?? '' };
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
+
function _parseDurationComponents(value) {
|
|
539
|
+
const trimmed = value.trim();
|
|
540
|
+
const match = trimmed.match(/^(\d+(?:\.\d+)?)\s*(s|ms|sec|seconds?|milliseconds?)?$/i);
|
|
541
|
+
if (!match) {
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
const number = parseFloat(match[1]);
|
|
545
|
+
const unit = (match[2] || 'ms').toLowerCase();
|
|
546
|
+
if (unit === 'ms' || unit === 'millisecond' || unit === 'milliseconds') {
|
|
547
|
+
return { number, milliseconds: Math.floor(number) };
|
|
548
|
+
}
|
|
549
|
+
else if (unit === 's' || unit === 'sec' || unit === 'second' || unit === 'seconds') {
|
|
550
|
+
return { number, milliseconds: Math.floor(number * 1000) };
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
function parseDuration(value, defaultMs = 300) {
|
|
555
|
+
if (typeof value === 'number') {
|
|
556
|
+
return Math.max(0, Math.floor(value));
|
|
557
|
+
}
|
|
558
|
+
if (typeof value === 'string') {
|
|
559
|
+
const result = _parseDurationComponents(value);
|
|
560
|
+
return result ? result.milliseconds : defaultMs;
|
|
561
|
+
}
|
|
562
|
+
return defaultMs;
|
|
563
|
+
}
|
|
564
|
+
function parseDurationStrict(value) {
|
|
565
|
+
if (typeof value === 'number') {
|
|
566
|
+
if (value < 0)
|
|
567
|
+
throw new Error('Duration must be >= 0');
|
|
568
|
+
return Math.floor(value);
|
|
569
|
+
}
|
|
570
|
+
if (typeof value === 'string') {
|
|
571
|
+
const result = _parseDurationComponents(value);
|
|
572
|
+
if (!result) {
|
|
573
|
+
throw new Error(`Invalid duration format: "${value}"`);
|
|
574
|
+
}
|
|
575
|
+
return result.milliseconds;
|
|
576
|
+
}
|
|
577
|
+
throw new Error(`Invalid duration type: ${typeof value}`);
|
|
578
|
+
}
|
|
579
|
+
function parseCSSDurations(durationString) {
|
|
580
|
+
if (!durationString || durationString === 'none') {
|
|
581
|
+
return [0];
|
|
582
|
+
}
|
|
583
|
+
return durationString.split(',').map(duration => {
|
|
584
|
+
const value = parseFloat(duration.trim());
|
|
585
|
+
if (isNaN(value))
|
|
586
|
+
return 0;
|
|
587
|
+
if (duration.includes('s') && !duration.includes('ms')) {
|
|
588
|
+
return value * 1000;
|
|
589
|
+
}
|
|
590
|
+
return value;
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
function calculateMaxAnimationTime(durations, delays) {
|
|
594
|
+
let maxTime = 0;
|
|
595
|
+
for (let i = 0; i < durations.length; i++) {
|
|
596
|
+
const duration = durations[i] || 0;
|
|
597
|
+
const delay = delays[i] || 0;
|
|
598
|
+
const totalTime = duration + delay;
|
|
599
|
+
maxTime = Math.max(maxTime, totalTime);
|
|
600
|
+
}
|
|
601
|
+
return maxTime;
|
|
602
|
+
}
|
|
603
|
+
function camelToKebab(str) {
|
|
604
|
+
return str.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
605
|
+
}
|
|
606
|
+
|
|
538
607
|
function batchApply(targets, operation) {
|
|
539
608
|
for (const element of targets) {
|
|
540
609
|
operation(element);
|
|
@@ -600,15 +669,18 @@ function toggleAttribute(element, name, value) {
|
|
|
600
669
|
}
|
|
601
670
|
}
|
|
602
671
|
}
|
|
672
|
+
function toCssPropertyName(property) {
|
|
673
|
+
return property.startsWith('--') ? property : camelToKebab(property);
|
|
674
|
+
}
|
|
603
675
|
function batchSetStyles(targets, styles) {
|
|
604
676
|
const entries = Object.entries(styles);
|
|
605
677
|
return batchApplyItems(targets, entries, (element, [property, value]) => {
|
|
606
|
-
element.style.setProperty(property, value);
|
|
678
|
+
element.style.setProperty(toCssPropertyName(property), value);
|
|
607
679
|
});
|
|
608
680
|
}
|
|
609
681
|
function batchRemoveStyles(targets, properties) {
|
|
610
682
|
return batchApplyItems(targets, properties, (element, property) => {
|
|
611
|
-
element.style.removeProperty(property);
|
|
683
|
+
element.style.removeProperty(toCssPropertyName(property));
|
|
612
684
|
});
|
|
613
685
|
}
|
|
614
686
|
|
|
@@ -1343,75 +1415,6 @@ let RemoveCommand = (() => {
|
|
|
1343
1415
|
})();
|
|
1344
1416
|
const createRemoveCommand = createFactory(RemoveCommand);
|
|
1345
1417
|
|
|
1346
|
-
function _parseDurationComponents(value) {
|
|
1347
|
-
const trimmed = value.trim();
|
|
1348
|
-
const match = trimmed.match(/^(\d+(?:\.\d+)?)\s*(s|ms|sec|seconds?|milliseconds?)?$/i);
|
|
1349
|
-
if (!match) {
|
|
1350
|
-
return null;
|
|
1351
|
-
}
|
|
1352
|
-
const number = parseFloat(match[1]);
|
|
1353
|
-
const unit = (match[2] || 'ms').toLowerCase();
|
|
1354
|
-
if (unit === 'ms' || unit === 'millisecond' || unit === 'milliseconds') {
|
|
1355
|
-
return { number, milliseconds: Math.floor(number) };
|
|
1356
|
-
}
|
|
1357
|
-
else if (unit === 's' || unit === 'sec' || unit === 'second' || unit === 'seconds') {
|
|
1358
|
-
return { number, milliseconds: Math.floor(number * 1000) };
|
|
1359
|
-
}
|
|
1360
|
-
return null;
|
|
1361
|
-
}
|
|
1362
|
-
function parseDuration(value, defaultMs = 300) {
|
|
1363
|
-
if (typeof value === 'number') {
|
|
1364
|
-
return Math.max(0, Math.floor(value));
|
|
1365
|
-
}
|
|
1366
|
-
if (typeof value === 'string') {
|
|
1367
|
-
const result = _parseDurationComponents(value);
|
|
1368
|
-
return result ? result.milliseconds : defaultMs;
|
|
1369
|
-
}
|
|
1370
|
-
return defaultMs;
|
|
1371
|
-
}
|
|
1372
|
-
function parseDurationStrict(value) {
|
|
1373
|
-
if (typeof value === 'number') {
|
|
1374
|
-
if (value < 0)
|
|
1375
|
-
throw new Error('Duration must be >= 0');
|
|
1376
|
-
return Math.floor(value);
|
|
1377
|
-
}
|
|
1378
|
-
if (typeof value === 'string') {
|
|
1379
|
-
const result = _parseDurationComponents(value);
|
|
1380
|
-
if (!result) {
|
|
1381
|
-
throw new Error(`Invalid duration format: "${value}"`);
|
|
1382
|
-
}
|
|
1383
|
-
return result.milliseconds;
|
|
1384
|
-
}
|
|
1385
|
-
throw new Error(`Invalid duration type: ${typeof value}`);
|
|
1386
|
-
}
|
|
1387
|
-
function parseCSSDurations(durationString) {
|
|
1388
|
-
if (!durationString || durationString === 'none') {
|
|
1389
|
-
return [0];
|
|
1390
|
-
}
|
|
1391
|
-
return durationString.split(',').map(duration => {
|
|
1392
|
-
const value = parseFloat(duration.trim());
|
|
1393
|
-
if (isNaN(value))
|
|
1394
|
-
return 0;
|
|
1395
|
-
if (duration.includes('s') && !duration.includes('ms')) {
|
|
1396
|
-
return value * 1000;
|
|
1397
|
-
}
|
|
1398
|
-
return value;
|
|
1399
|
-
});
|
|
1400
|
-
}
|
|
1401
|
-
function calculateMaxAnimationTime(durations, delays) {
|
|
1402
|
-
let maxTime = 0;
|
|
1403
|
-
for (let i = 0; i < durations.length; i++) {
|
|
1404
|
-
const duration = durations[i] || 0;
|
|
1405
|
-
const delay = delays[i] || 0;
|
|
1406
|
-
const totalTime = duration + delay;
|
|
1407
|
-
maxTime = Math.max(maxTime, totalTime);
|
|
1408
|
-
}
|
|
1409
|
-
return maxTime;
|
|
1410
|
-
}
|
|
1411
|
-
function camelToKebab(str) {
|
|
1412
|
-
return str.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
1418
|
function detectSmartElementType(elements) {
|
|
1416
1419
|
if (elements.length === 0)
|
|
1417
1420
|
return null;
|
|
@@ -1877,13 +1880,6 @@ function isFunction(value) {
|
|
|
1877
1880
|
function isInputElement$1(el) {
|
|
1878
1881
|
return (el !== null && typeof el === 'object' && 'tagName' in el && el.tagName === 'INPUT');
|
|
1879
1882
|
}
|
|
1880
|
-
function isFormElement$1(el) {
|
|
1881
|
-
if (el === null || typeof el !== 'object' || !('tagName' in el)) {
|
|
1882
|
-
return false;
|
|
1883
|
-
}
|
|
1884
|
-
const tag = el.tagName;
|
|
1885
|
-
return tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA';
|
|
1886
|
-
}
|
|
1887
1883
|
function isHTMLElement$1(el) {
|
|
1888
1884
|
return (el !== null &&
|
|
1889
1885
|
typeof el === 'object' &&
|
|
@@ -1943,7 +1939,7 @@ const SPECIAL_DOM_PROPERTIES = {
|
|
|
1943
1939
|
innertext: el => el.textContent?.trim(),
|
|
1944
1940
|
innerHTML: el => el.innerHTML,
|
|
1945
1941
|
outerhtml: el => el.outerHTML,
|
|
1946
|
-
value: el => (
|
|
1942
|
+
value: el => ('value' in el ? el.value : undefined),
|
|
1947
1943
|
checked: el => (isInputElement$1(el) ? el.checked : undefined),
|
|
1948
1944
|
disabled: el => ('disabled' in el ? el.disabled : undefined),
|
|
1949
1945
|
selected: el => (isOptionElement$1(el) ? el.selected : undefined),
|
|
@@ -2813,7 +2809,11 @@ let PutCommand = (() => {
|
|
|
2813
2809
|
}
|
|
2814
2810
|
if (isInsertableNode(v))
|
|
2815
2811
|
return v;
|
|
2816
|
-
|
|
2812
|
+
if (v == null)
|
|
2813
|
+
return 'null';
|
|
2814
|
+
if (Array.isArray(v))
|
|
2815
|
+
return arrayFragment(v);
|
|
2816
|
+
return String(v);
|
|
2817
2817
|
}
|
|
2818
2818
|
looksLikeCss(s) {
|
|
2819
2819
|
if (!s)
|
|
@@ -2898,6 +2898,19 @@ let PutCommand = (() => {
|
|
|
2898
2898
|
})();
|
|
2899
2899
|
return PutCommand = _classThis;
|
|
2900
2900
|
})();
|
|
2901
|
+
function arrayFragment(items) {
|
|
2902
|
+
const fragment = document.createDocumentFragment();
|
|
2903
|
+
for (const item of items) {
|
|
2904
|
+
if (isInsertableNode(item)) {
|
|
2905
|
+
fragment.append(item);
|
|
2906
|
+
continue;
|
|
2907
|
+
}
|
|
2908
|
+
const template = document.createElement('template');
|
|
2909
|
+
template.innerHTML = item === null ? '' : String(item);
|
|
2910
|
+
fragment.append(template.content);
|
|
2911
|
+
}
|
|
2912
|
+
return fragment;
|
|
2913
|
+
}
|
|
2901
2914
|
const createPutCommand = createFactory(PutCommand);
|
|
2902
2915
|
|
|
2903
2916
|
const GLOBAL_WRITE_HOOKS = new Set();
|
|
@@ -3020,6 +3033,16 @@ function convertToNumber(value) {
|
|
|
3020
3033
|
}
|
|
3021
3034
|
return 0;
|
|
3022
3035
|
}
|
|
3036
|
+
function counterAmount(value) {
|
|
3037
|
+
return typeof value === 'number' ? value : parseFloat(String(value));
|
|
3038
|
+
}
|
|
3039
|
+
function counterValue(value) {
|
|
3040
|
+
if (isHTMLElement$2(value)) {
|
|
3041
|
+
const element = value;
|
|
3042
|
+
return counterValue(element.value || element.textContent);
|
|
3043
|
+
}
|
|
3044
|
+
return value ? counterAmount(value) : 0;
|
|
3045
|
+
}
|
|
3023
3046
|
function getVariableValue(name, context, preferredScope) {
|
|
3024
3047
|
if (preferredScope === 'element') {
|
|
3025
3048
|
return getElementVar(context, name);
|
|
@@ -3124,35 +3147,39 @@ function setElementPropertyValue(propertyPath, value, context) {
|
|
|
3124
3147
|
element[property] = value;
|
|
3125
3148
|
}
|
|
3126
3149
|
}
|
|
3150
|
+
function isObjectOwner(value) {
|
|
3151
|
+
return (typeof value === 'object' && value !== null && !Array.isArray(value) && !isHTMLElement$2(value));
|
|
3152
|
+
}
|
|
3127
3153
|
function getCurrentNumericValue(target, property, scope, context) {
|
|
3128
3154
|
if (typeof target === 'number') {
|
|
3129
3155
|
return target;
|
|
3130
3156
|
}
|
|
3131
3157
|
if (isHTMLElement$2(target)) {
|
|
3132
3158
|
const element = target;
|
|
3159
|
+
if (property?.startsWith('@'))
|
|
3160
|
+
return counterValue(element.getAttribute(property.slice(1)));
|
|
3133
3161
|
if (property) {
|
|
3134
3162
|
if (property.startsWith('data-') ||
|
|
3135
3163
|
['id', 'class', 'title', 'alt', 'src', 'href'].includes(property)) {
|
|
3136
|
-
|
|
3137
|
-
return convertToNumber(value);
|
|
3164
|
+
return counterValue(element.getAttribute(property));
|
|
3138
3165
|
}
|
|
3139
3166
|
else {
|
|
3140
|
-
|
|
3141
|
-
return convertToNumber(value);
|
|
3167
|
+
return counterValue(element[property]);
|
|
3142
3168
|
}
|
|
3143
3169
|
}
|
|
3144
3170
|
else {
|
|
3145
|
-
|
|
3146
|
-
return convertToNumber(value);
|
|
3171
|
+
return counterValue(element);
|
|
3147
3172
|
}
|
|
3148
3173
|
}
|
|
3174
|
+
if (property && isObjectOwner(target)) {
|
|
3175
|
+
return counterValue(target[property]);
|
|
3176
|
+
}
|
|
3149
3177
|
if (typeof target === 'string') {
|
|
3150
3178
|
if (scope === 'element') {
|
|
3151
|
-
return
|
|
3179
|
+
return counterValue(getVariableValue(target, context, 'element'));
|
|
3152
3180
|
}
|
|
3153
3181
|
if (scope === 'global') {
|
|
3154
|
-
|
|
3155
|
-
return convertToNumber(value);
|
|
3182
|
+
return counterValue(getVariableValue(target, context, 'global'));
|
|
3156
3183
|
}
|
|
3157
3184
|
if (target.includes('.')) {
|
|
3158
3185
|
return getElementPropertyValue(target, context);
|
|
@@ -3166,14 +3193,17 @@ function getCurrentNumericValue(target, property, scope, context) {
|
|
|
3166
3193
|
else if (target === 'you' && context.you) {
|
|
3167
3194
|
return convertToNumber(context.you.value || 0);
|
|
3168
3195
|
}
|
|
3169
|
-
|
|
3170
|
-
return convertToNumber(value);
|
|
3196
|
+
return counterValue(getVariableValue(target, context));
|
|
3171
3197
|
}
|
|
3172
|
-
return
|
|
3198
|
+
return counterValue(target);
|
|
3173
3199
|
}
|
|
3174
3200
|
function setTargetValue(target, property, scope, newValue, context) {
|
|
3175
3201
|
if (isHTMLElement$2(target)) {
|
|
3176
3202
|
const element = target;
|
|
3203
|
+
if (property?.startsWith('@')) {
|
|
3204
|
+
element.setAttribute(property.slice(1), String(newValue));
|
|
3205
|
+
return;
|
|
3206
|
+
}
|
|
3177
3207
|
if (property) {
|
|
3178
3208
|
if (property.startsWith('data-') ||
|
|
3179
3209
|
['id', 'class', 'title', 'alt', 'src', 'href'].includes(property)) {
|
|
@@ -3193,6 +3223,10 @@ function setTargetValue(target, property, scope, newValue, context) {
|
|
|
3193
3223
|
}
|
|
3194
3224
|
return;
|
|
3195
3225
|
}
|
|
3226
|
+
if (property && isObjectOwner(target)) {
|
|
3227
|
+
target[property] = newValue;
|
|
3228
|
+
return;
|
|
3229
|
+
}
|
|
3196
3230
|
if (typeof target === 'string') {
|
|
3197
3231
|
if (scope === 'element') {
|
|
3198
3232
|
setVariableValue(target, newValue, context, 'element');
|
|
@@ -3967,6 +4001,39 @@ function makeTypeCheckHandler(negated) {
|
|
|
3967
4001
|
};
|
|
3968
4002
|
};
|
|
3969
4003
|
}
|
|
4004
|
+
const OF_OPERAND_BP = 70;
|
|
4005
|
+
function parseOfOperand(ctx, minBp = OF_OPERAND_BP) {
|
|
4006
|
+
let right = ctx.parseExpr(minBp);
|
|
4007
|
+
if (ctx.peek()?.value === 'in') {
|
|
4008
|
+
const inToken = ctx.advance();
|
|
4009
|
+
const scope = ctx.parseExpr(minBp);
|
|
4010
|
+
right = {
|
|
4011
|
+
type: 'binaryExpression',
|
|
4012
|
+
operator: 'in',
|
|
4013
|
+
left: right,
|
|
4014
|
+
right: scope,
|
|
4015
|
+
start: right.start,
|
|
4016
|
+
end: scope.end ?? inToken.end,
|
|
4017
|
+
line: right.line ?? inToken.line,
|
|
4018
|
+
column: right.column ?? inToken.column,
|
|
4019
|
+
};
|
|
4020
|
+
}
|
|
4021
|
+
return right;
|
|
4022
|
+
}
|
|
4023
|
+
const THE_OF_TARGET_BP = OF_OPERAND_BP + 1;
|
|
4024
|
+
function ofHandler(left, token, ctx) {
|
|
4025
|
+
const right = parseOfOperand(ctx);
|
|
4026
|
+
return {
|
|
4027
|
+
type: 'binaryExpression',
|
|
4028
|
+
operator: token.value,
|
|
4029
|
+
left,
|
|
4030
|
+
right,
|
|
4031
|
+
start: left.start,
|
|
4032
|
+
end: right.end ?? token.end,
|
|
4033
|
+
line: left.line ?? token.line,
|
|
4034
|
+
column: left.column ?? token.column,
|
|
4035
|
+
};
|
|
4036
|
+
}
|
|
3970
4037
|
const PARSER_COMPARISON_FRAGMENT = new Map([
|
|
3971
4038
|
['===', leftAssoc(30)],
|
|
3972
4039
|
['!==', leftAssoc(30)],
|
|
@@ -4011,7 +4078,7 @@ const PARSER_COMPARISON_FRAGMENT = new Map([
|
|
|
4011
4078
|
['is greater than or equal to', leftAssoc(30)],
|
|
4012
4079
|
['is less than or equal to', leftAssoc(30)],
|
|
4013
4080
|
['in', leftAssoc(30)],
|
|
4014
|
-
['of',
|
|
4081
|
+
['of', { infix: { bp: [90, OF_OPERAND_BP], handler: ofHandler } }],
|
|
4015
4082
|
['really', leftAssoc(30)],
|
|
4016
4083
|
[
|
|
4017
4084
|
'exists',
|
|
@@ -4102,6 +4169,89 @@ function getRegisteredNodeWriter(type) {
|
|
|
4102
4169
|
return NODE_WRITERS.get(type);
|
|
4103
4170
|
}
|
|
4104
4171
|
|
|
4172
|
+
function beepValues(me, values) {
|
|
4173
|
+
const outputs = values.map(describeBeepValue);
|
|
4174
|
+
const shown = outputs.filter(output => announce(me, output.value));
|
|
4175
|
+
if (shown.length === 0)
|
|
4176
|
+
return outputs;
|
|
4177
|
+
console.group('\ud83d\udd14 beep! Debug Output');
|
|
4178
|
+
for (const output of shown) {
|
|
4179
|
+
console.log(`Value:`, output.value);
|
|
4180
|
+
console.log(`Type:`, output.type);
|
|
4181
|
+
console.log(`Representation:`, output.representation);
|
|
4182
|
+
console.log('---');
|
|
4183
|
+
}
|
|
4184
|
+
console.groupEnd();
|
|
4185
|
+
return outputs;
|
|
4186
|
+
}
|
|
4187
|
+
function announce(me, value) {
|
|
4188
|
+
const target = me;
|
|
4189
|
+
if (typeof CustomEvent !== 'function' || typeof target?.dispatchEvent !== 'function')
|
|
4190
|
+
return true;
|
|
4191
|
+
return target.dispatchEvent(new CustomEvent('hyperscript:beep', {
|
|
4192
|
+
bubbles: true,
|
|
4193
|
+
cancelable: true,
|
|
4194
|
+
detail: { element: me, value },
|
|
4195
|
+
}));
|
|
4196
|
+
}
|
|
4197
|
+
function describeBeepValue(value) {
|
|
4198
|
+
return { value, type: typeOf(value), representation: representationOf(value) };
|
|
4199
|
+
}
|
|
4200
|
+
function typeOf(value) {
|
|
4201
|
+
if (value === null)
|
|
4202
|
+
return 'null';
|
|
4203
|
+
if (value === undefined)
|
|
4204
|
+
return 'undefined';
|
|
4205
|
+
if (Array.isArray(value))
|
|
4206
|
+
return 'array';
|
|
4207
|
+
if (isHTMLElement$2(value))
|
|
4208
|
+
return 'HTMLElement';
|
|
4209
|
+
if (typeof Element !== 'undefined' && value instanceof Element)
|
|
4210
|
+
return 'Element';
|
|
4211
|
+
if (typeof Node !== 'undefined' && value instanceof Node)
|
|
4212
|
+
return 'Node';
|
|
4213
|
+
if (value instanceof Error)
|
|
4214
|
+
return 'Error';
|
|
4215
|
+
if (value instanceof Date)
|
|
4216
|
+
return 'Date';
|
|
4217
|
+
if (value instanceof RegExp)
|
|
4218
|
+
return 'RegExp';
|
|
4219
|
+
return typeof value;
|
|
4220
|
+
}
|
|
4221
|
+
function representationOf(value) {
|
|
4222
|
+
if (value === null)
|
|
4223
|
+
return 'null';
|
|
4224
|
+
if (value === undefined)
|
|
4225
|
+
return 'undefined';
|
|
4226
|
+
if (Array.isArray(value)) {
|
|
4227
|
+
return `Array(${value.length}) [${value
|
|
4228
|
+
.slice(0, 3)
|
|
4229
|
+
.map(v => representationOf(v))
|
|
4230
|
+
.join(', ')}${value.length > 3 ? '...' : ''}]`;
|
|
4231
|
+
}
|
|
4232
|
+
if (isHTMLElement$2(value)) {
|
|
4233
|
+
const el = value;
|
|
4234
|
+
const tag = el.tagName.toLowerCase();
|
|
4235
|
+
const id = el.id ? `#${el.id}` : '';
|
|
4236
|
+
const classes = el.className ? `.${el.className.split(' ').join('.')}` : '';
|
|
4237
|
+
return `<${tag}${id}${classes}/>`;
|
|
4238
|
+
}
|
|
4239
|
+
if (value instanceof Error)
|
|
4240
|
+
return `Error: ${value.message}`;
|
|
4241
|
+
if (typeof value === 'string')
|
|
4242
|
+
return value.length > 50 ? `"${value.substring(0, 47)}..."` : `"${value}"`;
|
|
4243
|
+
if (typeof value === 'object') {
|
|
4244
|
+
try {
|
|
4245
|
+
const keys = Object.keys(value);
|
|
4246
|
+
return `Object {${keys.slice(0, 3).join(', ')}${keys.length > 3 ? '...' : ''}}`;
|
|
4247
|
+
}
|
|
4248
|
+
catch {
|
|
4249
|
+
return '[Object]';
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
return String(value);
|
|
4253
|
+
}
|
|
4254
|
+
|
|
4105
4255
|
const NUMBER_WORDS = {
|
|
4106
4256
|
1: 'one',
|
|
4107
4257
|
2: 'two',
|
|
@@ -4703,14 +4853,15 @@ const closestExpression = {
|
|
|
4703
4853
|
if (typeof selector !== 'string') {
|
|
4704
4854
|
throw new Error('closest requires a string selector');
|
|
4705
4855
|
}
|
|
4706
|
-
|
|
4856
|
+
const start = args.length > 1 ? args[1] : context.me;
|
|
4857
|
+
if (!(start instanceof Element)) {
|
|
4707
4858
|
return null;
|
|
4708
4859
|
}
|
|
4709
|
-
return
|
|
4860
|
+
return start.closest(selector);
|
|
4710
4861
|
},
|
|
4711
4862
|
validate(args) {
|
|
4712
|
-
if (args.length !== 1) {
|
|
4713
|
-
return 'closest requires
|
|
4863
|
+
if (args.length !== 1 && args.length !== 2) {
|
|
4864
|
+
return 'closest requires a selector and, optionally, the element to start from';
|
|
4714
4865
|
}
|
|
4715
4866
|
const arg = args[0];
|
|
4716
4867
|
if (typeof arg === 'string')
|
|
@@ -7096,7 +7247,7 @@ const isEmptyExpression = {
|
|
|
7096
7247
|
else if (value instanceof Node || value instanceof Element)
|
|
7097
7248
|
result = false;
|
|
7098
7249
|
else if (isObject(value))
|
|
7099
|
-
result =
|
|
7250
|
+
result = value.length === 0;
|
|
7100
7251
|
else
|
|
7101
7252
|
result = false;
|
|
7102
7253
|
return result;
|
|
@@ -8173,6 +8324,48 @@ function parseMaybeNamedArgument(ctx) {
|
|
|
8173
8324
|
const value = ctx.parseExpression();
|
|
8174
8325
|
return name !== undefined ? { name, value } : { value };
|
|
8175
8326
|
}
|
|
8327
|
+
function isNakedNamedArgStart(ctx) {
|
|
8328
|
+
if (ctx.check('{'))
|
|
8329
|
+
return false;
|
|
8330
|
+
if (!ctx.checkIdentifierLike())
|
|
8331
|
+
return false;
|
|
8332
|
+
const next = ctx.peekAt(1);
|
|
8333
|
+
return next !== null && next.value === ':';
|
|
8334
|
+
}
|
|
8335
|
+
function parseNakedNamedArgs(ctx, parseValue, command) {
|
|
8336
|
+
const properties = [];
|
|
8337
|
+
const startPos = ctx.getPosition();
|
|
8338
|
+
do {
|
|
8339
|
+
if (!ctx.checkIdentifierLike())
|
|
8340
|
+
break;
|
|
8341
|
+
const keyToken = ctx.advance();
|
|
8342
|
+
const key = {
|
|
8343
|
+
type: 'identifier',
|
|
8344
|
+
name: keyToken.value,
|
|
8345
|
+
start: keyToken.start,
|
|
8346
|
+
end: keyToken.end,
|
|
8347
|
+
line: keyToken.line,
|
|
8348
|
+
column: keyToken.column,
|
|
8349
|
+
};
|
|
8350
|
+
ctx.consume(':', `Expected ':' after property name in ${command} named arguments`);
|
|
8351
|
+
const value = parseValue();
|
|
8352
|
+
if (value) {
|
|
8353
|
+
properties.push({ key, value });
|
|
8354
|
+
}
|
|
8355
|
+
} while (ctx.match(',') && !ctx.isAtEnd());
|
|
8356
|
+
const endPos = ctx.getPosition();
|
|
8357
|
+
return {
|
|
8358
|
+
type: 'objectLiteral',
|
|
8359
|
+
properties,
|
|
8360
|
+
start: startPos.start,
|
|
8361
|
+
end: endPos.end,
|
|
8362
|
+
line: startPos.line,
|
|
8363
|
+
column: startPos.column,
|
|
8364
|
+
};
|
|
8365
|
+
}
|
|
8366
|
+
function isGluedBeepBang(beep, bang) {
|
|
8367
|
+
return beep?.value === 'beep' && bang?.value === '!' && bang.start === beep.end;
|
|
8368
|
+
}
|
|
8176
8369
|
|
|
8177
8370
|
class CommandNodeBuilder {
|
|
8178
8371
|
constructor(name) {
|
|
@@ -8374,6 +8567,8 @@ function parseTriggerCommand(ctx, identifierNode) {
|
|
|
8374
8567
|
const modifiers = {};
|
|
8375
8568
|
while (!isCommandBoundary(ctx)) {
|
|
8376
8569
|
if (ctx.check(KEYWORDS.ON) || ctx.check(KEYWORDS.TO)) {
|
|
8570
|
+
if (modifiers['on'])
|
|
8571
|
+
break;
|
|
8377
8572
|
ctx.advance();
|
|
8378
8573
|
const target = parseOneArgument(ctx, [KEYWORDS.WITH]);
|
|
8379
8574
|
if (target)
|
|
@@ -8514,6 +8709,9 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
8514
8709
|
ctx.advance();
|
|
8515
8710
|
loopType = KEYWORDS.FOREVER;
|
|
8516
8711
|
}
|
|
8712
|
+
else if (ctx.checkIsCommand() || ctx.isCommand(ctx.peek().value)) {
|
|
8713
|
+
loopType = KEYWORDS.FOREVER;
|
|
8714
|
+
}
|
|
8517
8715
|
else {
|
|
8518
8716
|
times = ctx.parseExpression();
|
|
8519
8717
|
if (ctx.check(KEYWORDS.TIMES)) {
|
|
@@ -8556,10 +8754,12 @@ function parseRepeatCommand(ctx, commandToken) {
|
|
|
8556
8754
|
loopType = result.terminator;
|
|
8557
8755
|
ctx.advance();
|
|
8558
8756
|
condition = ctx.parseExpression();
|
|
8559
|
-
if (
|
|
8757
|
+
if (ctx.check('end')) {
|
|
8758
|
+
ctx.advance();
|
|
8759
|
+
}
|
|
8760
|
+
else if (!ctx.atEndOfInput()) {
|
|
8560
8761
|
throw new Error('Expected "end" to close repeat block');
|
|
8561
8762
|
}
|
|
8562
|
-
ctx.advance();
|
|
8563
8763
|
}
|
|
8564
8764
|
}
|
|
8565
8765
|
else {
|
|
@@ -8805,7 +9005,7 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
8805
9005
|
}));
|
|
8806
9006
|
}
|
|
8807
9007
|
}
|
|
8808
|
-
if (!consumedElseIf && !ctx.
|
|
9008
|
+
if (!consumedElseIf && !ctx.atEndOfInput()) {
|
|
8809
9009
|
ctx.consume(KEYWORDS.END, "Expected 'end' after if block");
|
|
8810
9010
|
}
|
|
8811
9011
|
}
|
|
@@ -8830,7 +9030,6 @@ function parseIfCommand(ctx, commandToken) {
|
|
|
8830
9030
|
.build();
|
|
8831
9031
|
}
|
|
8832
9032
|
function parseForCommand(ctx, commandToken) {
|
|
8833
|
-
const args = [];
|
|
8834
9033
|
let variable = null;
|
|
8835
9034
|
let collection = null;
|
|
8836
9035
|
if (ctx.check(KEYWORDS.EACH)) {
|
|
@@ -8873,31 +9072,22 @@ function parseForCommand(ctx, commandToken) {
|
|
|
8873
9072
|
}
|
|
8874
9073
|
}
|
|
8875
9074
|
const commands = ctx.parseCommandListUntilEnd('for');
|
|
8876
|
-
|
|
8877
|
-
type: 'identifier',
|
|
8878
|
-
name: 'for',
|
|
8879
|
-
start: commandToken.start,
|
|
8880
|
-
end: commandToken.end,
|
|
8881
|
-
line: commandToken.line,
|
|
8882
|
-
column: commandToken.column,
|
|
8883
|
-
});
|
|
8884
|
-
const forPos = {
|
|
9075
|
+
const pos = {
|
|
8885
9076
|
start: commandToken.start,
|
|
8886
9077
|
end: commandToken.end,
|
|
8887
9078
|
line: commandToken.line,
|
|
8888
9079
|
column: commandToken.column,
|
|
8889
9080
|
};
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
}
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
.withArgs(...args)
|
|
9081
|
+
const modifiers = {
|
|
9082
|
+
loopType: toLegacyExpression(createStringLiteral(KEYWORDS.FOR, pos)),
|
|
9083
|
+
for: toLegacyExpression(createStringLiteral(variable, pos)),
|
|
9084
|
+
in: collection,
|
|
9085
|
+
};
|
|
9086
|
+
if (indexVariable)
|
|
9087
|
+
modifiers['index'] = toLegacyExpression(createStringLiteral(indexVariable, pos));
|
|
9088
|
+
return CommandNodeBuilder.from({ ...commandToken, value: 'repeat' })
|
|
9089
|
+
.withArgs(createBlock(commands, { ...pos, end: pos.end || 0 }))
|
|
9090
|
+
.withModifiers(modifiers)
|
|
8901
9091
|
.endingAt(ctx.getPosition())
|
|
8902
9092
|
.build();
|
|
8903
9093
|
}
|
|
@@ -8953,86 +9143,159 @@ function parseMeasureCommand(ctx, identifierNode) {
|
|
|
8953
9143
|
}
|
|
8954
9144
|
return builder.build();
|
|
8955
9145
|
}
|
|
8956
|
-
const
|
|
9146
|
+
const CONTEXT_REFS = new Set(['me', 'it', 'you', 'result']);
|
|
8957
9147
|
function parseTransitionCommand(ctx, commandToken) {
|
|
8958
|
-
const
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
const
|
|
8963
|
-
const
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
if (
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
|
|
8973
|
-
target = parsed.object;
|
|
8974
|
-
property = {
|
|
8975
|
-
type: 'string',
|
|
8976
|
-
value: parsed.property.name,
|
|
8977
|
-
start: leadToken.start || 0,
|
|
8978
|
-
end: ctx.getPosition().end,
|
|
8979
|
-
line: leadToken.line,
|
|
8980
|
-
column: leadToken.column,
|
|
8981
|
-
};
|
|
9148
|
+
const pairs = [];
|
|
9149
|
+
do {
|
|
9150
|
+
pairs.push(parseTransitionPair(ctx));
|
|
9151
|
+
} while (startsAnotherPair(ctx));
|
|
9152
|
+
const [first, ...rest] = pairs;
|
|
9153
|
+
const args = first.owner ? [first.owner, first.property] : [first.property];
|
|
9154
|
+
const modifiers = { to: first.to };
|
|
9155
|
+
if (first.from)
|
|
9156
|
+
modifiers['from'] = first.from;
|
|
9157
|
+
if (rest.length > 0)
|
|
9158
|
+
modifiers['pairs'] = pairsNode(rest);
|
|
9159
|
+
for (let i = 0; i < 3 && !ctx.isAtEnd(); i++) {
|
|
9160
|
+
if (ctx.check('over') && !modifiers['over']) {
|
|
9161
|
+
ctx.advance();
|
|
9162
|
+
modifiers['over'] = ctx.parseExpression();
|
|
8982
9163
|
}
|
|
8983
|
-
else {
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
ctx.advance();
|
|
9164
|
+
else if (ctx.check('using') && !modifiers['using']) {
|
|
9165
|
+
ctx.advance();
|
|
9166
|
+
modifiers['using'] = ctx.parseExpression();
|
|
8987
9167
|
}
|
|
8988
|
-
|
|
8989
|
-
const firstToken = ctx.peek();
|
|
8990
|
-
if (!property && (isIdentifierLike(firstToken) || firstToken.value === '*')) {
|
|
8991
|
-
let propertyValue = '';
|
|
8992
|
-
if (ctx.check('*')) {
|
|
8993
|
-
propertyValue = '*';
|
|
9168
|
+
else if (ctx.check(KEYWORDS.WITH) && !modifiers['with']) {
|
|
8994
9169
|
ctx.advance();
|
|
9170
|
+
modifiers['with'] = ctx.parsePrimary();
|
|
8995
9171
|
}
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
propertyValue += hyphenatedName;
|
|
8999
|
-
property = {
|
|
9000
|
-
type: 'string',
|
|
9001
|
-
value: propertyValue,
|
|
9002
|
-
start: firstToken.start || 0,
|
|
9003
|
-
end: ctx.getPosition().end,
|
|
9004
|
-
line: firstToken.line,
|
|
9005
|
-
column: firstToken.column,
|
|
9006
|
-
};
|
|
9172
|
+
else {
|
|
9173
|
+
break;
|
|
9007
9174
|
}
|
|
9008
9175
|
}
|
|
9009
|
-
|
|
9010
|
-
|
|
9176
|
+
return CommandNodeBuilder.from(commandToken)
|
|
9177
|
+
.withArgs(...args)
|
|
9178
|
+
.withModifiers(modifiers)
|
|
9179
|
+
.endingAt(ctx.getPosition())
|
|
9180
|
+
.build();
|
|
9181
|
+
}
|
|
9182
|
+
function parseTransitionPair(ctx) {
|
|
9183
|
+
const { owner, property } = parseTransitionProperty(ctx);
|
|
9184
|
+
let from = null;
|
|
9185
|
+
if (ctx.check('from')) {
|
|
9186
|
+
ctx.advance();
|
|
9187
|
+
from = ctx.parseExpression();
|
|
9011
9188
|
}
|
|
9012
|
-
if (target)
|
|
9013
|
-
args.push(target);
|
|
9014
|
-
args.push(property);
|
|
9015
9189
|
if (!ctx.check(KEYWORDS.TO)) {
|
|
9016
9190
|
throw new Error('Expected "to" keyword after property in transition command');
|
|
9017
9191
|
}
|
|
9018
9192
|
ctx.advance();
|
|
9019
|
-
const
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9193
|
+
const to = ctx.parseExpression();
|
|
9194
|
+
return { owner, property, from, to };
|
|
9195
|
+
}
|
|
9196
|
+
function parseTransitionProperty(ctx) {
|
|
9197
|
+
const lead = ctx.peek();
|
|
9198
|
+
if (!lead || isKeyword(lead, [KEYWORDS.TO, 'from'])) {
|
|
9199
|
+
throw new Error('Transition command requires a CSS property');
|
|
9025
9200
|
}
|
|
9026
|
-
|
|
9201
|
+
const expr = ctx.parseExpression();
|
|
9202
|
+
const split = splitStyleExpression(expr);
|
|
9203
|
+
if (split)
|
|
9204
|
+
return { owner: split.owner, property: propertyNode(split.name, lead, ctx) };
|
|
9205
|
+
let name = '';
|
|
9206
|
+
if (ctx.check('*')) {
|
|
9207
|
+
name = '*';
|
|
9027
9208
|
ctx.advance();
|
|
9028
|
-
const timingFunction = ctx.parsePrimary();
|
|
9029
|
-
modifiers['with'] = timingFunction;
|
|
9030
9209
|
}
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9210
|
+
const hyphenated = parseHyphenatedName(ctx);
|
|
9211
|
+
if (!hyphenated)
|
|
9212
|
+
throw new Error('Transition command requires a CSS property');
|
|
9213
|
+
return { owner: expr, property: propertyNode(name + hyphenated, lead, ctx) };
|
|
9214
|
+
}
|
|
9215
|
+
function splitStyleExpression(node) {
|
|
9216
|
+
const n = node;
|
|
9217
|
+
switch (n.type) {
|
|
9218
|
+
case 'selector':
|
|
9219
|
+
return typeof n.value === 'string' && n.value.startsWith('*')
|
|
9220
|
+
? { owner: null, name: n.value }
|
|
9221
|
+
: null;
|
|
9222
|
+
case 'identifier':
|
|
9223
|
+
return typeof n.name === 'string' && !CONTEXT_REFS.has(n.name)
|
|
9224
|
+
? { owner: null, name: n.name }
|
|
9225
|
+
: null;
|
|
9226
|
+
case 'possessiveExpression':
|
|
9227
|
+
case 'memberExpression':
|
|
9228
|
+
return !n.computed && n.object && typeof n.property?.name === 'string'
|
|
9229
|
+
? { owner: n.object, name: n.property.name }
|
|
9230
|
+
: null;
|
|
9231
|
+
case 'binaryExpression': {
|
|
9232
|
+
if (n.operator !== 'of' || !n.left || !n.right)
|
|
9233
|
+
return null;
|
|
9234
|
+
const inner = splitStyleExpression(n.left);
|
|
9235
|
+
return inner && !inner.owner ? { owner: n.right, name: inner.name } : null;
|
|
9236
|
+
}
|
|
9237
|
+
case 'propertyOfExpression':
|
|
9238
|
+
return n.target && typeof n.property?.name === 'string'
|
|
9239
|
+
? { owner: n.target, name: n.property.name }
|
|
9240
|
+
: null;
|
|
9241
|
+
default:
|
|
9242
|
+
return null;
|
|
9243
|
+
}
|
|
9244
|
+
}
|
|
9245
|
+
function propertyNode(name, lead, ctx) {
|
|
9246
|
+
return {
|
|
9247
|
+
type: 'string',
|
|
9248
|
+
value: name,
|
|
9249
|
+
start: lead.start || 0,
|
|
9250
|
+
end: ctx.getPosition().end,
|
|
9251
|
+
line: lead.line,
|
|
9252
|
+
column: lead.column,
|
|
9253
|
+
};
|
|
9254
|
+
}
|
|
9255
|
+
function startsAnotherPair(ctx) {
|
|
9256
|
+
if (ctx.isAtEnd() || isComment(ctx.peek()))
|
|
9257
|
+
return false;
|
|
9258
|
+
if (isKeyword(ctx.peek(), ['over', 'using', KEYWORDS.WITH]))
|
|
9259
|
+
return false;
|
|
9260
|
+
return !isCommandBoundary(ctx, ['catch', 'finally', 'on']);
|
|
9261
|
+
}
|
|
9262
|
+
function pairsNode(pairs) {
|
|
9263
|
+
const field = (name, value) => ({
|
|
9264
|
+
key: {
|
|
9265
|
+
type: 'identifier',
|
|
9266
|
+
name,
|
|
9267
|
+
start: value.start,
|
|
9268
|
+
end: value.end,
|
|
9269
|
+
line: value.line,
|
|
9270
|
+
column: value.column,
|
|
9271
|
+
},
|
|
9272
|
+
value,
|
|
9273
|
+
});
|
|
9274
|
+
const elements = pairs.map(pair => {
|
|
9275
|
+
const properties = [field('property', pair.property), field('to', pair.to)];
|
|
9276
|
+
if (pair.owner)
|
|
9277
|
+
properties.push(field('owner', pair.owner));
|
|
9278
|
+
if (pair.from)
|
|
9279
|
+
properties.push(field('from', pair.from));
|
|
9280
|
+
return {
|
|
9281
|
+
type: 'objectLiteral',
|
|
9282
|
+
properties,
|
|
9283
|
+
start: (pair.owner ?? pair.property).start,
|
|
9284
|
+
end: pair.to.end,
|
|
9285
|
+
line: (pair.owner ?? pair.property).line,
|
|
9286
|
+
column: (pair.owner ?? pair.property).column,
|
|
9287
|
+
};
|
|
9288
|
+
});
|
|
9289
|
+
const firstEl = elements[0];
|
|
9290
|
+
const lastEl = elements[elements.length - 1];
|
|
9291
|
+
return {
|
|
9292
|
+
type: 'arrayLiteral',
|
|
9293
|
+
elements,
|
|
9294
|
+
start: firstEl.start,
|
|
9295
|
+
end: lastEl.end,
|
|
9296
|
+
line: firstEl.line,
|
|
9297
|
+
column: firstEl.column,
|
|
9298
|
+
};
|
|
9036
9299
|
}
|
|
9037
9300
|
function parseStartCommand(ctx, identifierNode) {
|
|
9038
9301
|
if (!ctx.match('view')) {
|
|
@@ -9152,6 +9415,15 @@ function parseToggleCommand(ctx, identifierNode) {
|
|
|
9152
9415
|
args.push(classArg.expression);
|
|
9153
9416
|
modifiers['as'] = literalModifier(mode);
|
|
9154
9417
|
}
|
|
9418
|
+
else if (classArg?.type === 'binaryExpression' &&
|
|
9419
|
+
classArg.operator === 'of' &&
|
|
9420
|
+
classArg.left?.type === 'selector' &&
|
|
9421
|
+
typeof classArg.left.value === 'string' &&
|
|
9422
|
+
classArg.left.value.startsWith('*') &&
|
|
9423
|
+
classArg.right) {
|
|
9424
|
+
args.push(classArg.left);
|
|
9425
|
+
modifiers['on'] = classArg.right;
|
|
9426
|
+
}
|
|
9155
9427
|
else if (classArg) {
|
|
9156
9428
|
args.push(classArg);
|
|
9157
9429
|
}
|
|
@@ -9329,11 +9601,17 @@ function parseSwapCommand(ctx, identifierNode) {
|
|
|
9329
9601
|
const targetExpr = isDelete ? ctx.parseExpression() : parseOneArgument(ctx, [KEYWORDS.WITH]);
|
|
9330
9602
|
if (targetExpr)
|
|
9331
9603
|
args.push(targetExpr);
|
|
9332
|
-
|
|
9604
|
+
const isMorph = identifierNode.name === 'morph';
|
|
9605
|
+
if (!isDelete &&
|
|
9606
|
+
(consumeOptionalKeyword(ctx, KEYWORDS.WITH) ||
|
|
9607
|
+
(isMorph && consumeOptionalKeyword(ctx, KEYWORDS.TO)))) {
|
|
9333
9608
|
const contentExpr = parseOneArgument(ctx, ['using']);
|
|
9334
9609
|
if (contentExpr)
|
|
9335
9610
|
modifiers['with'] = contentExpr;
|
|
9336
9611
|
}
|
|
9612
|
+
if (isMorph && modifiers['with'] === undefined) {
|
|
9613
|
+
ctx.addError("Expected 'to' and the content to morph into");
|
|
9614
|
+
}
|
|
9337
9615
|
return CommandNodeBuilder.fromIdentifier(identifierNode)
|
|
9338
9616
|
.withArgs(...args)
|
|
9339
9617
|
.withModifiers({ ...modifiers, ...parseViewTransitionTail(ctx) })
|
|
@@ -10094,6 +10372,8 @@ function atArgumentBoundary(ctx, grammar) {
|
|
|
10094
10372
|
const next = ctx.peek();
|
|
10095
10373
|
if (ctx.checkIsCommand() && ctx.peekAt(1)?.value === '(')
|
|
10096
10374
|
return false;
|
|
10375
|
+
if (isGluedBeepBang(next, ctx.peekAt(1)))
|
|
10376
|
+
return false;
|
|
10097
10377
|
if (isCommandBoundary(ctx, ['catch', 'finally', 'on']))
|
|
10098
10378
|
return true;
|
|
10099
10379
|
return isKeyword(next, [...grammar.markers]);
|
|
@@ -10125,10 +10405,13 @@ function parseDeclaredCommand(ctx, commandToken, name, grammar) {
|
|
|
10125
10405
|
}
|
|
10126
10406
|
}
|
|
10127
10407
|
const commaList = new Set(grammar.commaList ?? []);
|
|
10408
|
+
const namedArgs = new Set(grammar.namedArgs ?? []);
|
|
10128
10409
|
while (!ctx.isAtEnd() && isKeyword(ctx.peek(), [...grammar.markers])) {
|
|
10129
10410
|
const keyword = ctx.advance().value;
|
|
10130
10411
|
const key = ctx.resolveKeyword(keyword).toLowerCase();
|
|
10131
|
-
let value =
|
|
10412
|
+
let value = namedArgs.has(key) && isNakedNamedArgStart(ctx)
|
|
10413
|
+
? parseNakedNamedArgs(ctx, () => ctx.parseExpression(), name)
|
|
10414
|
+
: ctx.parseExpression();
|
|
10132
10415
|
if (value && commaList.has(key) && ctx.check(',')) {
|
|
10133
10416
|
const elements = [value];
|
|
10134
10417
|
while (ctx.match(',')) {
|
|
@@ -10293,8 +10576,8 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10293
10576
|
}
|
|
10294
10577
|
if (ctx.check('with') && !modifiers['with']) {
|
|
10295
10578
|
ctx.advance();
|
|
10296
|
-
if (
|
|
10297
|
-
modifiers['with'] =
|
|
10579
|
+
if (isNakedNamedArgStart(ctx)) {
|
|
10580
|
+
modifiers['with'] = parseNakedNamedArgs(ctx, () => ctx.parsePrimary(), 'fetch');
|
|
10298
10581
|
}
|
|
10299
10582
|
else {
|
|
10300
10583
|
modifiers['with'] = ctx.parsePrimary();
|
|
@@ -10329,45 +10612,6 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10329
10612
|
}
|
|
10330
10613
|
return builder.build();
|
|
10331
10614
|
}
|
|
10332
|
-
function isFetchNakedNamedArgStart(ctx) {
|
|
10333
|
-
if (ctx.check('{'))
|
|
10334
|
-
return false;
|
|
10335
|
-
if (!ctx.checkIdentifierLike())
|
|
10336
|
-
return false;
|
|
10337
|
-
const next = ctx.peekAt(1);
|
|
10338
|
-
return next !== null && next.value === ':';
|
|
10339
|
-
}
|
|
10340
|
-
function parseFetchNakedNamedArgs(ctx) {
|
|
10341
|
-
const properties = [];
|
|
10342
|
-
const startPos = ctx.getPosition();
|
|
10343
|
-
do {
|
|
10344
|
-
if (!ctx.checkIdentifierLike())
|
|
10345
|
-
break;
|
|
10346
|
-
const keyToken = ctx.advance();
|
|
10347
|
-
const key = {
|
|
10348
|
-
type: 'identifier',
|
|
10349
|
-
name: keyToken.value,
|
|
10350
|
-
start: keyToken.start,
|
|
10351
|
-
end: keyToken.end,
|
|
10352
|
-
line: keyToken.line,
|
|
10353
|
-
column: keyToken.column,
|
|
10354
|
-
};
|
|
10355
|
-
ctx.consume(':', "Expected ':' after property name in fetch named arguments");
|
|
10356
|
-
const value = ctx.parsePrimary();
|
|
10357
|
-
if (value) {
|
|
10358
|
-
properties.push({ key, value });
|
|
10359
|
-
}
|
|
10360
|
-
} while (ctx.match(',') && !ctx.isAtEnd());
|
|
10361
|
-
const endPos = ctx.getPosition();
|
|
10362
|
-
return {
|
|
10363
|
-
type: 'objectLiteral',
|
|
10364
|
-
properties,
|
|
10365
|
-
start: startPos.start,
|
|
10366
|
-
end: endPos.end,
|
|
10367
|
-
line: startPos.line,
|
|
10368
|
-
column: startPos.column,
|
|
10369
|
-
};
|
|
10370
|
-
}
|
|
10371
10615
|
function findJsEndBoundary(ctx, startPos) {
|
|
10372
10616
|
const input = ctx.getInputSlice(startPos);
|
|
10373
10617
|
if (!input) {
|
|
@@ -10487,6 +10731,7 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10487
10731
|
const commands = [];
|
|
10488
10732
|
while (!ctx.isAtEnd()) {
|
|
10489
10733
|
if (ctx.checkIsCommand()) {
|
|
10734
|
+
const word = ctx.peek().value;
|
|
10490
10735
|
try {
|
|
10491
10736
|
ctx.advance();
|
|
10492
10737
|
const cmd = ctx.parseCommand();
|
|
@@ -10497,7 +10742,8 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10497
10742
|
break;
|
|
10498
10743
|
}
|
|
10499
10744
|
}
|
|
10500
|
-
catch {
|
|
10745
|
+
catch (error) {
|
|
10746
|
+
ctx.addError(`'${word}' in a tell body failed to parse: ${error instanceof Error ? error.message : String(error)}`);
|
|
10501
10747
|
break;
|
|
10502
10748
|
}
|
|
10503
10749
|
if (ctx.match(KEYWORDS.AND) || ctx.match(KEYWORDS.THEN)) {
|
|
@@ -10646,7 +10892,6 @@ const ONE_EXPR = (syntax) => ({
|
|
|
10646
10892
|
markers: [],
|
|
10647
10893
|
syntax,
|
|
10648
10894
|
});
|
|
10649
|
-
const BEEP = ONE_EXPR('beep! [<expression>, \u2026]');
|
|
10650
10895
|
const COMMAND_GRAMMAR = {
|
|
10651
10896
|
append: { positional: 'expression', markers: ['to'], syntax: 'append <value> [to <target>]' },
|
|
10652
10897
|
prepend: { positional: 'expression', markers: ['to'], syntax: 'prepend <value> [to <target>]' },
|
|
@@ -10657,8 +10902,7 @@ const COMMAND_GRAMMAR = {
|
|
|
10657
10902
|
syntax: 'make (a|an) <type> [from <args>] [called <name>]',
|
|
10658
10903
|
},
|
|
10659
10904
|
throw: { positional: 'primary', markers: [], syntax: 'throw <error>' },
|
|
10660
|
-
'beep!'
|
|
10661
|
-
beep: BEEP,
|
|
10905
|
+
beep: ONE_EXPR('beep! [<expression>, \u2026]'),
|
|
10662
10906
|
blur: ONE_EXPR('blur [<target>]'),
|
|
10663
10907
|
break: NONE,
|
|
10664
10908
|
breakpoint: NONE,
|
|
@@ -10682,7 +10926,8 @@ const COMMAND_GRAMMAR = {
|
|
|
10682
10926
|
render: {
|
|
10683
10927
|
positional: 'expression',
|
|
10684
10928
|
markers: ['with'],
|
|
10685
|
-
|
|
10929
|
+
namedArgs: ['with'],
|
|
10930
|
+
syntax: 'render <template> [with <name>: <value>, \u2026]',
|
|
10686
10931
|
},
|
|
10687
10932
|
reset: ONE_EXPR('reset [<form>]'),
|
|
10688
10933
|
return: ONE_EXPR('return [<value>]'),
|
|
@@ -11037,7 +11282,10 @@ class Parser {
|
|
|
11037
11282
|
const firstToken = this.peek();
|
|
11038
11283
|
const prefixEntry = Parser.PRATT_TABLE.get(firstToken.value);
|
|
11039
11284
|
let left;
|
|
11040
|
-
if (
|
|
11285
|
+
if (isGluedBeepBang(firstToken, this.tokens[this.current + 1])) {
|
|
11286
|
+
left = this.parseBeepExpression();
|
|
11287
|
+
}
|
|
11288
|
+
else if (prefixEntry?.prefix) {
|
|
11041
11289
|
const token = this.advance();
|
|
11042
11290
|
if (this.isAtEnd()) {
|
|
11043
11291
|
this.addError(`Expected expression after '${token.value}' operator`);
|
|
@@ -11057,6 +11305,9 @@ class Parser {
|
|
|
11057
11305
|
continue;
|
|
11058
11306
|
}
|
|
11059
11307
|
}
|
|
11308
|
+
if (nextToken.value === '*' && this.isSpacedStyleRef(this.current)) {
|
|
11309
|
+
break;
|
|
11310
|
+
}
|
|
11060
11311
|
const infixEntry = Parser.PRATT_TABLE.get(nextToken.value);
|
|
11061
11312
|
if (!infixEntry?.infix) {
|
|
11062
11313
|
if (STOP_TOKENS.has(nextToken.value) || STOP_DELIMITERS.has(nextToken.value)) {
|
|
@@ -11118,6 +11369,35 @@ class Parser {
|
|
|
11118
11369
|
this.prattCache.set(cacheKey, { node: left, endPos: this.current });
|
|
11119
11370
|
return left;
|
|
11120
11371
|
}
|
|
11372
|
+
parseBeepExpression() {
|
|
11373
|
+
const beepToken = this.advance();
|
|
11374
|
+
this.advance();
|
|
11375
|
+
if (this.isAtEnd()) {
|
|
11376
|
+
this.addError("Expected expression after 'beep!'");
|
|
11377
|
+
return this.createErrorNode();
|
|
11378
|
+
}
|
|
11379
|
+
const operand = this.parseExpressionPratt(Parser.BEEP_OPERAND_BP);
|
|
11380
|
+
return {
|
|
11381
|
+
type: 'unaryExpression',
|
|
11382
|
+
operator: 'beep!',
|
|
11383
|
+
operand,
|
|
11384
|
+
argument: operand,
|
|
11385
|
+
prefix: true,
|
|
11386
|
+
start: beepToken.start,
|
|
11387
|
+
end: this.previous().end,
|
|
11388
|
+
line: beepToken.line,
|
|
11389
|
+
column: beepToken.column,
|
|
11390
|
+
};
|
|
11391
|
+
}
|
|
11392
|
+
isStyleRefStar(i) {
|
|
11393
|
+
const star = this.tokens[i];
|
|
11394
|
+
const name = this.tokens[i + 1];
|
|
11395
|
+
return star?.value === '*' && !!name && name.start === star.end && isIdentifierLike(name);
|
|
11396
|
+
}
|
|
11397
|
+
isSpacedStyleRef(i) {
|
|
11398
|
+
const prev = this.tokens[i - 1];
|
|
11399
|
+
return this.isStyleRefStar(i) && !!prev && prev.end < this.tokens[i].start;
|
|
11400
|
+
}
|
|
11121
11401
|
tryParseStringPostfix(left, nextToken) {
|
|
11122
11402
|
const v = nextToken.value;
|
|
11123
11403
|
let unit = null;
|
|
@@ -11320,6 +11600,10 @@ class Parser {
|
|
|
11320
11600
|
const isStop = () => this.check('end') || extraStops.some(s => this.check(s));
|
|
11321
11601
|
debug.parse('\ud83d\udd04 parseCommandListUntilTerminator: Starting (extraStops:', extraStops.join(','), ')');
|
|
11322
11602
|
while (!this.isAtEnd() && !isStop()) {
|
|
11603
|
+
if (this.checkComment()) {
|
|
11604
|
+
this.advance();
|
|
11605
|
+
continue;
|
|
11606
|
+
}
|
|
11323
11607
|
debug.parse('\ud83d\udccd Loop iteration, current token:', this.peek().value, 'kind:', this.peek().kind);
|
|
11324
11608
|
let parsedCommand = false;
|
|
11325
11609
|
const isCommandToken = this.checkIsCommand();
|
|
@@ -11403,7 +11687,7 @@ class Parser {
|
|
|
11403
11687
|
debug.parse('\u2705 Found "end", consuming it');
|
|
11404
11688
|
this.advance();
|
|
11405
11689
|
}
|
|
11406
|
-
else {
|
|
11690
|
+
else if (!this.atEndOfInput()) {
|
|
11407
11691
|
debug.parse('\u274c ERROR: Expected "end" but got:', this.peek().value, 'at position:', this.peek().start);
|
|
11408
11692
|
throw new Error(`Expected "end" to close ${construct} block`);
|
|
11409
11693
|
}
|
|
@@ -11416,7 +11700,7 @@ class Parser {
|
|
|
11416
11700
|
if (this.check('end')) {
|
|
11417
11701
|
this.advance();
|
|
11418
11702
|
}
|
|
11419
|
-
else {
|
|
11703
|
+
else if (!this.atEndOfInput()) {
|
|
11420
11704
|
throw new Error('Expected "end" to close repeat block');
|
|
11421
11705
|
}
|
|
11422
11706
|
}
|
|
@@ -11432,7 +11716,10 @@ class Parser {
|
|
|
11432
11716
|
this.advance();
|
|
11433
11717
|
}
|
|
11434
11718
|
else if (terminator === '') {
|
|
11435
|
-
|
|
11719
|
+
if (!this.atEndOfInput()) {
|
|
11720
|
+
throw new Error('Expected "end", "else", "until", or "while" to close repeat block');
|
|
11721
|
+
}
|
|
11722
|
+
return { commands, terminator: 'end' };
|
|
11436
11723
|
}
|
|
11437
11724
|
return { commands, terminator };
|
|
11438
11725
|
}
|
|
@@ -12016,7 +12303,9 @@ class Parser {
|
|
|
12016
12303
|
parseTopLevelInitBlock() {
|
|
12017
12304
|
const pos = this.getPosition();
|
|
12018
12305
|
const initCommands = this.parseCommandBlock(['end']);
|
|
12019
|
-
this.
|
|
12306
|
+
if (!this.match('end') && !this.atEndOfInput() && !this.checkFeatureStart()) {
|
|
12307
|
+
this.consume('end', "Expected 'end' after init block");
|
|
12308
|
+
}
|
|
12020
12309
|
return {
|
|
12021
12310
|
type: 'initBlock',
|
|
12022
12311
|
commands: initCommands,
|
|
@@ -12192,10 +12481,29 @@ class Parser {
|
|
|
12192
12481
|
...(sourceExpr.column !== undefined && { column: sourceExpr.column }),
|
|
12193
12482
|
};
|
|
12194
12483
|
}
|
|
12484
|
+
isArgumentListOnly(open) {
|
|
12485
|
+
let depth = 0;
|
|
12486
|
+
for (let i = open; i < this.tokens.length; i++) {
|
|
12487
|
+
const token = this.tokens[i];
|
|
12488
|
+
if (token.kind !== 'operator')
|
|
12489
|
+
continue;
|
|
12490
|
+
if (token.value === '(' || token.value === '[' || token.value === '{')
|
|
12491
|
+
depth++;
|
|
12492
|
+
else if (token.value === ')' || token.value === ']' || token.value === '}') {
|
|
12493
|
+
if (--depth === 0)
|
|
12494
|
+
return i === open + 1;
|
|
12495
|
+
}
|
|
12496
|
+
else if (token.value === ',' && depth === 1)
|
|
12497
|
+
return true;
|
|
12498
|
+
}
|
|
12499
|
+
return false;
|
|
12500
|
+
}
|
|
12195
12501
|
tryParsePseudoCommand(callExpr, sourceExpr) {
|
|
12196
12502
|
const methodName = callExpr.callee.name;
|
|
12197
12503
|
const nextToken = this.peek();
|
|
12198
|
-
const
|
|
12504
|
+
const nextIsArticle = nextToken.value.toLowerCase() === 'the';
|
|
12505
|
+
const hasPseudoCommandPattern = nextIsArticle ||
|
|
12506
|
+
Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(nextToken.value.toLowerCase()) ||
|
|
12199
12507
|
(isIdentifier(nextToken) && !this.isCommand(nextToken.value)) ||
|
|
12200
12508
|
isContextVar(nextToken);
|
|
12201
12509
|
if (!hasPseudoCommandPattern) {
|
|
@@ -12221,7 +12529,10 @@ class Parser {
|
|
|
12221
12529
|
});
|
|
12222
12530
|
}
|
|
12223
12531
|
let preposition;
|
|
12224
|
-
if (
|
|
12532
|
+
if (nextIsArticle) {
|
|
12533
|
+
this.advance();
|
|
12534
|
+
}
|
|
12535
|
+
else if (Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(this.peek().value.toLowerCase())) {
|
|
12225
12536
|
preposition = this.advance().value.toLowerCase();
|
|
12226
12537
|
}
|
|
12227
12538
|
let targetExpr;
|
|
@@ -12385,10 +12696,22 @@ class Parser {
|
|
|
12385
12696
|
this.consume(']', "Expected ']' after event condition");
|
|
12386
12697
|
}
|
|
12387
12698
|
let target;
|
|
12699
|
+
let targetExpression;
|
|
12388
12700
|
if (this.match('from')) {
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12701
|
+
if (this.check('the'))
|
|
12702
|
+
this.advance();
|
|
12703
|
+
if (Parser.POSITIONAL_SOURCE_HEADS.has(this.peek().value.toLowerCase())) {
|
|
12704
|
+
const startIndex = this.current;
|
|
12705
|
+
targetExpression = this.parseExpression();
|
|
12706
|
+
target = this.tokens
|
|
12707
|
+
.slice(startIndex, this.current)
|
|
12708
|
+
.map(t => t.value)
|
|
12709
|
+
.join(' ');
|
|
12710
|
+
}
|
|
12711
|
+
else {
|
|
12712
|
+
target = this.advance().value;
|
|
12713
|
+
}
|
|
12714
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'from' target: ${target}`);
|
|
12392
12715
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
12393
12716
|
}
|
|
12394
12717
|
let attributeName;
|
|
@@ -12434,7 +12757,7 @@ class Parser {
|
|
|
12434
12757
|
const nextIsOpenParen = this.tokens[this.current + 1]?.value === '(';
|
|
12435
12758
|
const commandName = this.peek().value.toLowerCase();
|
|
12436
12759
|
const isSpecialBodyCommand = commandName === 'js' || commandName === 'tell';
|
|
12437
|
-
if (nextIsOpenParen && !isSpecialBodyCommand) {
|
|
12760
|
+
if (nextIsOpenParen && !isSpecialBodyCommand && this.isArgumentListOnly(this.current + 1)) {
|
|
12438
12761
|
let expr;
|
|
12439
12762
|
const savedError = this.error;
|
|
12440
12763
|
try {
|
|
@@ -12466,7 +12789,7 @@ class Parser {
|
|
|
12466
12789
|
}
|
|
12467
12790
|
}
|
|
12468
12791
|
}
|
|
12469
|
-
else if (this.checkIdentifier()) {
|
|
12792
|
+
else if (this.checkIdentifier() || this.checkEventNamedCall()) {
|
|
12470
12793
|
const token = this.peek();
|
|
12471
12794
|
if (this.isCommand(token.value)) {
|
|
12472
12795
|
const cmd = this.parseCommandWithErrorRecovery();
|
|
@@ -12575,6 +12898,7 @@ class Parser {
|
|
|
12575
12898
|
...(eventParams.length > 0 && { args: eventParams }),
|
|
12576
12899
|
...(condition && { condition: fromLegacyExpression(condition) }),
|
|
12577
12900
|
...(target && { target }),
|
|
12901
|
+
...(targetExpression && { targetExpression: fromLegacyExpression(targetExpression) }),
|
|
12578
12902
|
...(attributeName && { attributeName }),
|
|
12579
12903
|
...(watchTarget && { watchTarget: fromLegacyExpression(watchTarget) }),
|
|
12580
12904
|
...(customEventSource && { customEventSource }),
|
|
@@ -12830,10 +13154,9 @@ class Parser {
|
|
|
12830
13154
|
}
|
|
12831
13155
|
parseCommandCore() {
|
|
12832
13156
|
const commandToken = this.previous();
|
|
12833
|
-
|
|
13157
|
+
const commandName = commandToken.value;
|
|
12834
13158
|
if (commandName === 'beep' && this.check('!')) {
|
|
12835
13159
|
this.advance();
|
|
12836
|
-
commandName = 'beep!';
|
|
12837
13160
|
}
|
|
12838
13161
|
if (commandName === 'fetch') {
|
|
12839
13162
|
return parseFetchCommand(this.getContext(), commandToken);
|
|
@@ -12932,6 +13255,9 @@ class Parser {
|
|
|
12932
13255
|
args.push(this.parsePrimary());
|
|
12933
13256
|
}
|
|
12934
13257
|
const callNode = this.createCallExpression(createIdentifier(funcName, namePos), args);
|
|
13258
|
+
if (funcName === 'closest' && args.length > 0 && this.match('to')) {
|
|
13259
|
+
callNode.closestTo = this.parseExpression();
|
|
13260
|
+
}
|
|
12935
13261
|
if (funcName === 'next' || funcName === 'previous') {
|
|
12936
13262
|
const relativePositional = this.parseRelativePositionalModifiers();
|
|
12937
13263
|
if (relativePositional) {
|
|
@@ -12971,6 +13297,9 @@ class Parser {
|
|
|
12971
13297
|
}
|
|
12972
13298
|
parseTheXofY() {
|
|
12973
13299
|
const positionalKeywords = ['first', 'last', 'next', 'previous', 'random', 'closest'];
|
|
13300
|
+
if (this.isStyleRefStar(this.current)) {
|
|
13301
|
+
return this.parsePrimary();
|
|
13302
|
+
}
|
|
12974
13303
|
if (!this.checkIdentifier()) {
|
|
12975
13304
|
return this.createIdentifier('the');
|
|
12976
13305
|
}
|
|
@@ -12986,7 +13315,7 @@ class Parser {
|
|
|
12986
13315
|
return this.createIdentifier(propertyName);
|
|
12987
13316
|
}
|
|
12988
13317
|
this.advance();
|
|
12989
|
-
const target = this.
|
|
13318
|
+
const target = parseOfOperand(this.makePrattContext(), THE_OF_TARGET_BP);
|
|
12990
13319
|
return {
|
|
12991
13320
|
type: 'propertyOfExpression',
|
|
12992
13321
|
property: { type: 'identifier', name: propertyName },
|
|
@@ -13184,6 +13513,13 @@ class Parser {
|
|
|
13184
13513
|
checkLiteral() {
|
|
13185
13514
|
return this.checkPredicate(isLiteral);
|
|
13186
13515
|
}
|
|
13516
|
+
checkEventNamedCall() {
|
|
13517
|
+
if (this.isAtEnd() || !this.checkIdentifierLike() || this.checkIsCommand())
|
|
13518
|
+
return false;
|
|
13519
|
+
const token = this.peek();
|
|
13520
|
+
const next = this.tokens[this.current + 1];
|
|
13521
|
+
return next?.value === '(' && next.start === token.end;
|
|
13522
|
+
}
|
|
13187
13523
|
checkIdentifierLike() {
|
|
13188
13524
|
return this.checkPredicate(isIdentifierLike);
|
|
13189
13525
|
}
|
|
@@ -13292,6 +13628,22 @@ class Parser {
|
|
|
13292
13628
|
isAtEnd() {
|
|
13293
13629
|
return this.current >= this.tokens.length;
|
|
13294
13630
|
}
|
|
13631
|
+
atEndOfInput() {
|
|
13632
|
+
for (let i = this.current; i < this.tokens.length; i++) {
|
|
13633
|
+
if (!isComment(this.tokens[i]))
|
|
13634
|
+
return false;
|
|
13635
|
+
}
|
|
13636
|
+
return true;
|
|
13637
|
+
}
|
|
13638
|
+
checkFeatureStart() {
|
|
13639
|
+
if (this.isAtEnd())
|
|
13640
|
+
return false;
|
|
13641
|
+
const value = this.peek().value;
|
|
13642
|
+
return (value === 'init' ||
|
|
13643
|
+
value === 'on' ||
|
|
13644
|
+
value === 'def' ||
|
|
13645
|
+
getRegisteredFeature(value) !== undefined);
|
|
13646
|
+
}
|
|
13295
13647
|
peek() {
|
|
13296
13648
|
if (this.isAtEnd()) {
|
|
13297
13649
|
return { kind: 'unknown', value: '', start: 0, end: 0, line: 1, column: 1 };
|
|
@@ -13503,6 +13855,7 @@ class Parser {
|
|
|
13503
13855
|
match: this.match.bind(this),
|
|
13504
13856
|
matchOperator: this.matchOperator.bind(this),
|
|
13505
13857
|
isAtEnd: this.isAtEnd.bind(this),
|
|
13858
|
+
atEndOfInput: this.atEndOfInput.bind(this),
|
|
13506
13859
|
createIdentifier: this.createIdentifier.bind(this),
|
|
13507
13860
|
parseExpression: this.parseExpression.bind(this),
|
|
13508
13861
|
parsePrimary: this.parsePrimary.bind(this),
|
|
@@ -13553,7 +13906,15 @@ Parser.POSTFIX_UNARY_OPERATORS = new Set([
|
|
|
13553
13906
|
'ignoring case',
|
|
13554
13907
|
]);
|
|
13555
13908
|
Parser.PRATT_TABLE = PARSER_TABLE;
|
|
13909
|
+
Parser.BEEP_OPERAND_BP = 80;
|
|
13556
13910
|
Parser.PSEUDO_COMMAND_PREPOSITIONS = ['from', 'on', 'with', 'into', 'at', 'to'];
|
|
13911
|
+
Parser.POSITIONAL_SOURCE_HEADS = new Set([
|
|
13912
|
+
'closest',
|
|
13913
|
+
'next',
|
|
13914
|
+
'previous',
|
|
13915
|
+
'first',
|
|
13916
|
+
'last',
|
|
13917
|
+
]);
|
|
13557
13918
|
function parse(input, options) {
|
|
13558
13919
|
const tokens = tokenize(input);
|
|
13559
13920
|
const parser = new Parser(tokens, options, input);
|
|
@@ -13995,11 +14356,16 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
13995
14356
|
}
|
|
13996
14357
|
}
|
|
13997
14358
|
}
|
|
13998
|
-
if (leftNode?.type === 'selector' &&
|
|
14359
|
+
if (leftNode?.type === 'selector' &&
|
|
14360
|
+
typeof leftNode.value === 'string' &&
|
|
14361
|
+
(leftNode.fromQuery || (operator === 'in' && leftNode.value.startsWith('.')))) {
|
|
13999
14362
|
const root = await evaluateAST(node.right, context);
|
|
14000
14363
|
const scope = root && typeof root.querySelectorAll === 'function' ? root : null;
|
|
14001
14364
|
if (scope) {
|
|
14002
|
-
|
|
14365
|
+
const query = leftNode.fromQuery
|
|
14366
|
+
? leftNode.value
|
|
14367
|
+
: escapeSelectorForQuery(leftNode, leftNode.value);
|
|
14368
|
+
return Array.from(scope.querySelectorAll(query));
|
|
14003
14369
|
}
|
|
14004
14370
|
}
|
|
14005
14371
|
}
|
|
@@ -14011,6 +14377,12 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14011
14377
|
return getExpr(context, 'styleRef').evaluate(context, leftNode.value.slice(1), el);
|
|
14012
14378
|
}
|
|
14013
14379
|
if (operator === 'of') {
|
|
14380
|
+
if (leftNode?.type === 'attributeAccess') {
|
|
14381
|
+
const target = await evaluateAST(node.right, context);
|
|
14382
|
+
if (target == null)
|
|
14383
|
+
return undefined;
|
|
14384
|
+
return getExpr(context, 'possessive').evaluate(context, target, `@${leftNode.attributeName}`);
|
|
14385
|
+
}
|
|
14014
14386
|
const path = propertyPathOf(node.left);
|
|
14015
14387
|
if (path) {
|
|
14016
14388
|
const target = await evaluateAST(node.right, context);
|
|
@@ -14018,6 +14390,10 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14018
14390
|
for (const seg of path) {
|
|
14019
14391
|
if (cur == null)
|
|
14020
14392
|
return undefined;
|
|
14393
|
+
if (isMappableCollection(cur) && !(seg in cur)) {
|
|
14394
|
+
cur = await getExpr(context, 'possessive').evaluate(context, cur, seg);
|
|
14395
|
+
continue;
|
|
14396
|
+
}
|
|
14021
14397
|
cur = isElement(cur) ? getElementProperty$1(cur, seg) : cur[seg];
|
|
14022
14398
|
}
|
|
14023
14399
|
return typeof cur === 'function' ? cur.bind(target) : cur;
|
|
@@ -14042,26 +14418,21 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14042
14418
|
const R = node.ignoringCase ? applyCI(right) : right;
|
|
14043
14419
|
switch (operator) {
|
|
14044
14420
|
case '+': {
|
|
14045
|
-
let addLeft = left;
|
|
14046
|
-
let addRight = right;
|
|
14047
14421
|
if (node.coerceNumeric) {
|
|
14048
|
-
|
|
14049
|
-
addLeft = convertToNumber(addLeft);
|
|
14050
|
-
if (typeof addRight === 'string')
|
|
14051
|
-
addRight = convertToNumber(addRight);
|
|
14422
|
+
return counterValue(left) + counterAmount(right);
|
|
14052
14423
|
}
|
|
14053
|
-
if (typeof
|
|
14054
|
-
return String(
|
|
14424
|
+
if (typeof left === 'string' || typeof right === 'string') {
|
|
14425
|
+
return String(left ?? '') + String(right ?? '');
|
|
14055
14426
|
}
|
|
14056
|
-
if (Array.isArray(
|
|
14057
|
-
return Array.isArray(
|
|
14427
|
+
if (Array.isArray(left)) {
|
|
14428
|
+
return Array.isArray(right) ? [...left, ...right] : [...left, right];
|
|
14058
14429
|
}
|
|
14059
|
-
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, {
|
|
14060
|
-
left: addLeft,
|
|
14061
|
-
right: addRight,
|
|
14062
|
-
}));
|
|
14430
|
+
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, { left, right }));
|
|
14063
14431
|
}
|
|
14064
14432
|
case '-':
|
|
14433
|
+
if (node.coerceNumeric) {
|
|
14434
|
+
return counterValue(left) - counterAmount(right);
|
|
14435
|
+
}
|
|
14065
14436
|
return unwrapTypedResult(await getExpr(context, 'subtraction').evaluate(context, { left, right }));
|
|
14066
14437
|
case '*':
|
|
14067
14438
|
return unwrapTypedResult(await getExpr(context, 'multiplication').evaluate(context, { left, right }));
|
|
@@ -14319,9 +14690,8 @@ async function evaluatePropertyOfExpressionNode(node, context) {
|
|
|
14319
14690
|
}
|
|
14320
14691
|
const propertyName = propertyNode.name;
|
|
14321
14692
|
const target = await evaluateAST(node.target, context);
|
|
14322
|
-
if (target == null)
|
|
14323
|
-
|
|
14324
|
-
}
|
|
14693
|
+
if (target == null)
|
|
14694
|
+
return undefined;
|
|
14325
14695
|
return getExpr(context, 'possessive').evaluate(context, target, propertyName);
|
|
14326
14696
|
}
|
|
14327
14697
|
async function evaluateTemplateLiteralNode(node, context) {
|
|
@@ -14439,6 +14809,9 @@ async function evaluateUnaryExpression(node, context) {
|
|
|
14439
14809
|
case 'not':
|
|
14440
14810
|
case '!':
|
|
14441
14811
|
return logicalExpressions.not.evaluate(context, value);
|
|
14812
|
+
case 'beep!':
|
|
14813
|
+
beepValues(context.me, [value]);
|
|
14814
|
+
return value;
|
|
14442
14815
|
case 'no':
|
|
14443
14816
|
return logicalExpressions.no.evaluate(context, value);
|
|
14444
14817
|
case '-':
|
|
@@ -14528,6 +14901,10 @@ async function evaluateCallExpression(node, context) {
|
|
|
14528
14901
|
const args = await resolveCallArgs(node.arguments, funcName, context);
|
|
14529
14902
|
switch (funcName) {
|
|
14530
14903
|
case 'closest':
|
|
14904
|
+
if (node.closestTo) {
|
|
14905
|
+
const start = unwrapElement(await evaluateAST(node.closestTo, context)) ?? null;
|
|
14906
|
+
return referencesExpressions.closest.evaluate(context, args[0], start);
|
|
14907
|
+
}
|
|
14531
14908
|
return referencesExpressions.closest.evaluate(context, ...args);
|
|
14532
14909
|
case 'previous':
|
|
14533
14910
|
case 'next': {
|
|
@@ -15952,10 +16329,29 @@ const STRATEGY_KEYWORDS = {
|
|
|
15952
16329
|
innermorph: 'morph',
|
|
15953
16330
|
outermorph: 'morphOuter',
|
|
15954
16331
|
};
|
|
16332
|
+
function loneRootWithTag(content, tagName) {
|
|
16333
|
+
let root;
|
|
16334
|
+
if (typeof content === 'string') {
|
|
16335
|
+
const template = document.createElement('template');
|
|
16336
|
+
template.innerHTML = content;
|
|
16337
|
+
root = template.content.firstElementChild;
|
|
16338
|
+
if (!root || root.nextElementSibling)
|
|
16339
|
+
return null;
|
|
16340
|
+
}
|
|
16341
|
+
else {
|
|
16342
|
+
root = content.cloneNode(true);
|
|
16343
|
+
}
|
|
16344
|
+
return root.tagName === tagName && isHTMLElement$2(root) ? root : null;
|
|
16345
|
+
}
|
|
15955
16346
|
function executeSwap(target, content, strategy, morphOptions) {
|
|
15956
16347
|
const contentStr = content !== null && !isHTMLElement$2(content) ? content : '';
|
|
15957
16348
|
const contentEl = isHTMLElement$2(content) ? content : null;
|
|
15958
16349
|
switch (strategy) {
|
|
16350
|
+
case 'morphMerge': {
|
|
16351
|
+
const root = content !== null ? loneRootWithTag(content, target.tagName) : null;
|
|
16352
|
+
executeSwap(target, root ?? content, root ? 'morphOuter' : 'morph', morphOptions);
|
|
16353
|
+
break;
|
|
16354
|
+
}
|
|
15959
16355
|
case 'morph':
|
|
15960
16356
|
if (content !== null) {
|
|
15961
16357
|
try {
|
|
@@ -16245,7 +16641,7 @@ let MorphCommand = (() => {
|
|
|
16245
16641
|
if (args.length === 0 && modifiers.with === undefined) {
|
|
16246
16642
|
throw new Error('[HyperFixi] morph: command requires arguments');
|
|
16247
16643
|
}
|
|
16248
|
-
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : '
|
|
16644
|
+
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : 'morphMerge';
|
|
16249
16645
|
const useViewTransition = modifiers.viewTransition !== undefined;
|
|
16250
16646
|
const targetNode = modifiers.on !== undefined ? modifiers.on : args[0];
|
|
16251
16647
|
const contentNode = modifiers.with !== undefined
|
|
@@ -17535,6 +17931,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17535
17931
|
}
|
|
17536
17932
|
return { kind: 'property', target: property };
|
|
17537
17933
|
}
|
|
17934
|
+
if (options.ofAndObjectProperty) {
|
|
17935
|
+
const access = ofOrPossessiveAccess(n);
|
|
17936
|
+
if (access) {
|
|
17937
|
+
const owner = await evaluator.evaluate(access.owner, context);
|
|
17938
|
+
const element = Array.isArray(owner) ? owner[0] : owner;
|
|
17939
|
+
if (access.isOf && isHTMLElement$2(element)) {
|
|
17940
|
+
return { kind: 'property', target: { element, property: access.name } };
|
|
17941
|
+
}
|
|
17942
|
+
if (isObjectOwner(owner)) {
|
|
17943
|
+
return { kind: 'member', container: owner, property: access.name };
|
|
17944
|
+
}
|
|
17945
|
+
}
|
|
17946
|
+
}
|
|
17538
17947
|
if (options.bareReference &&
|
|
17539
17948
|
(nodeType === 'identifier' || nodeType === 'variable' || nodeType === 'symbol') &&
|
|
17540
17949
|
typeof n.name === 'string') {
|
|
@@ -17544,6 +17953,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17544
17953
|
}
|
|
17545
17954
|
return null;
|
|
17546
17955
|
}
|
|
17956
|
+
function ofOrPossessiveAccess(n) {
|
|
17957
|
+
const [owner, property, isOf] = n.type === 'possessiveExpression'
|
|
17958
|
+
? [n.object, n.property, false]
|
|
17959
|
+
: n.type === 'propertyOfExpression'
|
|
17960
|
+
? [n.target, n.property, false]
|
|
17961
|
+
: n.type === 'binaryExpression' && n.operator === 'of'
|
|
17962
|
+
? [n.right, n.left, true]
|
|
17963
|
+
: [undefined, undefined, false];
|
|
17964
|
+
const name = property?.name;
|
|
17965
|
+
if (!owner || typeof name !== 'string' || !/^[A-Za-z_$][\w$]*$/.test(name))
|
|
17966
|
+
return null;
|
|
17967
|
+
return { owner, name, isOf };
|
|
17968
|
+
}
|
|
17547
17969
|
|
|
17548
17970
|
function toSetInput(target, value) {
|
|
17549
17971
|
switch (target.kind) {
|
|
@@ -17565,10 +17987,18 @@ function toSetInput(target, value) {
|
|
|
17565
17987
|
property: target.target.property,
|
|
17566
17988
|
value,
|
|
17567
17989
|
};
|
|
17990
|
+
case 'member':
|
|
17991
|
+
return {
|
|
17992
|
+
type: 'member-assignment',
|
|
17993
|
+
container: target.container,
|
|
17994
|
+
property: target.property,
|
|
17995
|
+
value,
|
|
17996
|
+
};
|
|
17568
17997
|
default:
|
|
17569
17998
|
throw new Error(`set: unrequested write-target rung '${target.kind}'`);
|
|
17570
17999
|
}
|
|
17571
18000
|
}
|
|
18001
|
+
const SET_RUNGS = { nodeWriters: true, styleSplit: true, ofAndObjectProperty: true };
|
|
17572
18002
|
let SetCommand = (() => {
|
|
17573
18003
|
let _classDecorators = [command({ name: 'set' })];
|
|
17574
18004
|
let _classDescriptor;
|
|
@@ -17587,8 +18017,7 @@ let SetCommand = (() => {
|
|
|
17587
18017
|
const argScope = firstArg?.scope;
|
|
17588
18018
|
const writeTarget = await resolveWriteTarget(firstArg, evaluator, context, {
|
|
17589
18019
|
scopeElements: () => this.resolveTargets(raw.modifiers.on, evaluator, context),
|
|
17590
|
-
|
|
17591
|
-
styleSplit: true,
|
|
18020
|
+
...SET_RUNGS,
|
|
17592
18021
|
});
|
|
17593
18022
|
if (writeTarget) {
|
|
17594
18023
|
return toSetInput(writeTarget, await this.extractValue(raw, evaluator, context));
|
|
@@ -17914,12 +18343,30 @@ function getNodeType(node) {
|
|
|
17914
18343
|
return 'unknown';
|
|
17915
18344
|
return node.type || 'unknown';
|
|
17916
18345
|
}
|
|
18346
|
+
function propertyTarget(node) {
|
|
18347
|
+
const n = node;
|
|
18348
|
+
const owner = n.type === 'propertyOfExpression'
|
|
18349
|
+
? n.target
|
|
18350
|
+
: n.type === 'possessiveExpression' ||
|
|
18351
|
+
n.type === 'memberExpression' ||
|
|
18352
|
+
n.type === 'propertyAccess'
|
|
18353
|
+
? n.object
|
|
18354
|
+
: undefined;
|
|
18355
|
+
if (!owner || n.computed)
|
|
18356
|
+
return null;
|
|
18357
|
+
const p = n.property;
|
|
18358
|
+
const name = typeof p === 'string' ? p : typeof p?.name === 'string' ? p.name : undefined;
|
|
18359
|
+
if (!name || !/^[A-Za-z_$][\w$-]*$/.test(name))
|
|
18360
|
+
return null;
|
|
18361
|
+
return { owner, name };
|
|
18362
|
+
}
|
|
17917
18363
|
async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
17918
18364
|
if (!raw.args || raw.args.length === 0) {
|
|
17919
18365
|
throw new Error(`${commandName} command requires a target`);
|
|
17920
18366
|
}
|
|
17921
18367
|
const targetArg = raw.args[0];
|
|
17922
18368
|
let target;
|
|
18369
|
+
let property;
|
|
17923
18370
|
let extractedScope;
|
|
17924
18371
|
let customWrite;
|
|
17925
18372
|
const nodeType = getNodeType(targetArg);
|
|
@@ -17934,7 +18381,25 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17934
18381
|
}
|
|
17935
18382
|
else {
|
|
17936
18383
|
const writer = getRegisteredNodeWriter(nodeType);
|
|
17937
|
-
|
|
18384
|
+
const attribute = writer
|
|
18385
|
+
? null
|
|
18386
|
+
: await resolveAttributeWriteTarget(targetArg, evaluator, context, async () => context.me ? [context.me] : []);
|
|
18387
|
+
const prop = writer || attribute ? null : propertyTarget(targetArg);
|
|
18388
|
+
const owner = prop ? await evaluator.evaluate(prop.owner, context) : undefined;
|
|
18389
|
+
const ownerElement = Array.isArray(owner) ? owner[0] : owner;
|
|
18390
|
+
if (attribute?.elements[0]) {
|
|
18391
|
+
target = attribute.elements[0];
|
|
18392
|
+
property = `@${attribute.name}`;
|
|
18393
|
+
}
|
|
18394
|
+
else if (prop && isHTMLElement$2(ownerElement)) {
|
|
18395
|
+
target = ownerElement;
|
|
18396
|
+
property = prop.name;
|
|
18397
|
+
}
|
|
18398
|
+
else if (prop && isObjectOwner(owner)) {
|
|
18399
|
+
target = owner;
|
|
18400
|
+
property = prop.name;
|
|
18401
|
+
}
|
|
18402
|
+
else if (writer) {
|
|
17938
18403
|
const currentRaw = await evaluator.evaluate(targetArg, context);
|
|
17939
18404
|
const currentValue = typeof currentRaw === 'number'
|
|
17940
18405
|
? currentRaw
|
|
@@ -17972,24 +18437,22 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17972
18437
|
if (typeof evaluated === 'number') {
|
|
17973
18438
|
amount = evaluated;
|
|
17974
18439
|
}
|
|
18440
|
+
else if (evaluated == null) {
|
|
18441
|
+
amount = NaN;
|
|
18442
|
+
}
|
|
17975
18443
|
}
|
|
17976
18444
|
}
|
|
17977
18445
|
const byModifier = raw.modifiers?.by;
|
|
17978
18446
|
if (byModifier) {
|
|
17979
|
-
const
|
|
17980
|
-
|
|
17981
|
-
|
|
17982
|
-
|
|
17983
|
-
else if (getNodeType(byModifier) !== 'literal') {
|
|
17984
|
-
const evaluated = await evaluator.evaluate(byModifier, context);
|
|
17985
|
-
if (typeof evaluated === 'number') {
|
|
17986
|
-
amount = evaluated;
|
|
17987
|
-
}
|
|
17988
|
-
}
|
|
18447
|
+
const value = getNodeType(byModifier) === 'literal'
|
|
18448
|
+
? byModifier.value
|
|
18449
|
+
: await evaluator.evaluate(byModifier, context);
|
|
18450
|
+
amount = counterAmount(value);
|
|
17989
18451
|
}
|
|
17990
18452
|
return {
|
|
17991
18453
|
target,
|
|
17992
18454
|
amount,
|
|
18455
|
+
...(property && { property }),
|
|
17993
18456
|
...(scope && { scope }),
|
|
17994
18457
|
...(customWrite && { customWrite }),
|
|
17995
18458
|
};
|
|
@@ -18012,7 +18475,7 @@ let NumericModifyCommand = (() => {
|
|
|
18012
18475
|
async execute(input, context) {
|
|
18013
18476
|
const { target, property, scope, amount = 1, operation = 'increment', customWrite } = input;
|
|
18014
18477
|
if (customWrite) {
|
|
18015
|
-
const delta =
|
|
18478
|
+
const delta = amount;
|
|
18016
18479
|
const newValue = operation === 'increment'
|
|
18017
18480
|
? customWrite.currentValue + delta
|
|
18018
18481
|
: customWrite.currentValue - delta;
|
|
@@ -18026,8 +18489,7 @@ let NumericModifyCommand = (() => {
|
|
|
18026
18489
|
newValue = NaN;
|
|
18027
18490
|
}
|
|
18028
18491
|
else {
|
|
18029
|
-
|
|
18030
|
-
newValue = operation === 'increment' ? currentValue + delta : currentValue - delta;
|
|
18492
|
+
newValue = operation === 'increment' ? currentValue + amount : currentValue - amount;
|
|
18031
18493
|
}
|
|
18032
18494
|
setTargetValue(target, property, scope, newValue, context);
|
|
18033
18495
|
Object.assign(context, { it: newValue });
|
|
@@ -18843,17 +19305,7 @@ let BeepCommand = (() => {
|
|
|
18843
19305
|
this.debugContext(context);
|
|
18844
19306
|
return { expressionCount: 0, debugged: true, outputs: [] };
|
|
18845
19307
|
}
|
|
18846
|
-
const outputs =
|
|
18847
|
-
console.group('\ud83d\udd14 beep! Debug Output');
|
|
18848
|
-
for (const expression of expressions) {
|
|
18849
|
-
const output = this.debugExpression(expression);
|
|
18850
|
-
outputs.push(output);
|
|
18851
|
-
console.log(`Value:`, expression);
|
|
18852
|
-
console.log(`Type:`, output.type);
|
|
18853
|
-
console.log(`Representation:`, output.representation);
|
|
18854
|
-
console.log('---');
|
|
18855
|
-
}
|
|
18856
|
-
console.groupEnd();
|
|
19308
|
+
const outputs = beepValues(context.me, expressions);
|
|
18857
19309
|
return { expressionCount: expressions.length, debugged: true, outputs };
|
|
18858
19310
|
}
|
|
18859
19311
|
debugContext(context) {
|
|
@@ -18866,67 +19318,6 @@ let BeepCommand = (() => {
|
|
|
18866
19318
|
console.log('variables:', context.variables);
|
|
18867
19319
|
console.groupEnd();
|
|
18868
19320
|
}
|
|
18869
|
-
debugExpression(expression) {
|
|
18870
|
-
return {
|
|
18871
|
-
value: expression,
|
|
18872
|
-
type: this.getType(expression),
|
|
18873
|
-
representation: this.getRepresentation(expression),
|
|
18874
|
-
};
|
|
18875
|
-
}
|
|
18876
|
-
getType(value) {
|
|
18877
|
-
if (value === null)
|
|
18878
|
-
return 'null';
|
|
18879
|
-
if (value === undefined)
|
|
18880
|
-
return 'undefined';
|
|
18881
|
-
if (Array.isArray(value))
|
|
18882
|
-
return 'array';
|
|
18883
|
-
if (isHTMLElement$2(value))
|
|
18884
|
-
return 'HTMLElement';
|
|
18885
|
-
if (value instanceof Element)
|
|
18886
|
-
return 'Element';
|
|
18887
|
-
if (value instanceof Node)
|
|
18888
|
-
return 'Node';
|
|
18889
|
-
if (value instanceof Error)
|
|
18890
|
-
return 'Error';
|
|
18891
|
-
if (value instanceof Date)
|
|
18892
|
-
return 'Date';
|
|
18893
|
-
if (value instanceof RegExp)
|
|
18894
|
-
return 'RegExp';
|
|
18895
|
-
return typeof value;
|
|
18896
|
-
}
|
|
18897
|
-
getRepresentation(value) {
|
|
18898
|
-
if (value === null)
|
|
18899
|
-
return 'null';
|
|
18900
|
-
if (value === undefined)
|
|
18901
|
-
return 'undefined';
|
|
18902
|
-
if (Array.isArray(value)) {
|
|
18903
|
-
return `Array(${value.length}) [${value
|
|
18904
|
-
.slice(0, 3)
|
|
18905
|
-
.map(v => this.getRepresentation(v))
|
|
18906
|
-
.join(', ')}${value.length > 3 ? '...' : ''}]`;
|
|
18907
|
-
}
|
|
18908
|
-
if (isHTMLElement$2(value)) {
|
|
18909
|
-
const el = value;
|
|
18910
|
-
const tag = el.tagName.toLowerCase();
|
|
18911
|
-
const id = el.id ? `#${el.id}` : '';
|
|
18912
|
-
const classes = el.className ? `.${el.className.split(' ').join('.')}` : '';
|
|
18913
|
-
return `<${tag}${id}${classes}/>`;
|
|
18914
|
-
}
|
|
18915
|
-
if (value instanceof Error)
|
|
18916
|
-
return `Error: ${value.message}`;
|
|
18917
|
-
if (typeof value === 'string')
|
|
18918
|
-
return value.length > 50 ? `"${value.substring(0, 47)}..."` : `"${value}"`;
|
|
18919
|
-
if (typeof value === 'object') {
|
|
18920
|
-
try {
|
|
18921
|
-
const keys = Object.keys(value);
|
|
18922
|
-
return `Object {${keys.slice(0, 3).join(', ')}${keys.length > 3 ? '...' : ''}}`;
|
|
18923
|
-
}
|
|
18924
|
-
catch {
|
|
18925
|
-
return '[Object]';
|
|
18926
|
-
}
|
|
18927
|
-
}
|
|
18928
|
-
return String(value);
|
|
18929
|
-
}
|
|
18930
19321
|
};
|
|
18931
19322
|
__setFunctionName(_classThis, "BeepCommand");
|
|
18932
19323
|
(() => {
|
|
@@ -19888,7 +20279,10 @@ function createUntilLoopConfig(conditionExpr, evaluateCondition, context, indexV
|
|
|
19888
20279
|
};
|
|
19889
20280
|
const config = {
|
|
19890
20281
|
type: 'until',
|
|
19891
|
-
shouldContinue: () =>
|
|
20282
|
+
shouldContinue: () => {
|
|
20283
|
+
const met = evaluateCondition(conditionExpr, context);
|
|
20284
|
+
return met instanceof Promise ? met.then(value => !value) : !met;
|
|
20285
|
+
},
|
|
19892
20286
|
};
|
|
19893
20287
|
return { config, iterCtx };
|
|
19894
20288
|
}
|
|
@@ -19937,6 +20331,18 @@ async function slotText(node, evaluator, context) {
|
|
|
19937
20331
|
const v = await evaluator.evaluate(node, context);
|
|
19938
20332
|
return typeof v === 'string' ? v : undefined;
|
|
19939
20333
|
}
|
|
20334
|
+
function isEventTarget(value) {
|
|
20335
|
+
return typeof value?.addEventListener === 'function';
|
|
20336
|
+
}
|
|
20337
|
+
async function evaluateLoopCondition(condition, context) {
|
|
20338
|
+
if (typeof condition === 'function')
|
|
20339
|
+
return Boolean(await condition());
|
|
20340
|
+
return evaluateCondition(condition, context);
|
|
20341
|
+
}
|
|
20342
|
+
function loopCount(value) {
|
|
20343
|
+
const count = Number(value);
|
|
20344
|
+
return Number.isNaN(count) ? 0 : count;
|
|
20345
|
+
}
|
|
19940
20346
|
let RepeatCommand = (() => {
|
|
19941
20347
|
let _classDecorators = [command({ name: 'repeat' })];
|
|
19942
20348
|
let _classDescriptor;
|
|
@@ -19994,17 +20400,24 @@ let RepeatCommand = (() => {
|
|
|
19994
20400
|
};
|
|
19995
20401
|
}
|
|
19996
20402
|
if (loopType === 'times' || m.times) {
|
|
19997
|
-
|
|
19998
|
-
const count = typeof countValue === 'number' ? countValue : parseInt(String(countValue), 10);
|
|
19999
|
-
if (isNaN(count))
|
|
20403
|
+
if (!m.times)
|
|
20000
20404
|
throw new Error('times loops require a count number');
|
|
20405
|
+
const count = loopCount(await evaluator.evaluate(m.times, context));
|
|
20001
20406
|
return { type: 'times', count, indexVariable, commands, elseCommands };
|
|
20002
20407
|
}
|
|
20003
20408
|
if (loopType === 'while' || m.while) {
|
|
20004
20409
|
const condition = m.while;
|
|
20005
20410
|
if (!condition)
|
|
20006
20411
|
throw new Error('while loops require a condition');
|
|
20007
|
-
|
|
20412
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20413
|
+
return {
|
|
20414
|
+
type: 'while',
|
|
20415
|
+
condition: check,
|
|
20416
|
+
indexVariable,
|
|
20417
|
+
commands,
|
|
20418
|
+
elseCommands,
|
|
20419
|
+
bottomTested,
|
|
20420
|
+
};
|
|
20008
20421
|
}
|
|
20009
20422
|
if (loopType === 'until-event' || m.event) {
|
|
20010
20423
|
const eventName = await text(m.event);
|
|
@@ -20022,7 +20435,7 @@ let RepeatCommand = (() => {
|
|
|
20022
20435
|
}
|
|
20023
20436
|
else {
|
|
20024
20437
|
const target = await evaluator.evaluate(m.from, context);
|
|
20025
|
-
if (target
|
|
20438
|
+
if (isEventTarget(target))
|
|
20026
20439
|
eventTarget = target;
|
|
20027
20440
|
else if (target === 'document')
|
|
20028
20441
|
eventTarget = document;
|
|
@@ -20043,7 +20456,15 @@ let RepeatCommand = (() => {
|
|
|
20043
20456
|
const condition = m.until;
|
|
20044
20457
|
if (!condition)
|
|
20045
20458
|
throw new Error('until loops require a condition');
|
|
20046
|
-
|
|
20459
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20460
|
+
return {
|
|
20461
|
+
type: 'until',
|
|
20462
|
+
condition: check,
|
|
20463
|
+
indexVariable,
|
|
20464
|
+
commands,
|
|
20465
|
+
elseCommands,
|
|
20466
|
+
bottomTested,
|
|
20467
|
+
};
|
|
20047
20468
|
}
|
|
20048
20469
|
if (loopType === 'forever') {
|
|
20049
20470
|
return { type: 'forever', indexVariable, commands, elseCommands };
|
|
@@ -20061,10 +20482,10 @@ let RepeatCommand = (() => {
|
|
|
20061
20482
|
({ config, iterCtx } = createTimesLoopConfig(count, indexVariable));
|
|
20062
20483
|
break;
|
|
20063
20484
|
case 'while':
|
|
20064
|
-
({ config, iterCtx } = createWhileLoopConfig(condition,
|
|
20485
|
+
({ config, iterCtx } = createWhileLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20065
20486
|
break;
|
|
20066
20487
|
case 'until':
|
|
20067
|
-
({ config, iterCtx } = createUntilLoopConfig(condition,
|
|
20488
|
+
({ config, iterCtx } = createUntilLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20068
20489
|
break;
|
|
20069
20490
|
case 'until-event':
|
|
20070
20491
|
({ config, iterCtx } = createUntilEventLoopConfig(eventName, eventTarget, indexVariable));
|
|
@@ -21095,6 +21516,29 @@ function namedPropertyOf(node) {
|
|
|
21095
21516
|
}
|
|
21096
21517
|
return null;
|
|
21097
21518
|
}
|
|
21519
|
+
const RESTORE_KEYWORDS = new Set(['initial', 'inherit', 'unset', 'revert']);
|
|
21520
|
+
function elementsOf(value) {
|
|
21521
|
+
if (Array.isArray(value) || isNodeList(value)) {
|
|
21522
|
+
return Array.from(value).filter(isHTMLElement$2);
|
|
21523
|
+
}
|
|
21524
|
+
return isHTMLElement$2(value) ? [value] : [];
|
|
21525
|
+
}
|
|
21526
|
+
async function valueOf(node, evaluator, context) {
|
|
21527
|
+
const value = await evaluator.evaluate(node, context);
|
|
21528
|
+
const name = node.name;
|
|
21529
|
+
if (value === undefined && node.type === 'identifier' && typeof name === 'string')
|
|
21530
|
+
return name;
|
|
21531
|
+
return value;
|
|
21532
|
+
}
|
|
21533
|
+
function longestTransitionMs(css) {
|
|
21534
|
+
let longest;
|
|
21535
|
+
for (const item of css.split(',')) {
|
|
21536
|
+
const times = [...item.matchAll(/(\d*\.?\d+)(ms|s)\b/g)].map(m => parseFloat(m[1]) * (m[2] === 's' ? 1000 : 1));
|
|
21537
|
+
if (times.length > 0)
|
|
21538
|
+
longest = Math.max(longest ?? 0, times[0] + (times[1] ?? 0));
|
|
21539
|
+
}
|
|
21540
|
+
return longest;
|
|
21541
|
+
}
|
|
21098
21542
|
let TransitionCommand = (() => {
|
|
21099
21543
|
let _classDecorators = [command({ name: 'transition' })];
|
|
21100
21544
|
let _classDescriptor;
|
|
@@ -21110,11 +21554,10 @@ let TransitionCommand = (() => {
|
|
|
21110
21554
|
let property;
|
|
21111
21555
|
let target;
|
|
21112
21556
|
const firstArg = await evaluator.evaluate(raw.args[0], context);
|
|
21113
|
-
const
|
|
21114
|
-
|
|
21115
|
-
if (isHTMLElement$2(firstAsElement) ||
|
|
21557
|
+
const owners = elementsOf(firstArg);
|
|
21558
|
+
if (owners.length > 0 ||
|
|
21116
21559
|
(typeof firstArg === 'string' && /^[#.]|^(?:me|it|you)$/.test(firstArg))) {
|
|
21117
|
-
target =
|
|
21560
|
+
target = owners.length === 1 ? owners[0] : owners.length > 1 ? owners : firstArg;
|
|
21118
21561
|
property = String(await evaluator.evaluate(raw.args[1], context));
|
|
21119
21562
|
}
|
|
21120
21563
|
else if (raw.args.length >= 2) {
|
|
@@ -21126,9 +21569,9 @@ let TransitionCommand = (() => {
|
|
|
21126
21569
|
throw new Error('transition requires a CSS property');
|
|
21127
21570
|
property = named.property;
|
|
21128
21571
|
if (named.objectNode !== undefined) {
|
|
21129
|
-
const owner =
|
|
21130
|
-
if (
|
|
21131
|
-
target = owner;
|
|
21572
|
+
const owner = elementsOf(await evaluator.evaluate(named.objectNode, context));
|
|
21573
|
+
if (owner.length > 0)
|
|
21574
|
+
target = owner.length === 1 ? owner[0] : owner;
|
|
21132
21575
|
}
|
|
21133
21576
|
}
|
|
21134
21577
|
else {
|
|
@@ -21139,60 +21582,131 @@ let TransitionCommand = (() => {
|
|
|
21139
21582
|
}
|
|
21140
21583
|
if (!raw.modifiers?.to)
|
|
21141
21584
|
throw new Error('transition requires "to <value>"');
|
|
21142
|
-
|
|
21143
|
-
|
|
21144
|
-
value
|
|
21145
|
-
}
|
|
21146
|
-
const result = { property, value: value };
|
|
21585
|
+
const result = {
|
|
21586
|
+
property,
|
|
21587
|
+
value: await valueOf(raw.modifiers.to, evaluator, context),
|
|
21588
|
+
};
|
|
21147
21589
|
if (target !== undefined)
|
|
21148
21590
|
result.target = target;
|
|
21591
|
+
if (raw.modifiers?.from)
|
|
21592
|
+
result.from = await valueOf(raw.modifiers.from, evaluator, context);
|
|
21593
|
+
if (raw.modifiers?.pairs) {
|
|
21594
|
+
result.pairs = await this.laterPairs(raw.modifiers.pairs, evaluator, context);
|
|
21595
|
+
}
|
|
21149
21596
|
if (raw.modifiers?.over)
|
|
21150
21597
|
result.duration = await evaluator.evaluate(raw.modifiers.over, context);
|
|
21151
21598
|
if (raw.modifiers?.with)
|
|
21152
21599
|
result.timingFunction = String(await evaluator.evaluate(raw.modifiers.with, context));
|
|
21600
|
+
if (raw.modifiers?.using)
|
|
21601
|
+
result.using = String(await evaluator.evaluate(raw.modifiers.using, context));
|
|
21153
21602
|
return result;
|
|
21154
21603
|
}
|
|
21604
|
+
async laterPairs(node, evaluator, context) {
|
|
21605
|
+
const pairs = [];
|
|
21606
|
+
for (const pairNode of node.elements ?? []) {
|
|
21607
|
+
const fields = new Map();
|
|
21608
|
+
const properties = pairNode
|
|
21609
|
+
.properties ?? [];
|
|
21610
|
+
for (const { key, value } of properties) {
|
|
21611
|
+
if (typeof key.name === 'string')
|
|
21612
|
+
fields.set(key.name, value);
|
|
21613
|
+
}
|
|
21614
|
+
const propertyNode = fields.get('property');
|
|
21615
|
+
const toNode = fields.get('to');
|
|
21616
|
+
if (!propertyNode || !toNode)
|
|
21617
|
+
throw new Error('transition requires property and value');
|
|
21618
|
+
const pair = {
|
|
21619
|
+
property: String(await evaluator.evaluate(propertyNode, context)),
|
|
21620
|
+
value: await valueOf(toNode, evaluator, context),
|
|
21621
|
+
};
|
|
21622
|
+
const ownerNode = fields.get('owner');
|
|
21623
|
+
if (ownerNode) {
|
|
21624
|
+
const owners = elementsOf(await evaluator.evaluate(ownerNode, context));
|
|
21625
|
+
if (owners.length === 0)
|
|
21626
|
+
throw new Error('transition: target element not found');
|
|
21627
|
+
pair.target = owners.length === 1 ? owners[0] : owners;
|
|
21628
|
+
}
|
|
21629
|
+
const fromNode = fields.get('from');
|
|
21630
|
+
if (fromNode)
|
|
21631
|
+
pair.from = await valueOf(fromNode, evaluator, context);
|
|
21632
|
+
pairs.push(pair);
|
|
21633
|
+
}
|
|
21634
|
+
return pairs;
|
|
21635
|
+
}
|
|
21155
21636
|
async execute(input, context) {
|
|
21156
|
-
|
|
21157
|
-
const
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21164
|
-
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
toValue = getComputedStyle(targetElement).getPropertyValue(property);
|
|
21178
|
-
if (currentInline) {
|
|
21179
|
-
targetElement.style.setProperty(property, currentInline);
|
|
21180
|
-
}
|
|
21181
|
-
removeInlineAfter = true;
|
|
21182
|
-
}
|
|
21183
|
-
targetElement.style.setProperty(property, toValue);
|
|
21184
|
-
const result = await waitForTransitionEnd(targetElement, property, duration);
|
|
21185
|
-
targetElement.style.transition = originalTransition;
|
|
21186
|
-
if (removeInlineAfter) {
|
|
21187
|
-
targetElement.style.removeProperty(property);
|
|
21637
|
+
const duration = parseDuration(input.duration, (input.using !== undefined && longestTransitionMs(input.using)) || 300);
|
|
21638
|
+
const timing = input.timingFunction || 'ease';
|
|
21639
|
+
const jobs = [];
|
|
21640
|
+
for (const pair of [input, ...(input.pairs ?? [])]) {
|
|
21641
|
+
let property = pair.property;
|
|
21642
|
+
if (property.startsWith('*'))
|
|
21643
|
+
property = property.substring(1);
|
|
21644
|
+
property = camelToKebab(property);
|
|
21645
|
+
const elements = Array.isArray(pair.target)
|
|
21646
|
+
? pair.target.filter(isHTMLElement$2)
|
|
21647
|
+
: [resolveElement(pair.target, context, 'transition')];
|
|
21648
|
+
for (const element of elements) {
|
|
21649
|
+
jobs.push({
|
|
21650
|
+
element,
|
|
21651
|
+
property,
|
|
21652
|
+
pair,
|
|
21653
|
+
fromValue: getComputedStyle(element).getPropertyValue(property),
|
|
21654
|
+
toValue: '',
|
|
21655
|
+
removeInlineAfter: false,
|
|
21656
|
+
});
|
|
21657
|
+
}
|
|
21188
21658
|
}
|
|
21659
|
+
if (jobs.length === 0)
|
|
21660
|
+
throw new Error('transition: target element not found');
|
|
21661
|
+
for (const job of jobs) {
|
|
21662
|
+
if (job.pair.from !== undefined) {
|
|
21663
|
+
job.element.style.setProperty(job.property, String(job.pair.from));
|
|
21664
|
+
}
|
|
21665
|
+
}
|
|
21666
|
+
for (const job of jobs)
|
|
21667
|
+
if (job.pair.from !== undefined)
|
|
21668
|
+
void job.element.offsetWidth;
|
|
21669
|
+
const originals = new Map();
|
|
21670
|
+
for (const job of jobs) {
|
|
21671
|
+
if (!originals.has(job.element))
|
|
21672
|
+
originals.set(job.element, job.element.style.transition);
|
|
21673
|
+
}
|
|
21674
|
+
for (const [element, original] of originals) {
|
|
21675
|
+
const own = jobs
|
|
21676
|
+
.filter(job => job.element === element)
|
|
21677
|
+
.map(job => `${job.property} ${duration}ms ${timing}`);
|
|
21678
|
+
element.style.transition = input.using ?? [original, ...own].filter(Boolean).join(', ');
|
|
21679
|
+
}
|
|
21680
|
+
for (const job of jobs) {
|
|
21681
|
+
const { element, property } = job;
|
|
21682
|
+
let toValue = String(job.pair.value);
|
|
21683
|
+
if (RESTORE_KEYWORDS.has(toValue)) {
|
|
21684
|
+
const currentInline = element.style.getPropertyValue(property);
|
|
21685
|
+
element.style.removeProperty(property);
|
|
21686
|
+
toValue = getComputedStyle(element).getPropertyValue(property);
|
|
21687
|
+
if (currentInline) {
|
|
21688
|
+
element.style.setProperty(property, currentInline);
|
|
21689
|
+
}
|
|
21690
|
+
job.removeInlineAfter = true;
|
|
21691
|
+
}
|
|
21692
|
+
job.toValue = toValue;
|
|
21693
|
+
element.style.setProperty(property, toValue);
|
|
21694
|
+
}
|
|
21695
|
+
const results = await Promise.all(jobs.map(job => waitForTransitionEnd(job.element, job.property, duration)));
|
|
21696
|
+
for (const [element, original] of originals)
|
|
21697
|
+
element.style.transition = original;
|
|
21698
|
+
for (const job of jobs) {
|
|
21699
|
+
if (job.removeInlineAfter)
|
|
21700
|
+
job.element.style.removeProperty(job.property);
|
|
21701
|
+
}
|
|
21702
|
+
const first = jobs[0];
|
|
21189
21703
|
return {
|
|
21190
|
-
element:
|
|
21191
|
-
property,
|
|
21192
|
-
fromValue,
|
|
21193
|
-
toValue,
|
|
21704
|
+
element: first.element,
|
|
21705
|
+
property: first.property,
|
|
21706
|
+
fromValue: first.fromValue,
|
|
21707
|
+
toValue: first.toValue,
|
|
21194
21708
|
duration,
|
|
21195
|
-
completed: result.completed,
|
|
21709
|
+
completed: results.every(result => result.completed),
|
|
21196
21710
|
};
|
|
21197
21711
|
}
|
|
21198
21712
|
};
|
|
@@ -21205,13 +21719,16 @@ let TransitionCommand = (() => {
|
|
|
21205
21719
|
})();
|
|
21206
21720
|
_classThis.metadata = commandMeta({
|
|
21207
21721
|
description: 'Animate CSS properties using CSS transitions',
|
|
21208
|
-
syntax: 'transition [<
|
|
21722
|
+
syntax: 'transition <property> [from <value>] to <value> [<property> \u2026 to <value>]\u2026 [over <duration>] [using <css> | with <timing>]',
|
|
21209
21723
|
examples: [
|
|
21210
21724
|
'transition opacity to 0.5',
|
|
21211
21725
|
'transition my *opacity to 0 over 200ms',
|
|
21212
21726
|
"transition #box's *opacity to 0 over 200ms",
|
|
21213
21727
|
'transition left to 100px over 500ms',
|
|
21214
21728
|
'transition background-color to red over 1s with ease-in-out',
|
|
21729
|
+
'transition *width to 100px *height to 50px over 300ms',
|
|
21730
|
+
'transition *opacity of #panel from 0 to 1 over 200ms',
|
|
21731
|
+
'transition my *opacity to 0 using "opacity 1s ease-in"',
|
|
21215
21732
|
],
|
|
21216
21733
|
sideEffects: ['style-change', 'timing'],
|
|
21217
21734
|
category: 'animation',
|
|
@@ -22337,16 +22854,12 @@ class RenderCommand {
|
|
|
22337
22854
|
}
|
|
22338
22855
|
RenderCommand.metadata = commandMeta({
|
|
22339
22856
|
description: 'Render templates with @if, @else, and @repeat directives',
|
|
22340
|
-
syntax: [
|
|
22341
|
-
'render <template>',
|
|
22342
|
-
'render <template> with <variables>',
|
|
22343
|
-
'render <template> with (key: value, ...)',
|
|
22344
|
-
],
|
|
22857
|
+
syntax: ['render <template>', 'render <template> with <name>: <value>, ...'],
|
|
22345
22858
|
examples: [
|
|
22346
22859
|
'render myTemplate',
|
|
22347
|
-
'render myTemplate with
|
|
22348
|
-
'render "<template>Hello ${name}!</template>" with
|
|
22349
|
-
'render template with
|
|
22860
|
+
'render myTemplate with name: "Alice"',
|
|
22861
|
+
'render "<template>Hello ${name}!</template>" with name: "World"',
|
|
22862
|
+
'render template with items: data',
|
|
22350
22863
|
],
|
|
22351
22864
|
category: 'templates',
|
|
22352
22865
|
compatibility: 'standard',
|