rip-lang 3.16.0 → 3.16.2

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.
Files changed (57) hide show
  1. package/README.md +3 -4
  2. package/bin/rip +201 -18
  3. package/bin/rip-schema +175 -0
  4. package/docs/AGENTS.md +1 -1
  5. package/docs/RIP-APP.md +200 -19
  6. package/docs/RIP-DUCKDB.md +64 -1
  7. package/docs/RIP-INTRO.md +4 -4
  8. package/docs/RIP-LANG.md +36 -38
  9. package/docs/RIP-SCHEMA.md +1204 -364
  10. package/docs/RIP-TYPES.md +74 -103
  11. package/docs/demo/README.md +4 -3
  12. package/docs/dist/rip.js +4195 -966
  13. package/docs/dist/rip.min.js +1161 -284
  14. package/docs/dist/rip.min.js.br +0 -0
  15. package/docs/example/index.json +7 -7
  16. package/docs/example/index.json.br +0 -0
  17. package/docs/extensions/vscode/print/print-1.0.14.vsix +0 -0
  18. package/docs/extensions/vscode/print/print-latest.vsix +0 -0
  19. package/docs/extensions/vscode/rip/index.html +2 -1
  20. package/docs/extensions/vscode/rip/rip-0.5.15.vsix +0 -0
  21. package/docs/extensions/vscode/rip/rip-latest.vsix +0 -0
  22. package/docs/extensions/vscode/rip/vscode-rip-0.6.0.vsix +0 -0
  23. package/docs/index.html +1 -1
  24. package/docs/ui/bundle.json +55 -55
  25. package/docs/ui/bundle.json.br +0 -0
  26. package/docs/ui/hljs-rip.js +1 -1
  27. package/docs/ui/index.html +1 -1
  28. package/package.json +15 -7
  29. package/rip-loader.js +59 -2
  30. package/src/AGENTS.md +43 -12
  31. package/src/browser.js +52 -11
  32. package/src/compiler.js +538 -80
  33. package/src/components.js +488 -48
  34. package/src/dts.js +80 -50
  35. package/src/grammar/README.md +29 -170
  36. package/src/grammar/grammar.rip +17 -12
  37. package/src/grammar/solar.rip +4 -17
  38. package/src/lexer.js +82 -32
  39. package/src/parser.js +229 -229
  40. package/src/schema/dts.js +328 -54
  41. package/src/schema/loader-server.js +2 -1
  42. package/src/schema/runtime-browser-stubs.js +20 -9
  43. package/src/schema/runtime-ddl.js +161 -44
  44. package/src/schema/runtime-migrate.js +681 -0
  45. package/src/schema/runtime-orm.js +698 -54
  46. package/src/schema/runtime-validate.js +808 -24
  47. package/src/schema/runtime.generated.js +2395 -135
  48. package/src/schema/schema.js +1054 -94
  49. package/src/typecheck.js +1610 -127
  50. package/src/types.js +90 -6
  51. package/src/grammar/lunar.rip +0 -2412
  52. /package/docs/demo/{components → routes}/_layout.rip +0 -0
  53. /package/docs/demo/{components → routes}/about.rip +0 -0
  54. /package/docs/demo/{components → routes}/card.rip +0 -0
  55. /package/docs/demo/{components → routes}/counter.rip +0 -0
  56. /package/docs/demo/{components → routes}/index.rip +0 -0
  57. /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;
@@ -369,13 +378,45 @@ function collectTypeExpression(tokens, j) {
369
378
  }
370
379
  if (tTag === '=' || tTag === 'REACTIVE_ASSIGN' ||
371
380
  tTag === 'COMPUTED_ASSIGN' || tTag === 'READONLY_ASSIGN' ||
372
- tTag === 'EFFECT' || tTag === 'TERMINATOR' ||
381
+ tTag === 'EFFECT' || tTag === 'GATE' || tTag === 'TERMINATOR' ||
373
382
  tTag === 'INDENT' || tTag === 'OUTDENT' ||
374
383
  tTag === '->' || tTag === ',') {
375
384
  break;
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,50 @@ 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
- let typeStr = typeTokens.map(t => t[1]).join(' ').replace(/\s+/g, ' ').trim();
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
+ // Embedded-JS tokens are backtick literals with the delimiters stripped
474
+ // by the lexer. In type position they are TS template-literal types
475
+ // (e.g. `${number} min`) — re-wrap them so the emitted type is valid.
476
+ if (t[0] === 'JS') return '`' + t[1] + '`';
477
+ return t[1];
478
+ });
479
+ let typeStr = parts.join(' ').replace(/\s+/g, ' ').trim();
396
480
  typeStr = typeStr
397
481
  .replace(/\s*<\s*/g, '<').replace(/\s*>\s*/g, '>')
398
482
  .replace(/\s*\[\s*/g, '[').replace(/\s*\]\s*/g, ']')
@@ -485,13 +569,13 @@ function collectStructuralType(tokens, indentIdx) {
485
569
  (/^[a-zA-Z_$]/.test(tokens[j][1]) && tokens[j + 1]?.[0] === 'TYPE_ANNOTATION'))) {
486
570
  readonly = true;
487
571
  propName = tokens[j][1];
488
- // Carry predicate flag through
489
- if (tokens[j].data?.predicate) optional = true;
572
+ // Carry optional flag through
573
+ if (tokens[j].data?.optional) optional = true;
490
574
  j++;
491
575
  }
492
576
 
493
- // Check for ? (optional property) — lexer stores as .data.predicate
494
- if (t.data?.predicate) optional = true;
577
+ // Check for ? (optional property) — lexer stores as .data.optional
578
+ if (t.data?.optional) optional = true;
495
579
  // Also check for standalone ? token
496
580
  if (tokens[j]?.[1] === '?' && !tokens[j]?.spaced) {
497
581
  optional = true;