@hyperfixi/core 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -36
- package/dist/ast/command-slots.d.ts +1 -1
- package/dist/ast/nodes.d.ts +2 -0
- package/dist/ast-utils/index.cjs +193 -48
- package/dist/ast-utils/index.mjs +193 -48
- package/dist/ast-utils/interchange/types.d.ts +19 -1
- package/dist/behaviors/index.cjs +19 -0
- package/dist/behaviors/index.mjs +19 -0
- package/dist/bundle-generator/index.cjs +24 -9
- package/dist/bundle-generator/index.mjs +24 -9
- package/dist/bundle-generator/parser-templates.d.ts +1 -1
- package/dist/chunks/bridge-Cnj8dQFV.js +2 -0
- package/dist/chunks/browser-modular-BNDYF6Dq.js +2 -0
- package/dist/chunks/index-DQi2o8Lk.js +2 -0
- package/dist/chunks/index-LLuwEQp0.js +2 -0
- package/dist/chunks/index-uCOQ8Qn0.js +2 -0
- package/dist/commands/animation/transition.d.ts +12 -6
- package/dist/commands/helpers/loop-executor.d.ts +2 -2
- package/dist/commands/helpers/numeric-target-parser.d.ts +1 -1
- package/dist/commands/helpers/variable-access.d.ts +5 -2
- package/dist/commands/helpers/write-target.d.ts +5 -0
- package/dist/commands/index.cjs +929 -425
- package/dist/commands/index.mjs +929 -425
- package/dist/commands/templates/render.d.ts +4 -4
- package/dist/commands/utility/beep.d.ts +0 -3
- package/dist/expressions/index.cjs +7 -13
- package/dist/expressions/index.mjs +7 -13
- package/dist/htmx/i18n-hooks.d.ts +4 -1
- package/dist/hyperfixi-browser-classic-i18n.js +1 -1
- package/dist/hyperfixi-browser.js +1 -1
- package/dist/hyperfixi-classic-i18n.js +1 -1
- package/dist/hyperfixi-hx-v4.js +1 -1
- package/dist/hyperfixi-hx.js +1 -1
- package/dist/hyperfixi-hybrid-complete.js +1 -1
- package/dist/hyperfixi-hybrid-hx.js +1 -1
- package/dist/hyperfixi-multilingual.js +1 -1
- package/dist/hyperfixi.js +1 -1
- package/dist/hyperfixi.mjs +1 -1
- package/dist/index.cjs +1140 -485
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +1140 -485
- package/dist/lib/swap-executor.d.ts +1 -1
- package/dist/lokascript-browser-classic-i18n.js +1 -1
- package/dist/lokascript-browser.js +1 -1
- package/dist/lokascript-hybrid-complete.js +1 -1
- package/dist/lokascript-hybrid-hx.js +1 -1
- package/dist/lokascript-multilingual.js +1 -1
- package/dist/metadata.cjs +9 -9
- package/dist/metadata.d.ts +1 -1
- package/dist/metadata.mjs +9 -9
- package/dist/parser/command-grammar.d.ts +1 -0
- package/dist/parser/full-parser.cjs +387 -153
- package/dist/parser/full-parser.mjs +387 -153
- package/dist/parser/helpers/parsing-helpers.d.ts +3 -0
- package/dist/parser/hybrid/index.cjs +3 -0
- package/dist/parser/hybrid/index.mjs +3 -0
- package/dist/parser/hybrid/parser-core.cjs +3 -0
- package/dist/parser/hybrid/parser-core.mjs +3 -0
- package/dist/parser/hybrid-parser.cjs +3 -0
- package/dist/parser/hybrid-parser.mjs +3 -0
- package/dist/parser/parser-types.d.ts +2 -0
- package/dist/parser/parser.d.ts +9 -0
- package/dist/parser/pratt-parser.d.ts +2 -0
- package/dist/registry/index.cjs +526 -210
- package/dist/registry/index.mjs +526 -210
- package/dist/utils/beep.d.ts +8 -0
- package/dist/version.d.ts +1 -1
- package/package.json +21 -18
- package/vocab/htmx/ar.js +22 -20
- package/vocab/htmx/bn.js +21 -5
- package/vocab/htmx/de.js +33 -10
- package/vocab/htmx/en.js +4 -1
- package/vocab/htmx/es.js +28 -9
- package/vocab/htmx/fr.js +28 -8
- package/vocab/htmx/he.js +22 -1
- package/vocab/htmx/hi.js +28 -7
- package/vocab/htmx/id.js +29 -10
- package/vocab/htmx/it.js +26 -5
- package/vocab/htmx/ja.js +36 -11
- package/vocab/htmx/ko.js +27 -6
- package/vocab/htmx/ms.js +24 -1
- package/vocab/htmx/pl.js +27 -7
- package/vocab/htmx/pt.js +30 -9
- package/vocab/htmx/qu.js +32 -9
- package/vocab/htmx/ru.js +28 -6
- package/vocab/htmx/sw.js +28 -8
- package/vocab/htmx/th.js +19 -1
- package/vocab/htmx/tl.js +24 -1
- package/vocab/htmx/tr.js +34 -8
- package/vocab/htmx/uk.js +28 -6
- package/vocab/htmx/vi.js +27 -19
- package/vocab/htmx/zh.js +28 -9
- package/dist/chunks/bridge-DylVo1oZ.js +0 -2
- package/dist/chunks/browser-modular-sLPMdxR7.js +0 -2
- package/dist/chunks/index-C7lqD4mo.js +0 -2
- package/dist/chunks/index-CAPhqA6k.js +0 -2
- package/dist/chunks/index-CLdRyZaP.js +0 -2
package/dist/commands/index.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')) {
|
|
@@ -9329,11 +9592,17 @@ function parseSwapCommand(ctx, identifierNode) {
|
|
|
9329
9592
|
const targetExpr = isDelete ? ctx.parseExpression() : parseOneArgument(ctx, [KEYWORDS.WITH]);
|
|
9330
9593
|
if (targetExpr)
|
|
9331
9594
|
args.push(targetExpr);
|
|
9332
|
-
|
|
9595
|
+
const isMorph = identifierNode.name === 'morph';
|
|
9596
|
+
if (!isDelete &&
|
|
9597
|
+
(consumeOptionalKeyword(ctx, KEYWORDS.WITH) ||
|
|
9598
|
+
(isMorph && consumeOptionalKeyword(ctx, KEYWORDS.TO)))) {
|
|
9333
9599
|
const contentExpr = parseOneArgument(ctx, ['using']);
|
|
9334
9600
|
if (contentExpr)
|
|
9335
9601
|
modifiers['with'] = contentExpr;
|
|
9336
9602
|
}
|
|
9603
|
+
if (isMorph && modifiers['with'] === undefined) {
|
|
9604
|
+
ctx.addError("Expected 'to' and the content to morph into");
|
|
9605
|
+
}
|
|
9337
9606
|
return CommandNodeBuilder.fromIdentifier(identifierNode)
|
|
9338
9607
|
.withArgs(...args)
|
|
9339
9608
|
.withModifiers({ ...modifiers, ...parseViewTransitionTail(ctx) })
|
|
@@ -10094,6 +10363,8 @@ function atArgumentBoundary(ctx, grammar) {
|
|
|
10094
10363
|
const next = ctx.peek();
|
|
10095
10364
|
if (ctx.checkIsCommand() && ctx.peekAt(1)?.value === '(')
|
|
10096
10365
|
return false;
|
|
10366
|
+
if (isGluedBeepBang(next, ctx.peekAt(1)))
|
|
10367
|
+
return false;
|
|
10097
10368
|
if (isCommandBoundary(ctx, ['catch', 'finally', 'on']))
|
|
10098
10369
|
return true;
|
|
10099
10370
|
return isKeyword(next, [...grammar.markers]);
|
|
@@ -10125,10 +10396,13 @@ function parseDeclaredCommand(ctx, commandToken, name, grammar) {
|
|
|
10125
10396
|
}
|
|
10126
10397
|
}
|
|
10127
10398
|
const commaList = new Set(grammar.commaList ?? []);
|
|
10399
|
+
const namedArgs = new Set(grammar.namedArgs ?? []);
|
|
10128
10400
|
while (!ctx.isAtEnd() && isKeyword(ctx.peek(), [...grammar.markers])) {
|
|
10129
10401
|
const keyword = ctx.advance().value;
|
|
10130
10402
|
const key = ctx.resolveKeyword(keyword).toLowerCase();
|
|
10131
|
-
let value =
|
|
10403
|
+
let value = namedArgs.has(key) && isNakedNamedArgStart(ctx)
|
|
10404
|
+
? parseNakedNamedArgs(ctx, () => ctx.parseExpression(), name)
|
|
10405
|
+
: ctx.parseExpression();
|
|
10132
10406
|
if (value && commaList.has(key) && ctx.check(',')) {
|
|
10133
10407
|
const elements = [value];
|
|
10134
10408
|
while (ctx.match(',')) {
|
|
@@ -10293,8 +10567,8 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10293
10567
|
}
|
|
10294
10568
|
if (ctx.check('with') && !modifiers['with']) {
|
|
10295
10569
|
ctx.advance();
|
|
10296
|
-
if (
|
|
10297
|
-
modifiers['with'] =
|
|
10570
|
+
if (isNakedNamedArgStart(ctx)) {
|
|
10571
|
+
modifiers['with'] = parseNakedNamedArgs(ctx, () => ctx.parsePrimary(), 'fetch');
|
|
10298
10572
|
}
|
|
10299
10573
|
else {
|
|
10300
10574
|
modifiers['with'] = ctx.parsePrimary();
|
|
@@ -10329,45 +10603,6 @@ function parseFetchCommand(ctx, commandToken) {
|
|
|
10329
10603
|
}
|
|
10330
10604
|
return builder.build();
|
|
10331
10605
|
}
|
|
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
10606
|
function findJsEndBoundary(ctx, startPos) {
|
|
10372
10607
|
const input = ctx.getInputSlice(startPos);
|
|
10373
10608
|
if (!input) {
|
|
@@ -10487,6 +10722,7 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10487
10722
|
const commands = [];
|
|
10488
10723
|
while (!ctx.isAtEnd()) {
|
|
10489
10724
|
if (ctx.checkIsCommand()) {
|
|
10725
|
+
const word = ctx.peek().value;
|
|
10490
10726
|
try {
|
|
10491
10727
|
ctx.advance();
|
|
10492
10728
|
const cmd = ctx.parseCommand();
|
|
@@ -10497,7 +10733,8 @@ function parseTellCommand(ctx, identifierNode) {
|
|
|
10497
10733
|
break;
|
|
10498
10734
|
}
|
|
10499
10735
|
}
|
|
10500
|
-
catch {
|
|
10736
|
+
catch (error) {
|
|
10737
|
+
ctx.addError(`'${word}' in a tell body failed to parse: ${error instanceof Error ? error.message : String(error)}`);
|
|
10501
10738
|
break;
|
|
10502
10739
|
}
|
|
10503
10740
|
if (ctx.match(KEYWORDS.AND) || ctx.match(KEYWORDS.THEN)) {
|
|
@@ -10646,7 +10883,6 @@ const ONE_EXPR = (syntax) => ({
|
|
|
10646
10883
|
markers: [],
|
|
10647
10884
|
syntax,
|
|
10648
10885
|
});
|
|
10649
|
-
const BEEP = ONE_EXPR('beep! [<expression>, \u2026]');
|
|
10650
10886
|
const COMMAND_GRAMMAR = {
|
|
10651
10887
|
append: { positional: 'expression', markers: ['to'], syntax: 'append <value> [to <target>]' },
|
|
10652
10888
|
prepend: { positional: 'expression', markers: ['to'], syntax: 'prepend <value> [to <target>]' },
|
|
@@ -10657,8 +10893,7 @@ const COMMAND_GRAMMAR = {
|
|
|
10657
10893
|
syntax: 'make (a|an) <type> [from <args>] [called <name>]',
|
|
10658
10894
|
},
|
|
10659
10895
|
throw: { positional: 'primary', markers: [], syntax: 'throw <error>' },
|
|
10660
|
-
'beep!'
|
|
10661
|
-
beep: BEEP,
|
|
10896
|
+
beep: ONE_EXPR('beep! [<expression>, \u2026]'),
|
|
10662
10897
|
blur: ONE_EXPR('blur [<target>]'),
|
|
10663
10898
|
break: NONE,
|
|
10664
10899
|
breakpoint: NONE,
|
|
@@ -10682,7 +10917,8 @@ const COMMAND_GRAMMAR = {
|
|
|
10682
10917
|
render: {
|
|
10683
10918
|
positional: 'expression',
|
|
10684
10919
|
markers: ['with'],
|
|
10685
|
-
|
|
10920
|
+
namedArgs: ['with'],
|
|
10921
|
+
syntax: 'render <template> [with <name>: <value>, \u2026]',
|
|
10686
10922
|
},
|
|
10687
10923
|
reset: ONE_EXPR('reset [<form>]'),
|
|
10688
10924
|
return: ONE_EXPR('return [<value>]'),
|
|
@@ -11037,7 +11273,10 @@ class Parser {
|
|
|
11037
11273
|
const firstToken = this.peek();
|
|
11038
11274
|
const prefixEntry = Parser.PRATT_TABLE.get(firstToken.value);
|
|
11039
11275
|
let left;
|
|
11040
|
-
if (
|
|
11276
|
+
if (isGluedBeepBang(firstToken, this.tokens[this.current + 1])) {
|
|
11277
|
+
left = this.parseBeepExpression();
|
|
11278
|
+
}
|
|
11279
|
+
else if (prefixEntry?.prefix) {
|
|
11041
11280
|
const token = this.advance();
|
|
11042
11281
|
if (this.isAtEnd()) {
|
|
11043
11282
|
this.addError(`Expected expression after '${token.value}' operator`);
|
|
@@ -11057,6 +11296,9 @@ class Parser {
|
|
|
11057
11296
|
continue;
|
|
11058
11297
|
}
|
|
11059
11298
|
}
|
|
11299
|
+
if (nextToken.value === '*' && this.isSpacedStyleRef(this.current)) {
|
|
11300
|
+
break;
|
|
11301
|
+
}
|
|
11060
11302
|
const infixEntry = Parser.PRATT_TABLE.get(nextToken.value);
|
|
11061
11303
|
if (!infixEntry?.infix) {
|
|
11062
11304
|
if (STOP_TOKENS.has(nextToken.value) || STOP_DELIMITERS.has(nextToken.value)) {
|
|
@@ -11118,6 +11360,35 @@ class Parser {
|
|
|
11118
11360
|
this.prattCache.set(cacheKey, { node: left, endPos: this.current });
|
|
11119
11361
|
return left;
|
|
11120
11362
|
}
|
|
11363
|
+
parseBeepExpression() {
|
|
11364
|
+
const beepToken = this.advance();
|
|
11365
|
+
this.advance();
|
|
11366
|
+
if (this.isAtEnd()) {
|
|
11367
|
+
this.addError("Expected expression after 'beep!'");
|
|
11368
|
+
return this.createErrorNode();
|
|
11369
|
+
}
|
|
11370
|
+
const operand = this.parseExpressionPratt(Parser.BEEP_OPERAND_BP);
|
|
11371
|
+
return {
|
|
11372
|
+
type: 'unaryExpression',
|
|
11373
|
+
operator: 'beep!',
|
|
11374
|
+
operand,
|
|
11375
|
+
argument: operand,
|
|
11376
|
+
prefix: true,
|
|
11377
|
+
start: beepToken.start,
|
|
11378
|
+
end: this.previous().end,
|
|
11379
|
+
line: beepToken.line,
|
|
11380
|
+
column: beepToken.column,
|
|
11381
|
+
};
|
|
11382
|
+
}
|
|
11383
|
+
isStyleRefStar(i) {
|
|
11384
|
+
const star = this.tokens[i];
|
|
11385
|
+
const name = this.tokens[i + 1];
|
|
11386
|
+
return star?.value === '*' && !!name && name.start === star.end && isIdentifierLike(name);
|
|
11387
|
+
}
|
|
11388
|
+
isSpacedStyleRef(i) {
|
|
11389
|
+
const prev = this.tokens[i - 1];
|
|
11390
|
+
return this.isStyleRefStar(i) && !!prev && prev.end < this.tokens[i].start;
|
|
11391
|
+
}
|
|
11121
11392
|
tryParseStringPostfix(left, nextToken) {
|
|
11122
11393
|
const v = nextToken.value;
|
|
11123
11394
|
let unit = null;
|
|
@@ -11320,6 +11591,10 @@ class Parser {
|
|
|
11320
11591
|
const isStop = () => this.check('end') || extraStops.some(s => this.check(s));
|
|
11321
11592
|
debug.parse('\ud83d\udd04 parseCommandListUntilTerminator: Starting (extraStops:', extraStops.join(','), ')');
|
|
11322
11593
|
while (!this.isAtEnd() && !isStop()) {
|
|
11594
|
+
if (this.checkComment()) {
|
|
11595
|
+
this.advance();
|
|
11596
|
+
continue;
|
|
11597
|
+
}
|
|
11323
11598
|
debug.parse('\ud83d\udccd Loop iteration, current token:', this.peek().value, 'kind:', this.peek().kind);
|
|
11324
11599
|
let parsedCommand = false;
|
|
11325
11600
|
const isCommandToken = this.checkIsCommand();
|
|
@@ -11403,7 +11678,7 @@ class Parser {
|
|
|
11403
11678
|
debug.parse('\u2705 Found "end", consuming it');
|
|
11404
11679
|
this.advance();
|
|
11405
11680
|
}
|
|
11406
|
-
else {
|
|
11681
|
+
else if (!this.atEndOfInput()) {
|
|
11407
11682
|
debug.parse('\u274c ERROR: Expected "end" but got:', this.peek().value, 'at position:', this.peek().start);
|
|
11408
11683
|
throw new Error(`Expected "end" to close ${construct} block`);
|
|
11409
11684
|
}
|
|
@@ -11416,7 +11691,7 @@ class Parser {
|
|
|
11416
11691
|
if (this.check('end')) {
|
|
11417
11692
|
this.advance();
|
|
11418
11693
|
}
|
|
11419
|
-
else {
|
|
11694
|
+
else if (!this.atEndOfInput()) {
|
|
11420
11695
|
throw new Error('Expected "end" to close repeat block');
|
|
11421
11696
|
}
|
|
11422
11697
|
}
|
|
@@ -11432,7 +11707,10 @@ class Parser {
|
|
|
11432
11707
|
this.advance();
|
|
11433
11708
|
}
|
|
11434
11709
|
else if (terminator === '') {
|
|
11435
|
-
|
|
11710
|
+
if (!this.atEndOfInput()) {
|
|
11711
|
+
throw new Error('Expected "end", "else", "until", or "while" to close repeat block');
|
|
11712
|
+
}
|
|
11713
|
+
return { commands, terminator: 'end' };
|
|
11436
11714
|
}
|
|
11437
11715
|
return { commands, terminator };
|
|
11438
11716
|
}
|
|
@@ -12016,7 +12294,9 @@ class Parser {
|
|
|
12016
12294
|
parseTopLevelInitBlock() {
|
|
12017
12295
|
const pos = this.getPosition();
|
|
12018
12296
|
const initCommands = this.parseCommandBlock(['end']);
|
|
12019
|
-
this.
|
|
12297
|
+
if (!this.match('end') && !this.atEndOfInput() && !this.checkFeatureStart()) {
|
|
12298
|
+
this.consume('end', "Expected 'end' after init block");
|
|
12299
|
+
}
|
|
12020
12300
|
return {
|
|
12021
12301
|
type: 'initBlock',
|
|
12022
12302
|
commands: initCommands,
|
|
@@ -12192,10 +12472,29 @@ class Parser {
|
|
|
12192
12472
|
...(sourceExpr.column !== undefined && { column: sourceExpr.column }),
|
|
12193
12473
|
};
|
|
12194
12474
|
}
|
|
12475
|
+
isArgumentListOnly(open) {
|
|
12476
|
+
let depth = 0;
|
|
12477
|
+
for (let i = open; i < this.tokens.length; i++) {
|
|
12478
|
+
const token = this.tokens[i];
|
|
12479
|
+
if (token.kind !== 'operator')
|
|
12480
|
+
continue;
|
|
12481
|
+
if (token.value === '(' || token.value === '[' || token.value === '{')
|
|
12482
|
+
depth++;
|
|
12483
|
+
else if (token.value === ')' || token.value === ']' || token.value === '}') {
|
|
12484
|
+
if (--depth === 0)
|
|
12485
|
+
return i === open + 1;
|
|
12486
|
+
}
|
|
12487
|
+
else if (token.value === ',' && depth === 1)
|
|
12488
|
+
return true;
|
|
12489
|
+
}
|
|
12490
|
+
return false;
|
|
12491
|
+
}
|
|
12195
12492
|
tryParsePseudoCommand(callExpr, sourceExpr) {
|
|
12196
12493
|
const methodName = callExpr.callee.name;
|
|
12197
12494
|
const nextToken = this.peek();
|
|
12198
|
-
const
|
|
12495
|
+
const nextIsArticle = nextToken.value.toLowerCase() === 'the';
|
|
12496
|
+
const hasPseudoCommandPattern = nextIsArticle ||
|
|
12497
|
+
Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(nextToken.value.toLowerCase()) ||
|
|
12199
12498
|
(isIdentifier(nextToken) && !this.isCommand(nextToken.value)) ||
|
|
12200
12499
|
isContextVar(nextToken);
|
|
12201
12500
|
if (!hasPseudoCommandPattern) {
|
|
@@ -12221,7 +12520,10 @@ class Parser {
|
|
|
12221
12520
|
});
|
|
12222
12521
|
}
|
|
12223
12522
|
let preposition;
|
|
12224
|
-
if (
|
|
12523
|
+
if (nextIsArticle) {
|
|
12524
|
+
this.advance();
|
|
12525
|
+
}
|
|
12526
|
+
else if (Parser.PSEUDO_COMMAND_PREPOSITIONS.includes(this.peek().value.toLowerCase())) {
|
|
12225
12527
|
preposition = this.advance().value.toLowerCase();
|
|
12226
12528
|
}
|
|
12227
12529
|
let targetExpr;
|
|
@@ -12385,10 +12687,22 @@ class Parser {
|
|
|
12385
12687
|
this.consume(']', "Expected ']' after event condition");
|
|
12386
12688
|
}
|
|
12387
12689
|
let target;
|
|
12690
|
+
let targetExpression;
|
|
12388
12691
|
if (this.match('from')) {
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12692
|
+
if (this.check('the'))
|
|
12693
|
+
this.advance();
|
|
12694
|
+
if (Parser.POSITIONAL_SOURCE_HEADS.has(this.peek().value.toLowerCase())) {
|
|
12695
|
+
const startIndex = this.current;
|
|
12696
|
+
targetExpression = this.parseExpression();
|
|
12697
|
+
target = this.tokens
|
|
12698
|
+
.slice(startIndex, this.current)
|
|
12699
|
+
.map(t => t.value)
|
|
12700
|
+
.join(' ');
|
|
12701
|
+
}
|
|
12702
|
+
else {
|
|
12703
|
+
target = this.advance().value;
|
|
12704
|
+
}
|
|
12705
|
+
debug.parse(`\ud83d\udd27 parseEventHandler: Parsed 'from' target: ${target}`);
|
|
12392
12706
|
this.parseTemporalKeywordModifiers(modifiers);
|
|
12393
12707
|
}
|
|
12394
12708
|
let attributeName;
|
|
@@ -12434,7 +12748,7 @@ class Parser {
|
|
|
12434
12748
|
const nextIsOpenParen = this.tokens[this.current + 1]?.value === '(';
|
|
12435
12749
|
const commandName = this.peek().value.toLowerCase();
|
|
12436
12750
|
const isSpecialBodyCommand = commandName === 'js' || commandName === 'tell';
|
|
12437
|
-
if (nextIsOpenParen && !isSpecialBodyCommand) {
|
|
12751
|
+
if (nextIsOpenParen && !isSpecialBodyCommand && this.isArgumentListOnly(this.current + 1)) {
|
|
12438
12752
|
let expr;
|
|
12439
12753
|
const savedError = this.error;
|
|
12440
12754
|
try {
|
|
@@ -12466,7 +12780,7 @@ class Parser {
|
|
|
12466
12780
|
}
|
|
12467
12781
|
}
|
|
12468
12782
|
}
|
|
12469
|
-
else if (this.checkIdentifier()) {
|
|
12783
|
+
else if (this.checkIdentifier() || this.checkEventNamedCall()) {
|
|
12470
12784
|
const token = this.peek();
|
|
12471
12785
|
if (this.isCommand(token.value)) {
|
|
12472
12786
|
const cmd = this.parseCommandWithErrorRecovery();
|
|
@@ -12575,6 +12889,7 @@ class Parser {
|
|
|
12575
12889
|
...(eventParams.length > 0 && { args: eventParams }),
|
|
12576
12890
|
...(condition && { condition: fromLegacyExpression(condition) }),
|
|
12577
12891
|
...(target && { target }),
|
|
12892
|
+
...(targetExpression && { targetExpression: fromLegacyExpression(targetExpression) }),
|
|
12578
12893
|
...(attributeName && { attributeName }),
|
|
12579
12894
|
...(watchTarget && { watchTarget: fromLegacyExpression(watchTarget) }),
|
|
12580
12895
|
...(customEventSource && { customEventSource }),
|
|
@@ -12830,10 +13145,9 @@ class Parser {
|
|
|
12830
13145
|
}
|
|
12831
13146
|
parseCommandCore() {
|
|
12832
13147
|
const commandToken = this.previous();
|
|
12833
|
-
|
|
13148
|
+
const commandName = commandToken.value;
|
|
12834
13149
|
if (commandName === 'beep' && this.check('!')) {
|
|
12835
13150
|
this.advance();
|
|
12836
|
-
commandName = 'beep!';
|
|
12837
13151
|
}
|
|
12838
13152
|
if (commandName === 'fetch') {
|
|
12839
13153
|
return parseFetchCommand(this.getContext(), commandToken);
|
|
@@ -12932,6 +13246,9 @@ class Parser {
|
|
|
12932
13246
|
args.push(this.parsePrimary());
|
|
12933
13247
|
}
|
|
12934
13248
|
const callNode = this.createCallExpression(createIdentifier(funcName, namePos), args);
|
|
13249
|
+
if (funcName === 'closest' && args.length > 0 && this.match('to')) {
|
|
13250
|
+
callNode.closestTo = this.parseExpression();
|
|
13251
|
+
}
|
|
12935
13252
|
if (funcName === 'next' || funcName === 'previous') {
|
|
12936
13253
|
const relativePositional = this.parseRelativePositionalModifiers();
|
|
12937
13254
|
if (relativePositional) {
|
|
@@ -12971,6 +13288,9 @@ class Parser {
|
|
|
12971
13288
|
}
|
|
12972
13289
|
parseTheXofY() {
|
|
12973
13290
|
const positionalKeywords = ['first', 'last', 'next', 'previous', 'random', 'closest'];
|
|
13291
|
+
if (this.isStyleRefStar(this.current)) {
|
|
13292
|
+
return this.parsePrimary();
|
|
13293
|
+
}
|
|
12974
13294
|
if (!this.checkIdentifier()) {
|
|
12975
13295
|
return this.createIdentifier('the');
|
|
12976
13296
|
}
|
|
@@ -12986,7 +13306,7 @@ class Parser {
|
|
|
12986
13306
|
return this.createIdentifier(propertyName);
|
|
12987
13307
|
}
|
|
12988
13308
|
this.advance();
|
|
12989
|
-
const target = this.
|
|
13309
|
+
const target = parseOfOperand(this.makePrattContext(), THE_OF_TARGET_BP);
|
|
12990
13310
|
return {
|
|
12991
13311
|
type: 'propertyOfExpression',
|
|
12992
13312
|
property: { type: 'identifier', name: propertyName },
|
|
@@ -13184,6 +13504,13 @@ class Parser {
|
|
|
13184
13504
|
checkLiteral() {
|
|
13185
13505
|
return this.checkPredicate(isLiteral);
|
|
13186
13506
|
}
|
|
13507
|
+
checkEventNamedCall() {
|
|
13508
|
+
if (this.isAtEnd() || !this.checkIdentifierLike() || this.checkIsCommand())
|
|
13509
|
+
return false;
|
|
13510
|
+
const token = this.peek();
|
|
13511
|
+
const next = this.tokens[this.current + 1];
|
|
13512
|
+
return next?.value === '(' && next.start === token.end;
|
|
13513
|
+
}
|
|
13187
13514
|
checkIdentifierLike() {
|
|
13188
13515
|
return this.checkPredicate(isIdentifierLike);
|
|
13189
13516
|
}
|
|
@@ -13292,6 +13619,22 @@ class Parser {
|
|
|
13292
13619
|
isAtEnd() {
|
|
13293
13620
|
return this.current >= this.tokens.length;
|
|
13294
13621
|
}
|
|
13622
|
+
atEndOfInput() {
|
|
13623
|
+
for (let i = this.current; i < this.tokens.length; i++) {
|
|
13624
|
+
if (!isComment(this.tokens[i]))
|
|
13625
|
+
return false;
|
|
13626
|
+
}
|
|
13627
|
+
return true;
|
|
13628
|
+
}
|
|
13629
|
+
checkFeatureStart() {
|
|
13630
|
+
if (this.isAtEnd())
|
|
13631
|
+
return false;
|
|
13632
|
+
const value = this.peek().value;
|
|
13633
|
+
return (value === 'init' ||
|
|
13634
|
+
value === 'on' ||
|
|
13635
|
+
value === 'def' ||
|
|
13636
|
+
getRegisteredFeature(value) !== undefined);
|
|
13637
|
+
}
|
|
13295
13638
|
peek() {
|
|
13296
13639
|
if (this.isAtEnd()) {
|
|
13297
13640
|
return { kind: 'unknown', value: '', start: 0, end: 0, line: 1, column: 1 };
|
|
@@ -13503,6 +13846,7 @@ class Parser {
|
|
|
13503
13846
|
match: this.match.bind(this),
|
|
13504
13847
|
matchOperator: this.matchOperator.bind(this),
|
|
13505
13848
|
isAtEnd: this.isAtEnd.bind(this),
|
|
13849
|
+
atEndOfInput: this.atEndOfInput.bind(this),
|
|
13506
13850
|
createIdentifier: this.createIdentifier.bind(this),
|
|
13507
13851
|
parseExpression: this.parseExpression.bind(this),
|
|
13508
13852
|
parsePrimary: this.parsePrimary.bind(this),
|
|
@@ -13553,7 +13897,15 @@ Parser.POSTFIX_UNARY_OPERATORS = new Set([
|
|
|
13553
13897
|
'ignoring case',
|
|
13554
13898
|
]);
|
|
13555
13899
|
Parser.PRATT_TABLE = PARSER_TABLE;
|
|
13900
|
+
Parser.BEEP_OPERAND_BP = 80;
|
|
13556
13901
|
Parser.PSEUDO_COMMAND_PREPOSITIONS = ['from', 'on', 'with', 'into', 'at', 'to'];
|
|
13902
|
+
Parser.POSITIONAL_SOURCE_HEADS = new Set([
|
|
13903
|
+
'closest',
|
|
13904
|
+
'next',
|
|
13905
|
+
'previous',
|
|
13906
|
+
'first',
|
|
13907
|
+
'last',
|
|
13908
|
+
]);
|
|
13557
13909
|
function parse(input, options) {
|
|
13558
13910
|
const tokens = tokenize(input);
|
|
13559
13911
|
const parser = new Parser(tokens, options, input);
|
|
@@ -13995,11 +14347,16 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
13995
14347
|
}
|
|
13996
14348
|
}
|
|
13997
14349
|
}
|
|
13998
|
-
if (leftNode?.type === 'selector' &&
|
|
14350
|
+
if (leftNode?.type === 'selector' &&
|
|
14351
|
+
typeof leftNode.value === 'string' &&
|
|
14352
|
+
(leftNode.fromQuery || (operator === 'in' && leftNode.value.startsWith('.')))) {
|
|
13999
14353
|
const root = await evaluateAST(node.right, context);
|
|
14000
14354
|
const scope = root && typeof root.querySelectorAll === 'function' ? root : null;
|
|
14001
14355
|
if (scope) {
|
|
14002
|
-
|
|
14356
|
+
const query = leftNode.fromQuery
|
|
14357
|
+
? leftNode.value
|
|
14358
|
+
: escapeSelectorForQuery(leftNode, leftNode.value);
|
|
14359
|
+
return Array.from(scope.querySelectorAll(query));
|
|
14003
14360
|
}
|
|
14004
14361
|
}
|
|
14005
14362
|
}
|
|
@@ -14011,6 +14368,12 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14011
14368
|
return getExpr(context, 'styleRef').evaluate(context, leftNode.value.slice(1), el);
|
|
14012
14369
|
}
|
|
14013
14370
|
if (operator === 'of') {
|
|
14371
|
+
if (leftNode?.type === 'attributeAccess') {
|
|
14372
|
+
const target = await evaluateAST(node.right, context);
|
|
14373
|
+
if (target == null)
|
|
14374
|
+
return undefined;
|
|
14375
|
+
return getExpr(context, 'possessive').evaluate(context, target, `@${leftNode.attributeName}`);
|
|
14376
|
+
}
|
|
14014
14377
|
const path = propertyPathOf(node.left);
|
|
14015
14378
|
if (path) {
|
|
14016
14379
|
const target = await evaluateAST(node.right, context);
|
|
@@ -14018,6 +14381,10 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14018
14381
|
for (const seg of path) {
|
|
14019
14382
|
if (cur == null)
|
|
14020
14383
|
return undefined;
|
|
14384
|
+
if (isMappableCollection(cur) && !(seg in cur)) {
|
|
14385
|
+
cur = await getExpr(context, 'possessive').evaluate(context, cur, seg);
|
|
14386
|
+
continue;
|
|
14387
|
+
}
|
|
14021
14388
|
cur = isElement(cur) ? getElementProperty$1(cur, seg) : cur[seg];
|
|
14022
14389
|
}
|
|
14023
14390
|
return typeof cur === 'function' ? cur.bind(target) : cur;
|
|
@@ -14042,26 +14409,21 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
14042
14409
|
const R = node.ignoringCase ? applyCI(right) : right;
|
|
14043
14410
|
switch (operator) {
|
|
14044
14411
|
case '+': {
|
|
14045
|
-
let addLeft = left;
|
|
14046
|
-
let addRight = right;
|
|
14047
14412
|
if (node.coerceNumeric) {
|
|
14048
|
-
|
|
14049
|
-
addLeft = convertToNumber(addLeft);
|
|
14050
|
-
if (typeof addRight === 'string')
|
|
14051
|
-
addRight = convertToNumber(addRight);
|
|
14413
|
+
return counterValue(left) + counterAmount(right);
|
|
14052
14414
|
}
|
|
14053
|
-
if (typeof
|
|
14054
|
-
return String(
|
|
14415
|
+
if (typeof left === 'string' || typeof right === 'string') {
|
|
14416
|
+
return String(left ?? '') + String(right ?? '');
|
|
14055
14417
|
}
|
|
14056
|
-
if (Array.isArray(
|
|
14057
|
-
return Array.isArray(
|
|
14418
|
+
if (Array.isArray(left)) {
|
|
14419
|
+
return Array.isArray(right) ? [...left, ...right] : [...left, right];
|
|
14058
14420
|
}
|
|
14059
|
-
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, {
|
|
14060
|
-
left: addLeft,
|
|
14061
|
-
right: addRight,
|
|
14062
|
-
}));
|
|
14421
|
+
return unwrapTypedResult(await getExpr(context, 'addition').evaluate(context, { left, right }));
|
|
14063
14422
|
}
|
|
14064
14423
|
case '-':
|
|
14424
|
+
if (node.coerceNumeric) {
|
|
14425
|
+
return counterValue(left) - counterAmount(right);
|
|
14426
|
+
}
|
|
14065
14427
|
return unwrapTypedResult(await getExpr(context, 'subtraction').evaluate(context, { left, right }));
|
|
14066
14428
|
case '*':
|
|
14067
14429
|
return unwrapTypedResult(await getExpr(context, 'multiplication').evaluate(context, { left, right }));
|
|
@@ -14319,9 +14681,8 @@ async function evaluatePropertyOfExpressionNode(node, context) {
|
|
|
14319
14681
|
}
|
|
14320
14682
|
const propertyName = propertyNode.name;
|
|
14321
14683
|
const target = await evaluateAST(node.target, context);
|
|
14322
|
-
if (target == null)
|
|
14323
|
-
|
|
14324
|
-
}
|
|
14684
|
+
if (target == null)
|
|
14685
|
+
return undefined;
|
|
14325
14686
|
return getExpr(context, 'possessive').evaluate(context, target, propertyName);
|
|
14326
14687
|
}
|
|
14327
14688
|
async function evaluateTemplateLiteralNode(node, context) {
|
|
@@ -14439,6 +14800,9 @@ async function evaluateUnaryExpression(node, context) {
|
|
|
14439
14800
|
case 'not':
|
|
14440
14801
|
case '!':
|
|
14441
14802
|
return logicalExpressions.not.evaluate(context, value);
|
|
14803
|
+
case 'beep!':
|
|
14804
|
+
beepValues(context.me, [value]);
|
|
14805
|
+
return value;
|
|
14442
14806
|
case 'no':
|
|
14443
14807
|
return logicalExpressions.no.evaluate(context, value);
|
|
14444
14808
|
case '-':
|
|
@@ -14528,6 +14892,10 @@ async function evaluateCallExpression(node, context) {
|
|
|
14528
14892
|
const args = await resolveCallArgs(node.arguments, funcName, context);
|
|
14529
14893
|
switch (funcName) {
|
|
14530
14894
|
case 'closest':
|
|
14895
|
+
if (node.closestTo) {
|
|
14896
|
+
const start = unwrapElement(await evaluateAST(node.closestTo, context)) ?? null;
|
|
14897
|
+
return referencesExpressions.closest.evaluate(context, args[0], start);
|
|
14898
|
+
}
|
|
14531
14899
|
return referencesExpressions.closest.evaluate(context, ...args);
|
|
14532
14900
|
case 'previous':
|
|
14533
14901
|
case 'next': {
|
|
@@ -15952,10 +16320,29 @@ const STRATEGY_KEYWORDS = {
|
|
|
15952
16320
|
innermorph: 'morph',
|
|
15953
16321
|
outermorph: 'morphOuter',
|
|
15954
16322
|
};
|
|
16323
|
+
function loneRootWithTag(content, tagName) {
|
|
16324
|
+
let root;
|
|
16325
|
+
if (typeof content === 'string') {
|
|
16326
|
+
const template = document.createElement('template');
|
|
16327
|
+
template.innerHTML = content;
|
|
16328
|
+
root = template.content.firstElementChild;
|
|
16329
|
+
if (!root || root.nextElementSibling)
|
|
16330
|
+
return null;
|
|
16331
|
+
}
|
|
16332
|
+
else {
|
|
16333
|
+
root = content.cloneNode(true);
|
|
16334
|
+
}
|
|
16335
|
+
return root.tagName === tagName && isHTMLElement$2(root) ? root : null;
|
|
16336
|
+
}
|
|
15955
16337
|
function executeSwap(target, content, strategy, morphOptions) {
|
|
15956
16338
|
const contentStr = content !== null && !isHTMLElement$2(content) ? content : '';
|
|
15957
16339
|
const contentEl = isHTMLElement$2(content) ? content : null;
|
|
15958
16340
|
switch (strategy) {
|
|
16341
|
+
case 'morphMerge': {
|
|
16342
|
+
const root = content !== null ? loneRootWithTag(content, target.tagName) : null;
|
|
16343
|
+
executeSwap(target, root ?? content, root ? 'morphOuter' : 'morph', morphOptions);
|
|
16344
|
+
break;
|
|
16345
|
+
}
|
|
15959
16346
|
case 'morph':
|
|
15960
16347
|
if (content !== null) {
|
|
15961
16348
|
try {
|
|
@@ -16245,7 +16632,7 @@ let MorphCommand = (() => {
|
|
|
16245
16632
|
if (args.length === 0 && modifiers.with === undefined) {
|
|
16246
16633
|
throw new Error('[HyperFixi] morph: command requires arguments');
|
|
16247
16634
|
}
|
|
16248
|
-
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : '
|
|
16635
|
+
const strategy = literalText(modifiers.strategy)?.toLowerCase() === 'over' ? 'morphOuter' : 'morphMerge';
|
|
16249
16636
|
const useViewTransition = modifiers.viewTransition !== undefined;
|
|
16250
16637
|
const targetNode = modifiers.on !== undefined ? modifiers.on : args[0];
|
|
16251
16638
|
const contentNode = modifiers.with !== undefined
|
|
@@ -17535,6 +17922,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17535
17922
|
}
|
|
17536
17923
|
return { kind: 'property', target: property };
|
|
17537
17924
|
}
|
|
17925
|
+
if (options.ofAndObjectProperty) {
|
|
17926
|
+
const access = ofOrPossessiveAccess(n);
|
|
17927
|
+
if (access) {
|
|
17928
|
+
const owner = await evaluator.evaluate(access.owner, context);
|
|
17929
|
+
const element = Array.isArray(owner) ? owner[0] : owner;
|
|
17930
|
+
if (access.isOf && isHTMLElement$2(element)) {
|
|
17931
|
+
return { kind: 'property', target: { element, property: access.name } };
|
|
17932
|
+
}
|
|
17933
|
+
if (isObjectOwner(owner)) {
|
|
17934
|
+
return { kind: 'member', container: owner, property: access.name };
|
|
17935
|
+
}
|
|
17936
|
+
}
|
|
17937
|
+
}
|
|
17538
17938
|
if (options.bareReference &&
|
|
17539
17939
|
(nodeType === 'identifier' || nodeType === 'variable' || nodeType === 'symbol') &&
|
|
17540
17940
|
typeof n.name === 'string') {
|
|
@@ -17544,6 +17944,19 @@ async function resolveWriteTarget(node, evaluator, context, options) {
|
|
|
17544
17944
|
}
|
|
17545
17945
|
return null;
|
|
17546
17946
|
}
|
|
17947
|
+
function ofOrPossessiveAccess(n) {
|
|
17948
|
+
const [owner, property, isOf] = n.type === 'possessiveExpression'
|
|
17949
|
+
? [n.object, n.property, false]
|
|
17950
|
+
: n.type === 'propertyOfExpression'
|
|
17951
|
+
? [n.target, n.property, false]
|
|
17952
|
+
: n.type === 'binaryExpression' && n.operator === 'of'
|
|
17953
|
+
? [n.right, n.left, true]
|
|
17954
|
+
: [undefined, undefined, false];
|
|
17955
|
+
const name = property?.name;
|
|
17956
|
+
if (!owner || typeof name !== 'string' || !/^[A-Za-z_$][\w$]*$/.test(name))
|
|
17957
|
+
return null;
|
|
17958
|
+
return { owner, name, isOf };
|
|
17959
|
+
}
|
|
17547
17960
|
|
|
17548
17961
|
function toSetInput(target, value) {
|
|
17549
17962
|
switch (target.kind) {
|
|
@@ -17565,10 +17978,18 @@ function toSetInput(target, value) {
|
|
|
17565
17978
|
property: target.target.property,
|
|
17566
17979
|
value,
|
|
17567
17980
|
};
|
|
17981
|
+
case 'member':
|
|
17982
|
+
return {
|
|
17983
|
+
type: 'member-assignment',
|
|
17984
|
+
container: target.container,
|
|
17985
|
+
property: target.property,
|
|
17986
|
+
value,
|
|
17987
|
+
};
|
|
17568
17988
|
default:
|
|
17569
17989
|
throw new Error(`set: unrequested write-target rung '${target.kind}'`);
|
|
17570
17990
|
}
|
|
17571
17991
|
}
|
|
17992
|
+
const SET_RUNGS = { nodeWriters: true, styleSplit: true, ofAndObjectProperty: true };
|
|
17572
17993
|
let SetCommand = (() => {
|
|
17573
17994
|
let _classDecorators = [command({ name: 'set' })];
|
|
17574
17995
|
let _classDescriptor;
|
|
@@ -17587,8 +18008,7 @@ let SetCommand = (() => {
|
|
|
17587
18008
|
const argScope = firstArg?.scope;
|
|
17588
18009
|
const writeTarget = await resolveWriteTarget(firstArg, evaluator, context, {
|
|
17589
18010
|
scopeElements: () => this.resolveTargets(raw.modifiers.on, evaluator, context),
|
|
17590
|
-
|
|
17591
|
-
styleSplit: true,
|
|
18011
|
+
...SET_RUNGS,
|
|
17592
18012
|
});
|
|
17593
18013
|
if (writeTarget) {
|
|
17594
18014
|
return toSetInput(writeTarget, await this.extractValue(raw, evaluator, context));
|
|
@@ -17914,12 +18334,30 @@ function getNodeType(node) {
|
|
|
17914
18334
|
return 'unknown';
|
|
17915
18335
|
return node.type || 'unknown';
|
|
17916
18336
|
}
|
|
18337
|
+
function propertyTarget(node) {
|
|
18338
|
+
const n = node;
|
|
18339
|
+
const owner = n.type === 'propertyOfExpression'
|
|
18340
|
+
? n.target
|
|
18341
|
+
: n.type === 'possessiveExpression' ||
|
|
18342
|
+
n.type === 'memberExpression' ||
|
|
18343
|
+
n.type === 'propertyAccess'
|
|
18344
|
+
? n.object
|
|
18345
|
+
: undefined;
|
|
18346
|
+
if (!owner || n.computed)
|
|
18347
|
+
return null;
|
|
18348
|
+
const p = n.property;
|
|
18349
|
+
const name = typeof p === 'string' ? p : typeof p?.name === 'string' ? p.name : undefined;
|
|
18350
|
+
if (!name || !/^[A-Za-z_$][\w$-]*$/.test(name))
|
|
18351
|
+
return null;
|
|
18352
|
+
return { owner, name };
|
|
18353
|
+
}
|
|
17917
18354
|
async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
17918
18355
|
if (!raw.args || raw.args.length === 0) {
|
|
17919
18356
|
throw new Error(`${commandName} command requires a target`);
|
|
17920
18357
|
}
|
|
17921
18358
|
const targetArg = raw.args[0];
|
|
17922
18359
|
let target;
|
|
18360
|
+
let property;
|
|
17923
18361
|
let extractedScope;
|
|
17924
18362
|
let customWrite;
|
|
17925
18363
|
const nodeType = getNodeType(targetArg);
|
|
@@ -17934,7 +18372,25 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17934
18372
|
}
|
|
17935
18373
|
else {
|
|
17936
18374
|
const writer = getRegisteredNodeWriter(nodeType);
|
|
17937
|
-
|
|
18375
|
+
const attribute = writer
|
|
18376
|
+
? null
|
|
18377
|
+
: await resolveAttributeWriteTarget(targetArg, evaluator, context, async () => context.me ? [context.me] : []);
|
|
18378
|
+
const prop = writer || attribute ? null : propertyTarget(targetArg);
|
|
18379
|
+
const owner = prop ? await evaluator.evaluate(prop.owner, context) : undefined;
|
|
18380
|
+
const ownerElement = Array.isArray(owner) ? owner[0] : owner;
|
|
18381
|
+
if (attribute?.elements[0]) {
|
|
18382
|
+
target = attribute.elements[0];
|
|
18383
|
+
property = `@${attribute.name}`;
|
|
18384
|
+
}
|
|
18385
|
+
else if (prop && isHTMLElement$2(ownerElement)) {
|
|
18386
|
+
target = ownerElement;
|
|
18387
|
+
property = prop.name;
|
|
18388
|
+
}
|
|
18389
|
+
else if (prop && isObjectOwner(owner)) {
|
|
18390
|
+
target = owner;
|
|
18391
|
+
property = prop.name;
|
|
18392
|
+
}
|
|
18393
|
+
else if (writer) {
|
|
17938
18394
|
const currentRaw = await evaluator.evaluate(targetArg, context);
|
|
17939
18395
|
const currentValue = typeof currentRaw === 'number'
|
|
17940
18396
|
? currentRaw
|
|
@@ -17972,24 +18428,22 @@ async function parseNumericTargetInput(raw, evaluator, context, commandName) {
|
|
|
17972
18428
|
if (typeof evaluated === 'number') {
|
|
17973
18429
|
amount = evaluated;
|
|
17974
18430
|
}
|
|
18431
|
+
else if (evaluated == null) {
|
|
18432
|
+
amount = NaN;
|
|
18433
|
+
}
|
|
17975
18434
|
}
|
|
17976
18435
|
}
|
|
17977
18436
|
const byModifier = raw.modifiers?.by;
|
|
17978
18437
|
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
|
-
}
|
|
18438
|
+
const value = getNodeType(byModifier) === 'literal'
|
|
18439
|
+
? byModifier.value
|
|
18440
|
+
: await evaluator.evaluate(byModifier, context);
|
|
18441
|
+
amount = counterAmount(value);
|
|
17989
18442
|
}
|
|
17990
18443
|
return {
|
|
17991
18444
|
target,
|
|
17992
18445
|
amount,
|
|
18446
|
+
...(property && { property }),
|
|
17993
18447
|
...(scope && { scope }),
|
|
17994
18448
|
...(customWrite && { customWrite }),
|
|
17995
18449
|
};
|
|
@@ -18012,7 +18466,7 @@ let NumericModifyCommand = (() => {
|
|
|
18012
18466
|
async execute(input, context) {
|
|
18013
18467
|
const { target, property, scope, amount = 1, operation = 'increment', customWrite } = input;
|
|
18014
18468
|
if (customWrite) {
|
|
18015
|
-
const delta =
|
|
18469
|
+
const delta = amount;
|
|
18016
18470
|
const newValue = operation === 'increment'
|
|
18017
18471
|
? customWrite.currentValue + delta
|
|
18018
18472
|
: customWrite.currentValue - delta;
|
|
@@ -18026,8 +18480,7 @@ let NumericModifyCommand = (() => {
|
|
|
18026
18480
|
newValue = NaN;
|
|
18027
18481
|
}
|
|
18028
18482
|
else {
|
|
18029
|
-
|
|
18030
|
-
newValue = operation === 'increment' ? currentValue + delta : currentValue - delta;
|
|
18483
|
+
newValue = operation === 'increment' ? currentValue + amount : currentValue - amount;
|
|
18031
18484
|
}
|
|
18032
18485
|
setTargetValue(target, property, scope, newValue, context);
|
|
18033
18486
|
Object.assign(context, { it: newValue });
|
|
@@ -18843,17 +19296,7 @@ let BeepCommand = (() => {
|
|
|
18843
19296
|
this.debugContext(context);
|
|
18844
19297
|
return { expressionCount: 0, debugged: true, outputs: [] };
|
|
18845
19298
|
}
|
|
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();
|
|
19299
|
+
const outputs = beepValues(context.me, expressions);
|
|
18857
19300
|
return { expressionCount: expressions.length, debugged: true, outputs };
|
|
18858
19301
|
}
|
|
18859
19302
|
debugContext(context) {
|
|
@@ -18866,67 +19309,6 @@ let BeepCommand = (() => {
|
|
|
18866
19309
|
console.log('variables:', context.variables);
|
|
18867
19310
|
console.groupEnd();
|
|
18868
19311
|
}
|
|
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
19312
|
};
|
|
18931
19313
|
__setFunctionName(_classThis, "BeepCommand");
|
|
18932
19314
|
(() => {
|
|
@@ -19888,7 +20270,10 @@ function createUntilLoopConfig(conditionExpr, evaluateCondition, context, indexV
|
|
|
19888
20270
|
};
|
|
19889
20271
|
const config = {
|
|
19890
20272
|
type: 'until',
|
|
19891
|
-
shouldContinue: () =>
|
|
20273
|
+
shouldContinue: () => {
|
|
20274
|
+
const met = evaluateCondition(conditionExpr, context);
|
|
20275
|
+
return met instanceof Promise ? met.then(value => !value) : !met;
|
|
20276
|
+
},
|
|
19892
20277
|
};
|
|
19893
20278
|
return { config, iterCtx };
|
|
19894
20279
|
}
|
|
@@ -19937,6 +20322,18 @@ async function slotText(node, evaluator, context) {
|
|
|
19937
20322
|
const v = await evaluator.evaluate(node, context);
|
|
19938
20323
|
return typeof v === 'string' ? v : undefined;
|
|
19939
20324
|
}
|
|
20325
|
+
function isEventTarget(value) {
|
|
20326
|
+
return typeof value?.addEventListener === 'function';
|
|
20327
|
+
}
|
|
20328
|
+
async function evaluateLoopCondition(condition, context) {
|
|
20329
|
+
if (typeof condition === 'function')
|
|
20330
|
+
return Boolean(await condition());
|
|
20331
|
+
return evaluateCondition(condition, context);
|
|
20332
|
+
}
|
|
20333
|
+
function loopCount(value) {
|
|
20334
|
+
const count = Number(value);
|
|
20335
|
+
return Number.isNaN(count) ? 0 : count;
|
|
20336
|
+
}
|
|
19940
20337
|
let RepeatCommand = (() => {
|
|
19941
20338
|
let _classDecorators = [command({ name: 'repeat' })];
|
|
19942
20339
|
let _classDescriptor;
|
|
@@ -19994,17 +20391,24 @@ let RepeatCommand = (() => {
|
|
|
19994
20391
|
};
|
|
19995
20392
|
}
|
|
19996
20393
|
if (loopType === 'times' || m.times) {
|
|
19997
|
-
|
|
19998
|
-
const count = typeof countValue === 'number' ? countValue : parseInt(String(countValue), 10);
|
|
19999
|
-
if (isNaN(count))
|
|
20394
|
+
if (!m.times)
|
|
20000
20395
|
throw new Error('times loops require a count number');
|
|
20396
|
+
const count = loopCount(await evaluator.evaluate(m.times, context));
|
|
20001
20397
|
return { type: 'times', count, indexVariable, commands, elseCommands };
|
|
20002
20398
|
}
|
|
20003
20399
|
if (loopType === 'while' || m.while) {
|
|
20004
20400
|
const condition = m.while;
|
|
20005
20401
|
if (!condition)
|
|
20006
20402
|
throw new Error('while loops require a condition');
|
|
20007
|
-
|
|
20403
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20404
|
+
return {
|
|
20405
|
+
type: 'while',
|
|
20406
|
+
condition: check,
|
|
20407
|
+
indexVariable,
|
|
20408
|
+
commands,
|
|
20409
|
+
elseCommands,
|
|
20410
|
+
bottomTested,
|
|
20411
|
+
};
|
|
20008
20412
|
}
|
|
20009
20413
|
if (loopType === 'until-event' || m.event) {
|
|
20010
20414
|
const eventName = await text(m.event);
|
|
@@ -20022,7 +20426,7 @@ let RepeatCommand = (() => {
|
|
|
20022
20426
|
}
|
|
20023
20427
|
else {
|
|
20024
20428
|
const target = await evaluator.evaluate(m.from, context);
|
|
20025
|
-
if (target
|
|
20429
|
+
if (isEventTarget(target))
|
|
20026
20430
|
eventTarget = target;
|
|
20027
20431
|
else if (target === 'document')
|
|
20028
20432
|
eventTarget = document;
|
|
@@ -20043,7 +20447,15 @@ let RepeatCommand = (() => {
|
|
|
20043
20447
|
const condition = m.until;
|
|
20044
20448
|
if (!condition)
|
|
20045
20449
|
throw new Error('until loops require a condition');
|
|
20046
|
-
|
|
20450
|
+
const check = () => evaluator.evaluate(condition, context);
|
|
20451
|
+
return {
|
|
20452
|
+
type: 'until',
|
|
20453
|
+
condition: check,
|
|
20454
|
+
indexVariable,
|
|
20455
|
+
commands,
|
|
20456
|
+
elseCommands,
|
|
20457
|
+
bottomTested,
|
|
20458
|
+
};
|
|
20047
20459
|
}
|
|
20048
20460
|
if (loopType === 'forever') {
|
|
20049
20461
|
return { type: 'forever', indexVariable, commands, elseCommands };
|
|
@@ -20061,10 +20473,10 @@ let RepeatCommand = (() => {
|
|
|
20061
20473
|
({ config, iterCtx } = createTimesLoopConfig(count, indexVariable));
|
|
20062
20474
|
break;
|
|
20063
20475
|
case 'while':
|
|
20064
|
-
({ config, iterCtx } = createWhileLoopConfig(condition,
|
|
20476
|
+
({ config, iterCtx } = createWhileLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20065
20477
|
break;
|
|
20066
20478
|
case 'until':
|
|
20067
|
-
({ config, iterCtx } = createUntilLoopConfig(condition,
|
|
20479
|
+
({ config, iterCtx } = createUntilLoopConfig(condition, evaluateLoopCondition, context, indexVariable));
|
|
20068
20480
|
break;
|
|
20069
20481
|
case 'until-event':
|
|
20070
20482
|
({ config, iterCtx } = createUntilEventLoopConfig(eventName, eventTarget, indexVariable));
|
|
@@ -21095,6 +21507,29 @@ function namedPropertyOf(node) {
|
|
|
21095
21507
|
}
|
|
21096
21508
|
return null;
|
|
21097
21509
|
}
|
|
21510
|
+
const RESTORE_KEYWORDS = new Set(['initial', 'inherit', 'unset', 'revert']);
|
|
21511
|
+
function elementsOf(value) {
|
|
21512
|
+
if (Array.isArray(value) || isNodeList(value)) {
|
|
21513
|
+
return Array.from(value).filter(isHTMLElement$2);
|
|
21514
|
+
}
|
|
21515
|
+
return isHTMLElement$2(value) ? [value] : [];
|
|
21516
|
+
}
|
|
21517
|
+
async function valueOf(node, evaluator, context) {
|
|
21518
|
+
const value = await evaluator.evaluate(node, context);
|
|
21519
|
+
const name = node.name;
|
|
21520
|
+
if (value === undefined && node.type === 'identifier' && typeof name === 'string')
|
|
21521
|
+
return name;
|
|
21522
|
+
return value;
|
|
21523
|
+
}
|
|
21524
|
+
function longestTransitionMs(css) {
|
|
21525
|
+
let longest;
|
|
21526
|
+
for (const item of css.split(',')) {
|
|
21527
|
+
const times = [...item.matchAll(/(\d*\.?\d+)(ms|s)\b/g)].map(m => parseFloat(m[1]) * (m[2] === 's' ? 1000 : 1));
|
|
21528
|
+
if (times.length > 0)
|
|
21529
|
+
longest = Math.max(longest ?? 0, times[0] + (times[1] ?? 0));
|
|
21530
|
+
}
|
|
21531
|
+
return longest;
|
|
21532
|
+
}
|
|
21098
21533
|
let TransitionCommand = (() => {
|
|
21099
21534
|
let _classDecorators = [command({ name: 'transition' })];
|
|
21100
21535
|
let _classDescriptor;
|
|
@@ -21110,11 +21545,10 @@ let TransitionCommand = (() => {
|
|
|
21110
21545
|
let property;
|
|
21111
21546
|
let target;
|
|
21112
21547
|
const firstArg = await evaluator.evaluate(raw.args[0], context);
|
|
21113
|
-
const
|
|
21114
|
-
|
|
21115
|
-
if (isHTMLElement$2(firstAsElement) ||
|
|
21548
|
+
const owners = elementsOf(firstArg);
|
|
21549
|
+
if (owners.length > 0 ||
|
|
21116
21550
|
(typeof firstArg === 'string' && /^[#.]|^(?:me|it|you)$/.test(firstArg))) {
|
|
21117
|
-
target =
|
|
21551
|
+
target = owners.length === 1 ? owners[0] : owners.length > 1 ? owners : firstArg;
|
|
21118
21552
|
property = String(await evaluator.evaluate(raw.args[1], context));
|
|
21119
21553
|
}
|
|
21120
21554
|
else if (raw.args.length >= 2) {
|
|
@@ -21126,9 +21560,9 @@ let TransitionCommand = (() => {
|
|
|
21126
21560
|
throw new Error('transition requires a CSS property');
|
|
21127
21561
|
property = named.property;
|
|
21128
21562
|
if (named.objectNode !== undefined) {
|
|
21129
|
-
const owner =
|
|
21130
|
-
if (
|
|
21131
|
-
target = owner;
|
|
21563
|
+
const owner = elementsOf(await evaluator.evaluate(named.objectNode, context));
|
|
21564
|
+
if (owner.length > 0)
|
|
21565
|
+
target = owner.length === 1 ? owner[0] : owner;
|
|
21132
21566
|
}
|
|
21133
21567
|
}
|
|
21134
21568
|
else {
|
|
@@ -21139,60 +21573,131 @@ let TransitionCommand = (() => {
|
|
|
21139
21573
|
}
|
|
21140
21574
|
if (!raw.modifiers?.to)
|
|
21141
21575
|
throw new Error('transition requires "to <value>"');
|
|
21142
|
-
|
|
21143
|
-
|
|
21144
|
-
value
|
|
21145
|
-
}
|
|
21146
|
-
const result = { property, value: value };
|
|
21576
|
+
const result = {
|
|
21577
|
+
property,
|
|
21578
|
+
value: await valueOf(raw.modifiers.to, evaluator, context),
|
|
21579
|
+
};
|
|
21147
21580
|
if (target !== undefined)
|
|
21148
21581
|
result.target = target;
|
|
21582
|
+
if (raw.modifiers?.from)
|
|
21583
|
+
result.from = await valueOf(raw.modifiers.from, evaluator, context);
|
|
21584
|
+
if (raw.modifiers?.pairs) {
|
|
21585
|
+
result.pairs = await this.laterPairs(raw.modifiers.pairs, evaluator, context);
|
|
21586
|
+
}
|
|
21149
21587
|
if (raw.modifiers?.over)
|
|
21150
21588
|
result.duration = await evaluator.evaluate(raw.modifiers.over, context);
|
|
21151
21589
|
if (raw.modifiers?.with)
|
|
21152
21590
|
result.timingFunction = String(await evaluator.evaluate(raw.modifiers.with, context));
|
|
21591
|
+
if (raw.modifiers?.using)
|
|
21592
|
+
result.using = String(await evaluator.evaluate(raw.modifiers.using, context));
|
|
21153
21593
|
return result;
|
|
21154
21594
|
}
|
|
21595
|
+
async laterPairs(node, evaluator, context) {
|
|
21596
|
+
const pairs = [];
|
|
21597
|
+
for (const pairNode of node.elements ?? []) {
|
|
21598
|
+
const fields = new Map();
|
|
21599
|
+
const properties = pairNode
|
|
21600
|
+
.properties ?? [];
|
|
21601
|
+
for (const { key, value } of properties) {
|
|
21602
|
+
if (typeof key.name === 'string')
|
|
21603
|
+
fields.set(key.name, value);
|
|
21604
|
+
}
|
|
21605
|
+
const propertyNode = fields.get('property');
|
|
21606
|
+
const toNode = fields.get('to');
|
|
21607
|
+
if (!propertyNode || !toNode)
|
|
21608
|
+
throw new Error('transition requires property and value');
|
|
21609
|
+
const pair = {
|
|
21610
|
+
property: String(await evaluator.evaluate(propertyNode, context)),
|
|
21611
|
+
value: await valueOf(toNode, evaluator, context),
|
|
21612
|
+
};
|
|
21613
|
+
const ownerNode = fields.get('owner');
|
|
21614
|
+
if (ownerNode) {
|
|
21615
|
+
const owners = elementsOf(await evaluator.evaluate(ownerNode, context));
|
|
21616
|
+
if (owners.length === 0)
|
|
21617
|
+
throw new Error('transition: target element not found');
|
|
21618
|
+
pair.target = owners.length === 1 ? owners[0] : owners;
|
|
21619
|
+
}
|
|
21620
|
+
const fromNode = fields.get('from');
|
|
21621
|
+
if (fromNode)
|
|
21622
|
+
pair.from = await valueOf(fromNode, evaluator, context);
|
|
21623
|
+
pairs.push(pair);
|
|
21624
|
+
}
|
|
21625
|
+
return pairs;
|
|
21626
|
+
}
|
|
21155
21627
|
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);
|
|
21628
|
+
const duration = parseDuration(input.duration, (input.using !== undefined && longestTransitionMs(input.using)) || 300);
|
|
21629
|
+
const timing = input.timingFunction || 'ease';
|
|
21630
|
+
const jobs = [];
|
|
21631
|
+
for (const pair of [input, ...(input.pairs ?? [])]) {
|
|
21632
|
+
let property = pair.property;
|
|
21633
|
+
if (property.startsWith('*'))
|
|
21634
|
+
property = property.substring(1);
|
|
21635
|
+
property = camelToKebab(property);
|
|
21636
|
+
const elements = Array.isArray(pair.target)
|
|
21637
|
+
? pair.target.filter(isHTMLElement$2)
|
|
21638
|
+
: [resolveElement(pair.target, context, 'transition')];
|
|
21639
|
+
for (const element of elements) {
|
|
21640
|
+
jobs.push({
|
|
21641
|
+
element,
|
|
21642
|
+
property,
|
|
21643
|
+
pair,
|
|
21644
|
+
fromValue: getComputedStyle(element).getPropertyValue(property),
|
|
21645
|
+
toValue: '',
|
|
21646
|
+
removeInlineAfter: false,
|
|
21647
|
+
});
|
|
21648
|
+
}
|
|
21188
21649
|
}
|
|
21650
|
+
if (jobs.length === 0)
|
|
21651
|
+
throw new Error('transition: target element not found');
|
|
21652
|
+
for (const job of jobs) {
|
|
21653
|
+
if (job.pair.from !== undefined) {
|
|
21654
|
+
job.element.style.setProperty(job.property, String(job.pair.from));
|
|
21655
|
+
}
|
|
21656
|
+
}
|
|
21657
|
+
for (const job of jobs)
|
|
21658
|
+
if (job.pair.from !== undefined)
|
|
21659
|
+
void job.element.offsetWidth;
|
|
21660
|
+
const originals = new Map();
|
|
21661
|
+
for (const job of jobs) {
|
|
21662
|
+
if (!originals.has(job.element))
|
|
21663
|
+
originals.set(job.element, job.element.style.transition);
|
|
21664
|
+
}
|
|
21665
|
+
for (const [element, original] of originals) {
|
|
21666
|
+
const own = jobs
|
|
21667
|
+
.filter(job => job.element === element)
|
|
21668
|
+
.map(job => `${job.property} ${duration}ms ${timing}`);
|
|
21669
|
+
element.style.transition = input.using ?? [original, ...own].filter(Boolean).join(', ');
|
|
21670
|
+
}
|
|
21671
|
+
for (const job of jobs) {
|
|
21672
|
+
const { element, property } = job;
|
|
21673
|
+
let toValue = String(job.pair.value);
|
|
21674
|
+
if (RESTORE_KEYWORDS.has(toValue)) {
|
|
21675
|
+
const currentInline = element.style.getPropertyValue(property);
|
|
21676
|
+
element.style.removeProperty(property);
|
|
21677
|
+
toValue = getComputedStyle(element).getPropertyValue(property);
|
|
21678
|
+
if (currentInline) {
|
|
21679
|
+
element.style.setProperty(property, currentInline);
|
|
21680
|
+
}
|
|
21681
|
+
job.removeInlineAfter = true;
|
|
21682
|
+
}
|
|
21683
|
+
job.toValue = toValue;
|
|
21684
|
+
element.style.setProperty(property, toValue);
|
|
21685
|
+
}
|
|
21686
|
+
const results = await Promise.all(jobs.map(job => waitForTransitionEnd(job.element, job.property, duration)));
|
|
21687
|
+
for (const [element, original] of originals)
|
|
21688
|
+
element.style.transition = original;
|
|
21689
|
+
for (const job of jobs) {
|
|
21690
|
+
if (job.removeInlineAfter)
|
|
21691
|
+
job.element.style.removeProperty(job.property);
|
|
21692
|
+
}
|
|
21693
|
+
const first = jobs[0];
|
|
21189
21694
|
return {
|
|
21190
|
-
element:
|
|
21191
|
-
property,
|
|
21192
|
-
fromValue,
|
|
21193
|
-
toValue,
|
|
21695
|
+
element: first.element,
|
|
21696
|
+
property: first.property,
|
|
21697
|
+
fromValue: first.fromValue,
|
|
21698
|
+
toValue: first.toValue,
|
|
21194
21699
|
duration,
|
|
21195
|
-
completed: result.completed,
|
|
21700
|
+
completed: results.every(result => result.completed),
|
|
21196
21701
|
};
|
|
21197
21702
|
}
|
|
21198
21703
|
};
|
|
@@ -21205,13 +21710,16 @@ let TransitionCommand = (() => {
|
|
|
21205
21710
|
})();
|
|
21206
21711
|
_classThis.metadata = commandMeta({
|
|
21207
21712
|
description: 'Animate CSS properties using CSS transitions',
|
|
21208
|
-
syntax: 'transition [<
|
|
21713
|
+
syntax: 'transition <property> [from <value>] to <value> [<property> \u2026 to <value>]\u2026 [over <duration>] [using <css> | with <timing>]',
|
|
21209
21714
|
examples: [
|
|
21210
21715
|
'transition opacity to 0.5',
|
|
21211
21716
|
'transition my *opacity to 0 over 200ms',
|
|
21212
21717
|
"transition #box's *opacity to 0 over 200ms",
|
|
21213
21718
|
'transition left to 100px over 500ms',
|
|
21214
21719
|
'transition background-color to red over 1s with ease-in-out',
|
|
21720
|
+
'transition *width to 100px *height to 50px over 300ms',
|
|
21721
|
+
'transition *opacity of #panel from 0 to 1 over 200ms',
|
|
21722
|
+
'transition my *opacity to 0 using "opacity 1s ease-in"',
|
|
21215
21723
|
],
|
|
21216
21724
|
sideEffects: ['style-change', 'timing'],
|
|
21217
21725
|
category: 'animation',
|
|
@@ -22337,16 +22845,12 @@ class RenderCommand {
|
|
|
22337
22845
|
}
|
|
22338
22846
|
RenderCommand.metadata = commandMeta({
|
|
22339
22847
|
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
|
-
],
|
|
22848
|
+
syntax: ['render <template>', 'render <template> with <name>: <value>, ...'],
|
|
22345
22849
|
examples: [
|
|
22346
22850
|
'render myTemplate',
|
|
22347
|
-
'render myTemplate with
|
|
22348
|
-
'render "<template>Hello ${name}!</template>" with
|
|
22349
|
-
'render template with
|
|
22851
|
+
'render myTemplate with name: "Alice"',
|
|
22852
|
+
'render "<template>Hello ${name}!</template>" with name: "World"',
|
|
22853
|
+
'render template with items: data',
|
|
22350
22854
|
],
|
|
22351
22855
|
category: 'templates',
|
|
22352
22856
|
compatibility: 'standard',
|