rip-lang 3.8.9 → 3.9.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/CHANGELOG.md +31 -0
- package/README.md +5 -5
- package/docs/dist/rip-ui.min.js +171 -171
- package/docs/dist/rip-ui.min.js.br +0 -0
- package/docs/dist/rip.browser.min.js +168 -168
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/package.json +3 -3
- package/src/compiler.js +1 -2
- package/src/components.js +355 -7
- package/src/lexer.js +2 -275
- package/docs/dist/rip.browser.js +0 -8025
- package/docs/dist/ui.js +0 -962
- package/docs/dist/ui.min.js +0 -2
- package/docs/dist/ui.min.js.br +0 -0
- package/docs/dist/ui.rip +0 -957
- package/docs/dist/ui.rip.br +0 -0
- package/src/parser-rd.js +0 -3242
package/src/lexer.js
CHANGED
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
//
|
|
40
40
|
// ==========================================================================
|
|
41
41
|
|
|
42
|
-
import { TEMPLATE_TAGS } from './tags.js';
|
|
43
42
|
import { installTypeSupport } from './types.js';
|
|
44
43
|
|
|
45
44
|
// ==========================================================================
|
|
@@ -1263,7 +1262,7 @@ export class Lexer {
|
|
|
1263
1262
|
}
|
|
1264
1263
|
|
|
1265
1264
|
// ==========================================================================
|
|
1266
|
-
// Rewriter
|
|
1265
|
+
// Rewriter
|
|
1267
1266
|
// ==========================================================================
|
|
1268
1267
|
|
|
1269
1268
|
rewrite(tokens) {
|
|
@@ -1272,7 +1271,7 @@ export class Lexer {
|
|
|
1272
1271
|
this.closeOpenCalls();
|
|
1273
1272
|
this.closeOpenIndexes();
|
|
1274
1273
|
this.normalizeLines();
|
|
1275
|
-
this.rewriteRender();
|
|
1274
|
+
this.rewriteRender?.();
|
|
1276
1275
|
this.rewriteTypes();
|
|
1277
1276
|
this.tagPostfixConditionals();
|
|
1278
1277
|
this.addImplicitBracesAndParens();
|
|
@@ -1383,278 +1382,6 @@ export class Lexer {
|
|
|
1383
1382
|
});
|
|
1384
1383
|
}
|
|
1385
1384
|
|
|
1386
|
-
// =========================================================================
|
|
1387
|
-
// Render block rewriter
|
|
1388
|
-
// =========================================================================
|
|
1389
|
-
// Transforms template syntax inside render blocks:
|
|
1390
|
-
// - Implicit div for class-only selectors: .card → div.card
|
|
1391
|
-
// - Combine #id selectors: div # main → div#main
|
|
1392
|
-
// - Two-way binding: value <=> username → __bind_value__: username
|
|
1393
|
-
// - Event modifiers: @click.prevent: → [@click.prevent]:
|
|
1394
|
-
// - Dynamic classes: div.('card', x && 'active') → div.__clsx(...)
|
|
1395
|
-
// - Implicit nesting: inject -> before INDENT for template elements
|
|
1396
|
-
// - Hyphenated attributes: data-foo: "x" → "data-foo": "x"
|
|
1397
|
-
// =========================================================================
|
|
1398
|
-
rewriteRender() {
|
|
1399
|
-
let inRender = false;
|
|
1400
|
-
let renderIndentLevel = 0;
|
|
1401
|
-
let currentIndent = 0;
|
|
1402
|
-
let pendingCallEnds = [];
|
|
1403
|
-
|
|
1404
|
-
let isHtmlTag = (name) => {
|
|
1405
|
-
let tagPart = name.split('#')[0];
|
|
1406
|
-
return TEMPLATE_TAGS.has(tagPart);
|
|
1407
|
-
};
|
|
1408
|
-
|
|
1409
|
-
let isComponent = (name) => {
|
|
1410
|
-
if (!name || typeof name !== 'string') return false;
|
|
1411
|
-
return /^[A-Z]/.test(name);
|
|
1412
|
-
};
|
|
1413
|
-
|
|
1414
|
-
let isTemplateTag = (name) => {
|
|
1415
|
-
return isHtmlTag(name) || isComponent(name);
|
|
1416
|
-
};
|
|
1417
|
-
|
|
1418
|
-
let startsWithTag = (tokens, i) => {
|
|
1419
|
-
let j = i;
|
|
1420
|
-
while (j > 0) {
|
|
1421
|
-
let pt = tokens[j - 1][0];
|
|
1422
|
-
if (pt === 'INDENT' || pt === 'OUTDENT' || pt === 'TERMINATOR' || pt === 'RENDER' || pt === 'CALL_END' || pt === ')') {
|
|
1423
|
-
break;
|
|
1424
|
-
}
|
|
1425
|
-
j--;
|
|
1426
|
-
}
|
|
1427
|
-
return tokens[j] && tokens[j][0] === 'IDENTIFIER' && isTemplateTag(tokens[j][1]);
|
|
1428
|
-
};
|
|
1429
|
-
|
|
1430
|
-
this.scanTokens(function(token, i, tokens) {
|
|
1431
|
-
let tag = token[0];
|
|
1432
|
-
let nextToken = i < tokens.length - 1 ? tokens[i + 1] : null;
|
|
1433
|
-
|
|
1434
|
-
// Track entering render blocks
|
|
1435
|
-
if (tag === 'RENDER') {
|
|
1436
|
-
inRender = true;
|
|
1437
|
-
renderIndentLevel = currentIndent + 1;
|
|
1438
|
-
return 1;
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
// Track indentation
|
|
1442
|
-
if (tag === 'INDENT') {
|
|
1443
|
-
currentIndent++;
|
|
1444
|
-
return 1;
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
if (tag === 'OUTDENT') {
|
|
1448
|
-
currentIndent--;
|
|
1449
|
-
|
|
1450
|
-
// Insert pending CALL_END(s) after this OUTDENT
|
|
1451
|
-
let inserted = 0;
|
|
1452
|
-
while (pendingCallEnds.length > 0 && pendingCallEnds[pendingCallEnds.length - 1] > currentIndent) {
|
|
1453
|
-
let callEndToken = gen('CALL_END', ')', token);
|
|
1454
|
-
tokens.splice(i + 1 + inserted, 0, callEndToken);
|
|
1455
|
-
pendingCallEnds.pop();
|
|
1456
|
-
inserted++;
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
// Exit render block when we outdent past where it started
|
|
1460
|
-
if (inRender && currentIndent < renderIndentLevel) {
|
|
1461
|
-
inRender = false;
|
|
1462
|
-
}
|
|
1463
|
-
return 1 + inserted;
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
// Only process if we're inside a render block
|
|
1467
|
-
if (!inRender) return 1;
|
|
1468
|
-
|
|
1469
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1470
|
-
// Hyphenated attributes
|
|
1471
|
-
// data-lucide: "search" → "data-lucide": "search"
|
|
1472
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1473
|
-
if (tag === 'IDENTIFIER' && !token.spaced) {
|
|
1474
|
-
let parts = [token[1]];
|
|
1475
|
-
let j = i + 1;
|
|
1476
|
-
while (j + 1 < tokens.length) {
|
|
1477
|
-
let hyphen = tokens[j];
|
|
1478
|
-
let nextPart = tokens[j + 1];
|
|
1479
|
-
if (hyphen[0] === '-' && !hyphen.spaced &&
|
|
1480
|
-
(nextPart[0] === 'IDENTIFIER' || nextPart[0] === 'PROPERTY')) {
|
|
1481
|
-
parts.push(nextPart[1]);
|
|
1482
|
-
j += 2;
|
|
1483
|
-
if (nextPart[0] === 'PROPERTY') break;
|
|
1484
|
-
} else {
|
|
1485
|
-
break;
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
if (parts.length > 1 && j > i + 1 && tokens[j - 1][0] === 'PROPERTY') {
|
|
1489
|
-
token[0] = 'STRING';
|
|
1490
|
-
token[1] = `"${parts.join('-')}"`;
|
|
1491
|
-
tokens.splice(i + 1, j - i - 1);
|
|
1492
|
-
return 1;
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1497
|
-
// Implicit div for class-only selectors
|
|
1498
|
-
// .card → div.card
|
|
1499
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1500
|
-
if (tag === '.') {
|
|
1501
|
-
let prevToken = i > 0 ? tokens[i - 1] : null;
|
|
1502
|
-
let prevTag = prevToken ? prevToken[0] : null;
|
|
1503
|
-
if (prevTag === 'INDENT' || prevTag === 'TERMINATOR') {
|
|
1504
|
-
if (nextToken && nextToken[0] === 'PROPERTY') {
|
|
1505
|
-
let divToken = gen('IDENTIFIER', 'div', token);
|
|
1506
|
-
tokens.splice(i, 0, divToken);
|
|
1507
|
-
return 2;
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1513
|
-
// Combine #id selectors
|
|
1514
|
-
// div # main → div#main
|
|
1515
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1516
|
-
if (tag === 'IDENTIFIER' || tag === 'PROPERTY') {
|
|
1517
|
-
let next = tokens[i + 1];
|
|
1518
|
-
let nextNext = tokens[i + 2];
|
|
1519
|
-
if (next && next[0] === '#' && nextNext && (nextNext[0] === 'PROPERTY' || nextNext[0] === 'IDENTIFIER')) {
|
|
1520
|
-
token[1] = token[1] + '#' + nextNext[1];
|
|
1521
|
-
if (nextNext.spaced) token.spaced = true;
|
|
1522
|
-
tokens.splice(i + 1, 2);
|
|
1523
|
-
return 1;
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1528
|
-
// Two-way binding
|
|
1529
|
-
// value <=> username → __bind_value__: username
|
|
1530
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1531
|
-
if (tag === 'BIND') {
|
|
1532
|
-
let prevToken = i > 0 ? tokens[i - 1] : null;
|
|
1533
|
-
let nextBindToken = tokens[i + 1];
|
|
1534
|
-
if (prevToken && (prevToken[0] === 'IDENTIFIER' || prevToken[0] === 'PROPERTY') &&
|
|
1535
|
-
nextBindToken && nextBindToken[0] === 'IDENTIFIER') {
|
|
1536
|
-
prevToken[1] = `__bind_${prevToken[1]}__`;
|
|
1537
|
-
token[0] = ':';
|
|
1538
|
-
token[1] = ':';
|
|
1539
|
-
return 1;
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1544
|
-
// Event modifiers
|
|
1545
|
-
// @click.prevent: handler → [@click.prevent]: handler
|
|
1546
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1547
|
-
if (tag === '@') {
|
|
1548
|
-
let j = i + 1;
|
|
1549
|
-
if (j < tokens.length && tokens[j][0] === 'PROPERTY') {
|
|
1550
|
-
j++;
|
|
1551
|
-
while (j + 1 < tokens.length && tokens[j][0] === '.' && tokens[j + 1][0] === 'PROPERTY') {
|
|
1552
|
-
j += 2;
|
|
1553
|
-
}
|
|
1554
|
-
if (j > i + 2 && j < tokens.length && tokens[j][0] === ':') {
|
|
1555
|
-
let openBracket = gen('[', '[', token);
|
|
1556
|
-
tokens.splice(i, 0, openBracket);
|
|
1557
|
-
let closeBracket = gen(']', ']', tokens[j + 1]);
|
|
1558
|
-
tokens.splice(j + 1, 0, closeBracket);
|
|
1559
|
-
return 2;
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1565
|
-
// Dynamic classes
|
|
1566
|
-
// div.('card', x && 'active') → div.__clsx('card', x && 'active')
|
|
1567
|
-
// .('card') → div.__clsx('card')
|
|
1568
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1569
|
-
if (tag === '.' && nextToken && nextToken[0] === '(') {
|
|
1570
|
-
let prevToken = i > 0 ? tokens[i - 1] : null;
|
|
1571
|
-
let prevTag = prevToken ? prevToken[0] : null;
|
|
1572
|
-
let atLineStart = prevTag === 'INDENT' || prevTag === 'TERMINATOR';
|
|
1573
|
-
|
|
1574
|
-
let cxToken = gen('PROPERTY', '__clsx', token);
|
|
1575
|
-
nextToken[0] = 'CALL_START';
|
|
1576
|
-
let depth = 1;
|
|
1577
|
-
for (let j = i + 2; j < tokens.length && depth > 0; j++) {
|
|
1578
|
-
if (tokens[j][0] === '(' || tokens[j][0] === 'CALL_START') depth++;
|
|
1579
|
-
else if (tokens[j][0] === ')') {
|
|
1580
|
-
depth--;
|
|
1581
|
-
if (depth === 0) tokens[j][0] = 'CALL_END';
|
|
1582
|
-
} else if (tokens[j][0] === 'CALL_END') depth--;
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
if (atLineStart) {
|
|
1586
|
-
let divToken = gen('IDENTIFIER', 'div', token);
|
|
1587
|
-
tokens.splice(i, 0, divToken);
|
|
1588
|
-
tokens.splice(i + 2, 0, cxToken);
|
|
1589
|
-
return 3;
|
|
1590
|
-
} else {
|
|
1591
|
-
tokens.splice(i + 1, 0, cxToken);
|
|
1592
|
-
return 2;
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1597
|
-
// Implicit nesting (inject -> before INDENT)
|
|
1598
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1599
|
-
if (nextToken && nextToken[0] === 'INDENT') {
|
|
1600
|
-
if (tag === '->' || tag === '=>' || tag === 'CALL_START' || tag === '(') {
|
|
1601
|
-
return 1;
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
let isTemplateElement = false;
|
|
1605
|
-
let prevTag = i > 0 ? tokens[i - 1][0] : null;
|
|
1606
|
-
let isAfterControlFlow = prevTag === 'IF' || prevTag === 'UNLESS' || prevTag === 'WHILE' || prevTag === 'UNTIL' || prevTag === 'WHEN';
|
|
1607
|
-
|
|
1608
|
-
if (tag === 'IDENTIFIER' && isTemplateTag(token[1]) && !isAfterControlFlow) {
|
|
1609
|
-
isTemplateElement = true;
|
|
1610
|
-
} else if (tag === 'PROPERTY' || tag === 'STRING' || tag === 'CALL_END' || tag === ')') {
|
|
1611
|
-
isTemplateElement = startsWithTag(tokens, i);
|
|
1612
|
-
}
|
|
1613
|
-
else if (tag === 'IDENTIFIER' && i > 1 && tokens[i - 1][0] === '...') {
|
|
1614
|
-
if (startsWithTag(tokens, i)) {
|
|
1615
|
-
let commaToken = gen(',', ',', token);
|
|
1616
|
-
let arrowToken = gen('->', '->', token);
|
|
1617
|
-
arrowToken.newLine = true;
|
|
1618
|
-
tokens.splice(i + 1, 0, commaToken, arrowToken);
|
|
1619
|
-
return 3;
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
if (isTemplateElement) {
|
|
1624
|
-
let isClassOrIdTail = tag === 'PROPERTY' && i > 0 && (tokens[i - 1][0] === '.' || tokens[i - 1][0] === '#');
|
|
1625
|
-
if ((tag === 'IDENTIFIER' && isTemplateTag(token[1])) || isClassOrIdTail) {
|
|
1626
|
-
// Bare tag or tag.class/tag#id (no other args): inject CALL_START -> and manage CALL_END
|
|
1627
|
-
let callStartToken = gen('CALL_START', '(', token);
|
|
1628
|
-
let arrowToken = gen('->', '->', token);
|
|
1629
|
-
arrowToken.newLine = true;
|
|
1630
|
-
tokens.splice(i + 1, 0, callStartToken, arrowToken);
|
|
1631
|
-
pendingCallEnds.push(currentIndent + 1);
|
|
1632
|
-
return 3;
|
|
1633
|
-
} else {
|
|
1634
|
-
// Tag with args: inject , -> (call wrapping handled by addImplicitBracesAndParens)
|
|
1635
|
-
let commaToken = gen(',', ',', token);
|
|
1636
|
-
let arrowToken = gen('->', '->', token);
|
|
1637
|
-
arrowToken.newLine = true;
|
|
1638
|
-
tokens.splice(i + 1, 0, commaToken, arrowToken);
|
|
1639
|
-
return 3;
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1645
|
-
// Bare component reference (PascalCase, no children, no args)
|
|
1646
|
-
// Counter → Counter() so it gets treated as a component instantiation
|
|
1647
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
1648
|
-
if (tag === 'IDENTIFIER' && isComponent(token[1]) &&
|
|
1649
|
-
nextToken && (nextToken[0] === 'OUTDENT' || nextToken[0] === 'TERMINATOR')) {
|
|
1650
|
-
tokens.splice(i + 1, 0, gen('CALL_START', '(', token), gen('CALL_END', ')', token));
|
|
1651
|
-
return 3;
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
return 1;
|
|
1655
|
-
});
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
1385
|
tagPostfixConditionals() {
|
|
1659
1386
|
let original = null;
|
|
1660
1387
|
|