rip-lang 3.16.0 → 3.16.1
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 +1 -1
- package/bin/rip +162 -10
- package/docs/AGENTS.md +1 -1
- package/docs/RIP-APP.md +109 -17
- package/docs/RIP-LANG.md +4 -5
- package/docs/RIP-TYPES.md +74 -103
- package/docs/demo/README.md +4 -3
- package/docs/dist/rip.js +933 -338
- package/docs/dist/rip.min.js +209 -204
- package/docs/dist/rip.min.js.br +0 -0
- package/docs/example/index.json +7 -7
- package/docs/example/index.json.br +0 -0
- package/docs/extensions/vscode/print/print-1.0.14.vsix +0 -0
- package/docs/extensions/vscode/print/print-latest.vsix +0 -0
- package/docs/extensions/vscode/rip/rip-0.5.15.vsix +0 -0
- package/docs/extensions/vscode/rip/rip-latest.vsix +0 -0
- package/docs/ui/bundle.json +55 -55
- package/docs/ui/bundle.json.br +0 -0
- package/docs/ui/index.html +1 -1
- package/package.json +9 -4
- package/rip-loader.js +59 -2
- package/src/AGENTS.md +5 -5
- package/src/browser.js +52 -11
- package/src/compiler.js +318 -44
- package/src/components.js +178 -39
- package/src/dts.js +62 -47
- package/src/lexer.js +58 -15
- package/src/schema/schema.js +5 -5
- package/src/typecheck.js +1355 -100
- package/src/types.js +85 -5
- /package/docs/demo/{components → routes}/_layout.rip +0 -0
- /package/docs/demo/{components → routes}/about.rip +0 -0
- /package/docs/demo/{components → routes}/card.rip +0 -0
- /package/docs/demo/{components → routes}/counter.rip +0 -0
- /package/docs/demo/{components → routes}/index.rip +0 -0
- /package/docs/demo/{components → routes}/todos.rip +0 -0
package/src/types.js
CHANGED
|
@@ -316,6 +316,7 @@ export function installTypeSupport(Lexer) {
|
|
|
316
316
|
function collectTypeExpression(tokens, j) {
|
|
317
317
|
let typeTokens = [];
|
|
318
318
|
let depth = 0;
|
|
319
|
+
let bracketStack = []; // tracks innermost open bracket: '{', '[', '(', '<'
|
|
319
320
|
let startJ = j;
|
|
320
321
|
|
|
321
322
|
while (j < tokens.length) {
|
|
@@ -333,6 +334,8 @@ function collectTypeExpression(tokens, j) {
|
|
|
333
334
|
// Handle >> as two > closes (nested generics: Map<string, Set<number>>)
|
|
334
335
|
if (tTag === 'SHIFT' && t[1] === '>>' && depth >= 2) {
|
|
335
336
|
depth -= 2;
|
|
337
|
+
if (bracketStack[bracketStack.length - 1] === '<') bracketStack.pop();
|
|
338
|
+
if (bracketStack[bracketStack.length - 1] === '<') bracketStack.pop();
|
|
336
339
|
typeTokens.push(t);
|
|
337
340
|
j++;
|
|
338
341
|
continue;
|
|
@@ -340,6 +343,11 @@ function collectTypeExpression(tokens, j) {
|
|
|
340
343
|
|
|
341
344
|
if (isOpen) {
|
|
342
345
|
depth++;
|
|
346
|
+
let kind = (tTag === '{') ? '{'
|
|
347
|
+
: (tTag === '[' || tTag === 'INDEX_START') ? '['
|
|
348
|
+
: (tTag === 'COMPARE' && t[1] === '<') ? '<'
|
|
349
|
+
: '(';
|
|
350
|
+
bracketStack.push(kind);
|
|
343
351
|
typeTokens.push(t);
|
|
344
352
|
j++;
|
|
345
353
|
continue;
|
|
@@ -347,6 +355,7 @@ function collectTypeExpression(tokens, j) {
|
|
|
347
355
|
if (isClose) {
|
|
348
356
|
if (depth > 0) {
|
|
349
357
|
depth--;
|
|
358
|
+
bracketStack.pop();
|
|
350
359
|
typeTokens.push(t);
|
|
351
360
|
j++;
|
|
352
361
|
continue;
|
|
@@ -376,6 +385,38 @@ function collectTypeExpression(tokens, j) {
|
|
|
376
385
|
}
|
|
377
386
|
}
|
|
378
387
|
|
|
388
|
+
// Inside a bracketed type expression, INDENT/OUTDENT/TERMINATOR are
|
|
389
|
+
// pure layout tokens (multi-line type literal `{ \n field: T \n }`).
|
|
390
|
+
// They carry no semantic meaning and would otherwise leak their raw
|
|
391
|
+
// `[1]` value (e.g. an indent level integer like `2`) into the
|
|
392
|
+
// type string. INDENT/OUTDENT are dropped silently; TERMINATOR
|
|
393
|
+
// separates fields and is replaced with a synthetic `;` so the
|
|
394
|
+
// emitted type literal is valid TS (`{ a: T; b: U }`).
|
|
395
|
+
if (depth > 0 && (tTag === 'INDENT' || tTag === 'OUTDENT')) {
|
|
396
|
+
j++;
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (depth > 0 && tTag === 'TERMINATOR') {
|
|
400
|
+
typeTokens.push(['', ';']);
|
|
401
|
+
j++;
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Inside `{ ... }` the Rip rewriter sometimes drops TERMINATOR
|
|
406
|
+
// between fields (e.g. after `Record<string, string[]>` because `>`
|
|
407
|
+
// looks like a binary operator wanting a RHS). Detect a new field
|
|
408
|
+
// by seeing a PROPERTY token at the top of a `{` and inject `;` if
|
|
409
|
+
// the previously emitted token isn't already a separator/opener.
|
|
410
|
+
if (tTag === 'PROPERTY' &&
|
|
411
|
+
bracketStack[bracketStack.length - 1] === '{') {
|
|
412
|
+
let prev = typeTokens[typeTokens.length - 1];
|
|
413
|
+
let prevTag = prev?.[0];
|
|
414
|
+
let prevVal = prev?.[1];
|
|
415
|
+
let needsSep = prev && prevTag !== '{' && prevTag !== ',' &&
|
|
416
|
+
!(prevTag === '' && prevVal === ';');
|
|
417
|
+
if (needsSep) typeTokens.push(['', ';']);
|
|
418
|
+
}
|
|
419
|
+
|
|
379
420
|
// => at depth 0: function type arrow, continue collecting
|
|
380
421
|
// -> at depth 0: code arrow, handled as delimiter above
|
|
381
422
|
typeTokens.push(t);
|
|
@@ -392,7 +433,46 @@ function buildTypeString(typeTokens) {
|
|
|
392
433
|
if (typeTokens.length === 0) return '';
|
|
393
434
|
// Bare => (no params) means () => — add empty parens
|
|
394
435
|
if (typeTokens[0]?.[0] === '=>') typeTokens.unshift(['', '()']);
|
|
395
|
-
|
|
436
|
+
// Validation: `::` inside `{ ... }` in type position is illegal.
|
|
437
|
+
// `::` binds a name to a type (params, var decls, return types).
|
|
438
|
+
// Inside a structural type literal `{ ... }`, fields are key→type
|
|
439
|
+
// pairs and use `:` (TS-style), the same way TS type literals do.
|
|
440
|
+
// `::` has no role inside a type literal — every `:` there is
|
|
441
|
+
// already unambiguously a type separator.
|
|
442
|
+
{
|
|
443
|
+
let curlyDepth = 0;
|
|
444
|
+
for (let t of typeTokens) {
|
|
445
|
+
let tag = t[0];
|
|
446
|
+
if (tag === '{') curlyDepth++;
|
|
447
|
+
else if (tag === '}') curlyDepth--;
|
|
448
|
+
else if (tag === 'TYPE_ANNOTATION' && curlyDepth > 0) {
|
|
449
|
+
let loc = t.loc;
|
|
450
|
+
let where = loc ? ` (line ${loc.r}, col ${loc.c})` : '';
|
|
451
|
+
let err = new Error(
|
|
452
|
+
`Use \`:\` (not \`::\`) inside a structural type literal${where}. ` +
|
|
453
|
+
`\`::\` binds a name to a type; inside \`{ ... }\` in type ` +
|
|
454
|
+
`position, fields use \`:\` (TS-style).`
|
|
455
|
+
);
|
|
456
|
+
err.loc = loc;
|
|
457
|
+
throw err;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
// Inline structural / function-param property-name optional marker:
|
|
462
|
+
// an IDENTIFIER carrying `.data.optional` and followed by TYPE_ANNOTATION
|
|
463
|
+
// gets a trailing `?` appended to its emitted name. The lexer stripped
|
|
464
|
+
// the trailing `?` from the token text but flagged it on `.data.optional`.
|
|
465
|
+
let parts = typeTokens.map((t, i) => {
|
|
466
|
+
let next = typeTokens[i + 1];
|
|
467
|
+
// Re-attach the trailing `?` for optional property names. The next
|
|
468
|
+
// separator is `::` (TYPE_ANNOTATION) in function param lists, or
|
|
469
|
+
// `:` inside an inline structural type literal `{ x?: T }`.
|
|
470
|
+
if (t.data?.optional && next && (next[0] === 'TYPE_ANNOTATION' || next[0] === ':')) {
|
|
471
|
+
return `${t[1]}?`;
|
|
472
|
+
}
|
|
473
|
+
return t[1];
|
|
474
|
+
});
|
|
475
|
+
let typeStr = parts.join(' ').replace(/\s+/g, ' ').trim();
|
|
396
476
|
typeStr = typeStr
|
|
397
477
|
.replace(/\s*<\s*/g, '<').replace(/\s*>\s*/g, '>')
|
|
398
478
|
.replace(/\s*\[\s*/g, '[').replace(/\s*\]\s*/g, ']')
|
|
@@ -485,13 +565,13 @@ function collectStructuralType(tokens, indentIdx) {
|
|
|
485
565
|
(/^[a-zA-Z_$]/.test(tokens[j][1]) && tokens[j + 1]?.[0] === 'TYPE_ANNOTATION'))) {
|
|
486
566
|
readonly = true;
|
|
487
567
|
propName = tokens[j][1];
|
|
488
|
-
// Carry
|
|
489
|
-
if (tokens[j].data?.
|
|
568
|
+
// Carry optional flag through
|
|
569
|
+
if (tokens[j].data?.optional) optional = true;
|
|
490
570
|
j++;
|
|
491
571
|
}
|
|
492
572
|
|
|
493
|
-
// Check for ? (optional property) — lexer stores as .data.
|
|
494
|
-
if (t.data?.
|
|
573
|
+
// Check for ? (optional property) — lexer stores as .data.optional
|
|
574
|
+
if (t.data?.optional) optional = true;
|
|
495
575
|
// Also check for standalone ? token
|
|
496
576
|
if (tokens[j]?.[1] === '?' && !tokens[j]?.spaced) {
|
|
497
577
|
optional = true;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|