@hyperfixi/core 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/hyperscript-api.d.ts +6 -0
- package/dist/ast-utils/index.js +8 -8
- package/dist/ast-utils/index.mjs +8 -8
- package/dist/bundle-generator/index.js +12 -4
- package/dist/bundle-generator/index.mjs +12 -4
- package/dist/chunks/{bridge-fFLEvCQs.js → bridge-lZbOVRDD.js} +2 -2
- package/dist/chunks/browser-modular-DegkWQ8d.js +2 -0
- package/dist/chunks/{index-BRgVy8nY.js → index-i_j9Z-1e.js} +2 -2
- package/dist/commands/data/set.d.ts +1 -0
- package/dist/commands/index.js +156 -47
- package/dist/commands/index.mjs +156 -47
- package/dist/core/context.d.ts +4 -0
- package/dist/dom/attribute-processor.d.ts +1 -0
- package/dist/hyperfixi-browser-classic-i18n.js +1 -1
- package/dist/hyperfixi-browser-minimal.js +1 -1
- package/dist/hyperfixi-browser-standard.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-lite-plus.js +1 -1
- package/dist/hyperfixi-lite.js +1 -1
- package/dist/hyperfixi-minimal.js +1 -1
- package/dist/hyperfixi-multilingual.js +1 -1
- package/dist/hyperfixi-standard.js +1 -1
- package/dist/hyperfixi.js +1 -1
- package/dist/hyperfixi.mjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +694 -459
- package/dist/index.min.js +1 -1
- package/dist/index.mjs +691 -460
- package/dist/lokascript-browser-classic-i18n.js +1 -1
- package/dist/lokascript-browser-minimal.js +1 -1
- package/dist/lokascript-browser-standard.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-lite-plus.js +1 -1
- package/dist/lokascript-lite.js +1 -1
- package/dist/lokascript-multilingual.js +1 -1
- package/dist/parser/full-parser.js +70 -35
- package/dist/parser/full-parser.mjs +70 -35
- package/dist/parser/parser-types.d.ts +1 -1
- package/dist/parser/parser.d.ts +2 -0
- package/dist/parser/regex-parser.js +23 -14
- package/dist/parser/regex-parser.mjs +23 -14
- package/dist/registry/index.js +178 -45
- package/dist/registry/index.mjs +178 -45
- package/dist/types/core-context.d.ts +1 -0
- package/package.json +6 -6
- package/dist/chunks/browser-modular-BK3IOo93.js +0 -2
- package/dist/compatibility/browser-bundle.d.ts +0 -164
|
@@ -4007,7 +4007,7 @@ function parseColonVariable(ctx) {
|
|
|
4007
4007
|
return {
|
|
4008
4008
|
type: 'identifier',
|
|
4009
4009
|
name: varToken.value,
|
|
4010
|
-
scope: '
|
|
4010
|
+
scope: 'element',
|
|
4011
4011
|
start: varToken.start - 1,
|
|
4012
4012
|
end: varToken.end,
|
|
4013
4013
|
};
|
|
@@ -4059,7 +4059,7 @@ function parseTargetFallback(ctx) {
|
|
|
4059
4059
|
expression: {
|
|
4060
4060
|
type: 'identifier',
|
|
4061
4061
|
name: varToken.value,
|
|
4062
|
-
scope: '
|
|
4062
|
+
scope: 'element',
|
|
4063
4063
|
start: varToken.start,
|
|
4064
4064
|
end: varToken.end,
|
|
4065
4065
|
},
|
|
@@ -4140,6 +4140,11 @@ function parseSetCommand(ctx, identifierNode) {
|
|
|
4140
4140
|
}
|
|
4141
4141
|
ctx.advance();
|
|
4142
4142
|
const value = ctx.parseExpression() ?? ctx.parsePrimary();
|
|
4143
|
+
let scopeTarget;
|
|
4144
|
+
if (ctx.check(KEYWORDS.ON) && tokenLooksLikeElementTarget(ctx.peekAt(1))) {
|
|
4145
|
+
ctx.advance();
|
|
4146
|
+
scopeTarget = parseOneArgument(ctx);
|
|
4147
|
+
}
|
|
4143
4148
|
const finalArgs = [];
|
|
4144
4149
|
if (targetExpression) {
|
|
4145
4150
|
finalArgs.push(targetExpression);
|
|
@@ -4151,11 +4156,22 @@ function parseSetCommand(ctx, identifierNode) {
|
|
|
4151
4156
|
if (value) {
|
|
4152
4157
|
finalArgs.push(value);
|
|
4153
4158
|
}
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
.
|
|
4157
|
-
|
|
4159
|
+
const builder = CommandNodeBuilder.fromIdentifier(identifierNode).withArgs(...finalArgs);
|
|
4160
|
+
if (scopeTarget) {
|
|
4161
|
+
builder.withModifier('on', scopeTarget);
|
|
4162
|
+
}
|
|
4163
|
+
return builder.endingAt(ctx.getPosition()).build();
|
|
4158
4164
|
}
|
|
4165
|
+
function tokenLooksLikeElementTarget(token) {
|
|
4166
|
+
if (!token)
|
|
4167
|
+
return false;
|
|
4168
|
+
if (token.kind === 'selector')
|
|
4169
|
+
return true;
|
|
4170
|
+
if (token.value.startsWith('<'))
|
|
4171
|
+
return true;
|
|
4172
|
+
return ELEMENT_PRONOUNS.has(token.value);
|
|
4173
|
+
}
|
|
4174
|
+
const ELEMENT_PRONOUNS = new Set(['me', 'my', 'it', 'its', 'you', 'your', 'yourself']);
|
|
4159
4175
|
function parseIncrementDecrementCommand(ctx, commandToken) {
|
|
4160
4176
|
const commandName = commandToken.value;
|
|
4161
4177
|
const isIncrement = commandName === 'increment';
|
|
@@ -4201,6 +4217,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
|
|
|
4201
4217
|
column: commandToken.column,
|
|
4202
4218
|
};
|
|
4203
4219
|
const binaryExpr = createBinaryExpression(operator, target, amount, pos);
|
|
4220
|
+
binaryExpr.coerceNumeric = true;
|
|
4204
4221
|
const toIdentifier = createIdentifier(KEYWORDS.TO, pos);
|
|
4205
4222
|
const args = [targetWithScope, toIdentifier, binaryExpr];
|
|
4206
4223
|
return CommandNodeBuilder.from(commandToken)
|
|
@@ -4819,6 +4836,18 @@ class Parser {
|
|
|
4819
4836
|
this.advance();
|
|
4820
4837
|
continue;
|
|
4821
4838
|
}
|
|
4839
|
+
if (this.check('then')) {
|
|
4840
|
+
const next = this.peekAt(1);
|
|
4841
|
+
const startsFeature = next !== null &&
|
|
4842
|
+
(next.value === 'init' ||
|
|
4843
|
+
next.value === 'on' ||
|
|
4844
|
+
next.value === 'def' ||
|
|
4845
|
+
getRegisteredFeature(next.value) !== undefined);
|
|
4846
|
+
if (startsFeature) {
|
|
4847
|
+
this.advance();
|
|
4848
|
+
continue;
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4822
4851
|
if (this.check('init')) {
|
|
4823
4852
|
this.advance();
|
|
4824
4853
|
const initBlock = this.parseTopLevelInitBlock();
|
|
@@ -5619,7 +5648,7 @@ class Parser {
|
|
|
5619
5648
|
return {
|
|
5620
5649
|
type: 'identifier',
|
|
5621
5650
|
name: varToken.value,
|
|
5622
|
-
scope: '
|
|
5651
|
+
scope: 'element',
|
|
5623
5652
|
start: varToken.start - 1,
|
|
5624
5653
|
end: varToken.end,
|
|
5625
5654
|
line: varToken.line,
|
|
@@ -6246,6 +6275,33 @@ class Parser {
|
|
|
6246
6275
|
return null;
|
|
6247
6276
|
}
|
|
6248
6277
|
}
|
|
6278
|
+
parseTemporalKeywordModifiers(modifiers) {
|
|
6279
|
+
if (!this.check('debounced') && !this.check('throttled')) {
|
|
6280
|
+
return;
|
|
6281
|
+
}
|
|
6282
|
+
const modToken = this.advance();
|
|
6283
|
+
const modName = modToken.value.toLowerCase();
|
|
6284
|
+
const modifierKey = modName === 'debounced' ? 'debounce' : 'throttle';
|
|
6285
|
+
if (this.match('at')) {
|
|
6286
|
+
if (this.checkTimeExpression()) {
|
|
6287
|
+
const timeToken = this.advance();
|
|
6288
|
+
const delayMs = parseTimeToMs(timeToken.value);
|
|
6289
|
+
modifiers[modifierKey] = delayMs;
|
|
6290
|
+
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${timeToken.value}' (${delayMs}ms)`);
|
|
6291
|
+
}
|
|
6292
|
+
else if (this.matchNumber()) {
|
|
6293
|
+
const delayMs = parseInt(this.previous().value, 10);
|
|
6294
|
+
modifiers[modifierKey] = delayMs;
|
|
6295
|
+
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${delayMs}'`);
|
|
6296
|
+
}
|
|
6297
|
+
else {
|
|
6298
|
+
this.addError(`Expected time expression after '${modName} at', got: ${this.peek().value}`);
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6301
|
+
else {
|
|
6302
|
+
this.addError(`Expected 'at' after '${modName}'`);
|
|
6303
|
+
}
|
|
6304
|
+
}
|
|
6249
6305
|
parseEventHandler() {
|
|
6250
6306
|
debug.parse(`🔧 parseEventHandler: ENTRY - parsing event handler`);
|
|
6251
6307
|
const eventNames = [];
|
|
@@ -6333,30 +6389,7 @@ class Parser {
|
|
|
6333
6389
|
debug.parse(`🔧 parseEventHandler: Warning - unknown modifier '.${modName}'`);
|
|
6334
6390
|
}
|
|
6335
6391
|
}
|
|
6336
|
-
|
|
6337
|
-
const modToken = this.advance();
|
|
6338
|
-
const modName = modToken.value.toLowerCase();
|
|
6339
|
-
const modifierKey = modName === 'debounced' ? 'debounce' : 'throttle';
|
|
6340
|
-
if (this.match('at')) {
|
|
6341
|
-
if (this.checkTimeExpression()) {
|
|
6342
|
-
const timeToken = this.advance();
|
|
6343
|
-
const delayMs = parseTimeToMs(timeToken.value);
|
|
6344
|
-
modifiers[modifierKey] = delayMs;
|
|
6345
|
-
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${timeToken.value}' (${delayMs}ms)`);
|
|
6346
|
-
}
|
|
6347
|
-
else if (this.matchNumber()) {
|
|
6348
|
-
const delayMs = parseInt(this.previous().value, 10);
|
|
6349
|
-
modifiers[modifierKey] = delayMs;
|
|
6350
|
-
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${delayMs}'`);
|
|
6351
|
-
}
|
|
6352
|
-
else {
|
|
6353
|
-
this.addError(`Expected time expression after '${modName} at', got: ${this.peek().value}`);
|
|
6354
|
-
}
|
|
6355
|
-
}
|
|
6356
|
-
else {
|
|
6357
|
-
this.addError(`Expected 'at' after '${modName}'`);
|
|
6358
|
-
}
|
|
6359
|
-
}
|
|
6392
|
+
this.parseTemporalKeywordModifiers(modifiers);
|
|
6360
6393
|
if (firstOnceAlias) {
|
|
6361
6394
|
modifiers.once = true;
|
|
6362
6395
|
}
|
|
@@ -6373,6 +6406,7 @@ class Parser {
|
|
|
6373
6406
|
const targetToken = this.advance();
|
|
6374
6407
|
target = targetToken.value;
|
|
6375
6408
|
debug.parse(`🔧 parseEventHandler: Parsed 'from' target: ${target} (kind: ${targetToken.kind})`);
|
|
6409
|
+
this.parseTemporalKeywordModifiers(modifiers);
|
|
6376
6410
|
}
|
|
6377
6411
|
let attributeName;
|
|
6378
6412
|
if (this.match('of')) {
|
|
@@ -7343,6 +7377,10 @@ class Parser {
|
|
|
7343
7377
|
}
|
|
7344
7378
|
return this.tokens[this.current];
|
|
7345
7379
|
}
|
|
7380
|
+
peekAt(offset) {
|
|
7381
|
+
const index = this.current + offset;
|
|
7382
|
+
return index >= 0 && index < this.tokens.length ? this.tokens[index] : null;
|
|
7383
|
+
}
|
|
7346
7384
|
previous() {
|
|
7347
7385
|
return this.tokens[this.current - 1];
|
|
7348
7386
|
}
|
|
@@ -7547,10 +7585,7 @@ class Parser {
|
|
|
7547
7585
|
restorePosition: (pos) => {
|
|
7548
7586
|
parser.current = pos;
|
|
7549
7587
|
},
|
|
7550
|
-
peekAt: (offset) =>
|
|
7551
|
-
const index = parser.current + offset;
|
|
7552
|
-
return index >= 0 && index < parser.tokens.length ? parser.tokens[index] : null;
|
|
7553
|
-
},
|
|
7588
|
+
peekAt: (offset) => parser.peekAt(offset),
|
|
7554
7589
|
getInputSlice: (start, end) => {
|
|
7555
7590
|
if (!this.originalInput)
|
|
7556
7591
|
return '';
|
|
@@ -4005,7 +4005,7 @@ function parseColonVariable(ctx) {
|
|
|
4005
4005
|
return {
|
|
4006
4006
|
type: 'identifier',
|
|
4007
4007
|
name: varToken.value,
|
|
4008
|
-
scope: '
|
|
4008
|
+
scope: 'element',
|
|
4009
4009
|
start: varToken.start - 1,
|
|
4010
4010
|
end: varToken.end,
|
|
4011
4011
|
};
|
|
@@ -4057,7 +4057,7 @@ function parseTargetFallback(ctx) {
|
|
|
4057
4057
|
expression: {
|
|
4058
4058
|
type: 'identifier',
|
|
4059
4059
|
name: varToken.value,
|
|
4060
|
-
scope: '
|
|
4060
|
+
scope: 'element',
|
|
4061
4061
|
start: varToken.start,
|
|
4062
4062
|
end: varToken.end,
|
|
4063
4063
|
},
|
|
@@ -4138,6 +4138,11 @@ function parseSetCommand(ctx, identifierNode) {
|
|
|
4138
4138
|
}
|
|
4139
4139
|
ctx.advance();
|
|
4140
4140
|
const value = ctx.parseExpression() ?? ctx.parsePrimary();
|
|
4141
|
+
let scopeTarget;
|
|
4142
|
+
if (ctx.check(KEYWORDS.ON) && tokenLooksLikeElementTarget(ctx.peekAt(1))) {
|
|
4143
|
+
ctx.advance();
|
|
4144
|
+
scopeTarget = parseOneArgument(ctx);
|
|
4145
|
+
}
|
|
4141
4146
|
const finalArgs = [];
|
|
4142
4147
|
if (targetExpression) {
|
|
4143
4148
|
finalArgs.push(targetExpression);
|
|
@@ -4149,11 +4154,22 @@ function parseSetCommand(ctx, identifierNode) {
|
|
|
4149
4154
|
if (value) {
|
|
4150
4155
|
finalArgs.push(value);
|
|
4151
4156
|
}
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
.
|
|
4155
|
-
|
|
4157
|
+
const builder = CommandNodeBuilder.fromIdentifier(identifierNode).withArgs(...finalArgs);
|
|
4158
|
+
if (scopeTarget) {
|
|
4159
|
+
builder.withModifier('on', scopeTarget);
|
|
4160
|
+
}
|
|
4161
|
+
return builder.endingAt(ctx.getPosition()).build();
|
|
4156
4162
|
}
|
|
4163
|
+
function tokenLooksLikeElementTarget(token) {
|
|
4164
|
+
if (!token)
|
|
4165
|
+
return false;
|
|
4166
|
+
if (token.kind === 'selector')
|
|
4167
|
+
return true;
|
|
4168
|
+
if (token.value.startsWith('<'))
|
|
4169
|
+
return true;
|
|
4170
|
+
return ELEMENT_PRONOUNS.has(token.value);
|
|
4171
|
+
}
|
|
4172
|
+
const ELEMENT_PRONOUNS = new Set(['me', 'my', 'it', 'its', 'you', 'your', 'yourself']);
|
|
4157
4173
|
function parseIncrementDecrementCommand(ctx, commandToken) {
|
|
4158
4174
|
const commandName = commandToken.value;
|
|
4159
4175
|
const isIncrement = commandName === 'increment';
|
|
@@ -4199,6 +4215,7 @@ function parseIncrementDecrementCommand(ctx, commandToken) {
|
|
|
4199
4215
|
column: commandToken.column,
|
|
4200
4216
|
};
|
|
4201
4217
|
const binaryExpr = createBinaryExpression(operator, target, amount, pos);
|
|
4218
|
+
binaryExpr.coerceNumeric = true;
|
|
4202
4219
|
const toIdentifier = createIdentifier(KEYWORDS.TO, pos);
|
|
4203
4220
|
const args = [targetWithScope, toIdentifier, binaryExpr];
|
|
4204
4221
|
return CommandNodeBuilder.from(commandToken)
|
|
@@ -4817,6 +4834,18 @@ class Parser {
|
|
|
4817
4834
|
this.advance();
|
|
4818
4835
|
continue;
|
|
4819
4836
|
}
|
|
4837
|
+
if (this.check('then')) {
|
|
4838
|
+
const next = this.peekAt(1);
|
|
4839
|
+
const startsFeature = next !== null &&
|
|
4840
|
+
(next.value === 'init' ||
|
|
4841
|
+
next.value === 'on' ||
|
|
4842
|
+
next.value === 'def' ||
|
|
4843
|
+
getRegisteredFeature(next.value) !== undefined);
|
|
4844
|
+
if (startsFeature) {
|
|
4845
|
+
this.advance();
|
|
4846
|
+
continue;
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4820
4849
|
if (this.check('init')) {
|
|
4821
4850
|
this.advance();
|
|
4822
4851
|
const initBlock = this.parseTopLevelInitBlock();
|
|
@@ -5617,7 +5646,7 @@ class Parser {
|
|
|
5617
5646
|
return {
|
|
5618
5647
|
type: 'identifier',
|
|
5619
5648
|
name: varToken.value,
|
|
5620
|
-
scope: '
|
|
5649
|
+
scope: 'element',
|
|
5621
5650
|
start: varToken.start - 1,
|
|
5622
5651
|
end: varToken.end,
|
|
5623
5652
|
line: varToken.line,
|
|
@@ -6244,6 +6273,33 @@ class Parser {
|
|
|
6244
6273
|
return null;
|
|
6245
6274
|
}
|
|
6246
6275
|
}
|
|
6276
|
+
parseTemporalKeywordModifiers(modifiers) {
|
|
6277
|
+
if (!this.check('debounced') && !this.check('throttled')) {
|
|
6278
|
+
return;
|
|
6279
|
+
}
|
|
6280
|
+
const modToken = this.advance();
|
|
6281
|
+
const modName = modToken.value.toLowerCase();
|
|
6282
|
+
const modifierKey = modName === 'debounced' ? 'debounce' : 'throttle';
|
|
6283
|
+
if (this.match('at')) {
|
|
6284
|
+
if (this.checkTimeExpression()) {
|
|
6285
|
+
const timeToken = this.advance();
|
|
6286
|
+
const delayMs = parseTimeToMs(timeToken.value);
|
|
6287
|
+
modifiers[modifierKey] = delayMs;
|
|
6288
|
+
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${timeToken.value}' (${delayMs}ms)`);
|
|
6289
|
+
}
|
|
6290
|
+
else if (this.matchNumber()) {
|
|
6291
|
+
const delayMs = parseInt(this.previous().value, 10);
|
|
6292
|
+
modifiers[modifierKey] = delayMs;
|
|
6293
|
+
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${delayMs}'`);
|
|
6294
|
+
}
|
|
6295
|
+
else {
|
|
6296
|
+
this.addError(`Expected time expression after '${modName} at', got: ${this.peek().value}`);
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6299
|
+
else {
|
|
6300
|
+
this.addError(`Expected 'at' after '${modName}'`);
|
|
6301
|
+
}
|
|
6302
|
+
}
|
|
6247
6303
|
parseEventHandler() {
|
|
6248
6304
|
debug.parse(`🔧 parseEventHandler: ENTRY - parsing event handler`);
|
|
6249
6305
|
const eventNames = [];
|
|
@@ -6331,30 +6387,7 @@ class Parser {
|
|
|
6331
6387
|
debug.parse(`🔧 parseEventHandler: Warning - unknown modifier '.${modName}'`);
|
|
6332
6388
|
}
|
|
6333
6389
|
}
|
|
6334
|
-
|
|
6335
|
-
const modToken = this.advance();
|
|
6336
|
-
const modName = modToken.value.toLowerCase();
|
|
6337
|
-
const modifierKey = modName === 'debounced' ? 'debounce' : 'throttle';
|
|
6338
|
-
if (this.match('at')) {
|
|
6339
|
-
if (this.checkTimeExpression()) {
|
|
6340
|
-
const timeToken = this.advance();
|
|
6341
|
-
const delayMs = parseTimeToMs(timeToken.value);
|
|
6342
|
-
modifiers[modifierKey] = delayMs;
|
|
6343
|
-
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${timeToken.value}' (${delayMs}ms)`);
|
|
6344
|
-
}
|
|
6345
|
-
else if (this.matchNumber()) {
|
|
6346
|
-
const delayMs = parseInt(this.previous().value, 10);
|
|
6347
|
-
modifiers[modifierKey] = delayMs;
|
|
6348
|
-
debug.parse(`🔧 parseEventHandler: Parsed '${modName} at ${delayMs}'`);
|
|
6349
|
-
}
|
|
6350
|
-
else {
|
|
6351
|
-
this.addError(`Expected time expression after '${modName} at', got: ${this.peek().value}`);
|
|
6352
|
-
}
|
|
6353
|
-
}
|
|
6354
|
-
else {
|
|
6355
|
-
this.addError(`Expected 'at' after '${modName}'`);
|
|
6356
|
-
}
|
|
6357
|
-
}
|
|
6390
|
+
this.parseTemporalKeywordModifiers(modifiers);
|
|
6358
6391
|
if (firstOnceAlias) {
|
|
6359
6392
|
modifiers.once = true;
|
|
6360
6393
|
}
|
|
@@ -6371,6 +6404,7 @@ class Parser {
|
|
|
6371
6404
|
const targetToken = this.advance();
|
|
6372
6405
|
target = targetToken.value;
|
|
6373
6406
|
debug.parse(`🔧 parseEventHandler: Parsed 'from' target: ${target} (kind: ${targetToken.kind})`);
|
|
6407
|
+
this.parseTemporalKeywordModifiers(modifiers);
|
|
6374
6408
|
}
|
|
6375
6409
|
let attributeName;
|
|
6376
6410
|
if (this.match('of')) {
|
|
@@ -7341,6 +7375,10 @@ class Parser {
|
|
|
7341
7375
|
}
|
|
7342
7376
|
return this.tokens[this.current];
|
|
7343
7377
|
}
|
|
7378
|
+
peekAt(offset) {
|
|
7379
|
+
const index = this.current + offset;
|
|
7380
|
+
return index >= 0 && index < this.tokens.length ? this.tokens[index] : null;
|
|
7381
|
+
}
|
|
7344
7382
|
previous() {
|
|
7345
7383
|
return this.tokens[this.current - 1];
|
|
7346
7384
|
}
|
|
@@ -7545,10 +7583,7 @@ class Parser {
|
|
|
7545
7583
|
restorePosition: (pos) => {
|
|
7546
7584
|
parser.current = pos;
|
|
7547
7585
|
},
|
|
7548
|
-
peekAt: (offset) =>
|
|
7549
|
-
const index = parser.current + offset;
|
|
7550
|
-
return index >= 0 && index < parser.tokens.length ? parser.tokens[index] : null;
|
|
7551
|
-
},
|
|
7586
|
+
peekAt: (offset) => parser.peekAt(offset),
|
|
7552
7587
|
getInputSlice: (start, end) => {
|
|
7553
7588
|
if (!this.originalInput)
|
|
7554
7589
|
return '';
|
|
@@ -8,7 +8,7 @@ export interface Position {
|
|
|
8
8
|
export interface IdentifierNode extends ASTNode {
|
|
9
9
|
type: 'identifier';
|
|
10
10
|
name: string;
|
|
11
|
-
scope?: 'local' | 'global';
|
|
11
|
+
scope?: 'local' | 'element' | 'global';
|
|
12
12
|
}
|
|
13
13
|
export interface LiteralNode extends ASTNode {
|
|
14
14
|
type: 'literal';
|
package/dist/parser/parser.d.ts
CHANGED
|
@@ -67,6 +67,7 @@ export declare class Parser {
|
|
|
67
67
|
private createPseudoCommandNode;
|
|
68
68
|
private tryParsePseudoCommand;
|
|
69
69
|
private parseCommandWithErrorRecovery;
|
|
70
|
+
private parseTemporalKeywordModifiers;
|
|
70
71
|
private parseEventHandler;
|
|
71
72
|
private parseBehaviorDefinition;
|
|
72
73
|
private parseCommandSequence;
|
|
@@ -143,6 +144,7 @@ export declare class Parser {
|
|
|
143
144
|
private advance;
|
|
144
145
|
private isAtEnd;
|
|
145
146
|
private peek;
|
|
147
|
+
private peekAt;
|
|
146
148
|
private previous;
|
|
147
149
|
private consume;
|
|
148
150
|
private addError;
|
|
@@ -95,6 +95,15 @@ function parseCommand(code) {
|
|
|
95
95
|
}
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
|
+
const elementVars = new WeakMap();
|
|
99
|
+
function elemScope(el) {
|
|
100
|
+
let m = elementVars.get(el);
|
|
101
|
+
if (!m) {
|
|
102
|
+
m = new Map();
|
|
103
|
+
elementVars.set(el, m);
|
|
104
|
+
}
|
|
105
|
+
return m;
|
|
106
|
+
}
|
|
98
107
|
function resolveTarget(target, me) {
|
|
99
108
|
if (!target)
|
|
100
109
|
return me;
|
|
@@ -148,7 +157,7 @@ async function executeCommand(cmd, me, locals) {
|
|
|
148
157
|
return null;
|
|
149
158
|
}
|
|
150
159
|
case 'put': {
|
|
151
|
-
const content = evaluateValue(cmd.args[0], me
|
|
160
|
+
const content = evaluateValue(cmd.args[0], me);
|
|
152
161
|
for (const el of elements) {
|
|
153
162
|
switch (cmd.modifier?.toLowerCase()) {
|
|
154
163
|
case 'into':
|
|
@@ -168,9 +177,9 @@ async function executeCommand(cmd, me, locals) {
|
|
|
168
177
|
}
|
|
169
178
|
case 'set': {
|
|
170
179
|
const [targetExpr, valueExpr] = cmd.args;
|
|
171
|
-
const value = evaluateValue(valueExpr, me
|
|
180
|
+
const value = evaluateValue(valueExpr, me);
|
|
172
181
|
if (targetExpr.startsWith(':')) {
|
|
173
|
-
|
|
182
|
+
elemScope(me).set(targetExpr.slice(1), value);
|
|
174
183
|
return value;
|
|
175
184
|
}
|
|
176
185
|
const propMatch = targetExpr.match(/^(.+?)(?:'s|\.)\s*(\w+)$/);
|
|
@@ -184,7 +193,7 @@ async function executeCommand(cmd, me, locals) {
|
|
|
184
193
|
return value;
|
|
185
194
|
}
|
|
186
195
|
case 'log': {
|
|
187
|
-
const value = evaluateValue(cmd.args.join(' '), me
|
|
196
|
+
const value = evaluateValue(cmd.args.join(' '), me);
|
|
188
197
|
console.log(value);
|
|
189
198
|
return value;
|
|
190
199
|
}
|
|
@@ -223,7 +232,7 @@ function evaluateValue(expr, me, locals) {
|
|
|
223
232
|
if (e === 'null')
|
|
224
233
|
return null;
|
|
225
234
|
if (e.startsWith(':')) {
|
|
226
|
-
return
|
|
235
|
+
return elemScope(me).get(e.slice(1));
|
|
227
236
|
}
|
|
228
237
|
if (e === 'me')
|
|
229
238
|
return me;
|
|
@@ -242,13 +251,13 @@ async function executeParsed(parsed, me, locals = new Map()) {
|
|
|
242
251
|
let result;
|
|
243
252
|
for (const cmd of parsed) {
|
|
244
253
|
if (cmd.modifier === 'if' || cmd.modifier === 'unless') {
|
|
245
|
-
const condition = evaluateCondition(cmd.args[0], me
|
|
254
|
+
const condition = evaluateCondition(cmd.args[0], me);
|
|
246
255
|
const shouldRun = cmd.modifier === 'if' ? condition : !condition;
|
|
247
256
|
if (!shouldRun)
|
|
248
257
|
continue;
|
|
249
258
|
cmd.args.shift();
|
|
250
259
|
}
|
|
251
|
-
result = await executeCommand(cmd, me
|
|
260
|
+
result = await executeCommand(cmd, me);
|
|
252
261
|
}
|
|
253
262
|
return result;
|
|
254
263
|
}
|
|
@@ -258,17 +267,17 @@ async function executeParsed(parsed, me, locals = new Map()) {
|
|
|
258
267
|
if (eventName.startsWith('interval:')) {
|
|
259
268
|
const ms = parseInt(eventName.split(':')[1]);
|
|
260
269
|
setInterval(async () => {
|
|
261
|
-
|
|
270
|
+
new Map(locals);
|
|
262
271
|
for (const cmd of handler.commands) {
|
|
263
|
-
await executeCommand(cmd, me
|
|
272
|
+
await executeCommand(cmd, me);
|
|
264
273
|
}
|
|
265
274
|
}, ms);
|
|
266
275
|
return me;
|
|
267
276
|
}
|
|
268
277
|
if (eventName === 'init') {
|
|
269
|
-
|
|
278
|
+
new Map(locals);
|
|
270
279
|
for (const cmd of handler.commands) {
|
|
271
|
-
await executeCommand(cmd, me
|
|
280
|
+
await executeCommand(cmd, me);
|
|
272
281
|
}
|
|
273
282
|
return me;
|
|
274
283
|
}
|
|
@@ -277,7 +286,7 @@ async function executeParsed(parsed, me, locals = new Map()) {
|
|
|
277
286
|
const handlerLocals = new Map(locals);
|
|
278
287
|
handlerLocals.set('event', event);
|
|
279
288
|
for (const cmd of handler.commands) {
|
|
280
|
-
await executeCommand(cmd, me
|
|
289
|
+
await executeCommand(cmd, me);
|
|
281
290
|
}
|
|
282
291
|
});
|
|
283
292
|
}
|
|
@@ -294,9 +303,9 @@ function evaluateCondition(expr, me, locals) {
|
|
|
294
303
|
return Boolean(me[propMatch[2]]);
|
|
295
304
|
}
|
|
296
305
|
if (e.startsWith(':')) {
|
|
297
|
-
return Boolean(
|
|
306
|
+
return Boolean(elemScope(me).get(e.slice(1)));
|
|
298
307
|
}
|
|
299
|
-
const value = evaluateValue(e, me
|
|
308
|
+
const value = evaluateValue(e, me);
|
|
300
309
|
return Boolean(value);
|
|
301
310
|
}
|
|
302
311
|
function processElements(root = document) {
|
|
@@ -93,6 +93,15 @@ function parseCommand(code) {
|
|
|
93
93
|
}
|
|
94
94
|
return null;
|
|
95
95
|
}
|
|
96
|
+
const elementVars = new WeakMap();
|
|
97
|
+
function elemScope(el) {
|
|
98
|
+
let m = elementVars.get(el);
|
|
99
|
+
if (!m) {
|
|
100
|
+
m = new Map();
|
|
101
|
+
elementVars.set(el, m);
|
|
102
|
+
}
|
|
103
|
+
return m;
|
|
104
|
+
}
|
|
96
105
|
function resolveTarget(target, me) {
|
|
97
106
|
if (!target)
|
|
98
107
|
return me;
|
|
@@ -146,7 +155,7 @@ async function executeCommand(cmd, me, locals) {
|
|
|
146
155
|
return null;
|
|
147
156
|
}
|
|
148
157
|
case 'put': {
|
|
149
|
-
const content = evaluateValue(cmd.args[0], me
|
|
158
|
+
const content = evaluateValue(cmd.args[0], me);
|
|
150
159
|
for (const el of elements) {
|
|
151
160
|
switch (cmd.modifier?.toLowerCase()) {
|
|
152
161
|
case 'into':
|
|
@@ -166,9 +175,9 @@ async function executeCommand(cmd, me, locals) {
|
|
|
166
175
|
}
|
|
167
176
|
case 'set': {
|
|
168
177
|
const [targetExpr, valueExpr] = cmd.args;
|
|
169
|
-
const value = evaluateValue(valueExpr, me
|
|
178
|
+
const value = evaluateValue(valueExpr, me);
|
|
170
179
|
if (targetExpr.startsWith(':')) {
|
|
171
|
-
|
|
180
|
+
elemScope(me).set(targetExpr.slice(1), value);
|
|
172
181
|
return value;
|
|
173
182
|
}
|
|
174
183
|
const propMatch = targetExpr.match(/^(.+?)(?:'s|\.)\s*(\w+)$/);
|
|
@@ -182,7 +191,7 @@ async function executeCommand(cmd, me, locals) {
|
|
|
182
191
|
return value;
|
|
183
192
|
}
|
|
184
193
|
case 'log': {
|
|
185
|
-
const value = evaluateValue(cmd.args.join(' '), me
|
|
194
|
+
const value = evaluateValue(cmd.args.join(' '), me);
|
|
186
195
|
console.log(value);
|
|
187
196
|
return value;
|
|
188
197
|
}
|
|
@@ -221,7 +230,7 @@ function evaluateValue(expr, me, locals) {
|
|
|
221
230
|
if (e === 'null')
|
|
222
231
|
return null;
|
|
223
232
|
if (e.startsWith(':')) {
|
|
224
|
-
return
|
|
233
|
+
return elemScope(me).get(e.slice(1));
|
|
225
234
|
}
|
|
226
235
|
if (e === 'me')
|
|
227
236
|
return me;
|
|
@@ -240,13 +249,13 @@ async function executeParsed(parsed, me, locals = new Map()) {
|
|
|
240
249
|
let result;
|
|
241
250
|
for (const cmd of parsed) {
|
|
242
251
|
if (cmd.modifier === 'if' || cmd.modifier === 'unless') {
|
|
243
|
-
const condition = evaluateCondition(cmd.args[0], me
|
|
252
|
+
const condition = evaluateCondition(cmd.args[0], me);
|
|
244
253
|
const shouldRun = cmd.modifier === 'if' ? condition : !condition;
|
|
245
254
|
if (!shouldRun)
|
|
246
255
|
continue;
|
|
247
256
|
cmd.args.shift();
|
|
248
257
|
}
|
|
249
|
-
result = await executeCommand(cmd, me
|
|
258
|
+
result = await executeCommand(cmd, me);
|
|
250
259
|
}
|
|
251
260
|
return result;
|
|
252
261
|
}
|
|
@@ -256,17 +265,17 @@ async function executeParsed(parsed, me, locals = new Map()) {
|
|
|
256
265
|
if (eventName.startsWith('interval:')) {
|
|
257
266
|
const ms = parseInt(eventName.split(':')[1]);
|
|
258
267
|
setInterval(async () => {
|
|
259
|
-
|
|
268
|
+
new Map(locals);
|
|
260
269
|
for (const cmd of handler.commands) {
|
|
261
|
-
await executeCommand(cmd, me
|
|
270
|
+
await executeCommand(cmd, me);
|
|
262
271
|
}
|
|
263
272
|
}, ms);
|
|
264
273
|
return me;
|
|
265
274
|
}
|
|
266
275
|
if (eventName === 'init') {
|
|
267
|
-
|
|
276
|
+
new Map(locals);
|
|
268
277
|
for (const cmd of handler.commands) {
|
|
269
|
-
await executeCommand(cmd, me
|
|
278
|
+
await executeCommand(cmd, me);
|
|
270
279
|
}
|
|
271
280
|
return me;
|
|
272
281
|
}
|
|
@@ -275,7 +284,7 @@ async function executeParsed(parsed, me, locals = new Map()) {
|
|
|
275
284
|
const handlerLocals = new Map(locals);
|
|
276
285
|
handlerLocals.set('event', event);
|
|
277
286
|
for (const cmd of handler.commands) {
|
|
278
|
-
await executeCommand(cmd, me
|
|
287
|
+
await executeCommand(cmd, me);
|
|
279
288
|
}
|
|
280
289
|
});
|
|
281
290
|
}
|
|
@@ -292,9 +301,9 @@ function evaluateCondition(expr, me, locals) {
|
|
|
292
301
|
return Boolean(me[propMatch[2]]);
|
|
293
302
|
}
|
|
294
303
|
if (e.startsWith(':')) {
|
|
295
|
-
return Boolean(
|
|
304
|
+
return Boolean(elemScope(me).get(e.slice(1)));
|
|
296
305
|
}
|
|
297
|
-
const value = evaluateValue(e, me
|
|
306
|
+
const value = evaluateValue(e, me);
|
|
298
307
|
return Boolean(value);
|
|
299
308
|
}
|
|
300
309
|
function processElements(root = document) {
|