rip-lang 3.13.78 → 3.13.80

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 CHANGED
@@ -9,7 +9,7 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.78-blue.svg" alt="Version"></a>
12
+ <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.80-blue.svg" alt="Version"></a>
13
13
  <a href="#zero-dependencies"><img src="https://img.shields.io/badge/dependencies-ZERO-brightgreen.svg" alt="Dependencies"></a>
14
14
  <a href="#"><img src="https://img.shields.io/badge/tests-1%2C436%2F1%2C436-brightgreen.svg" alt="Tests"></a>
15
15
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rip-lang",
3
- "version": "3.13.78",
3
+ "version": "3.13.80",
4
4
  "description": "A modern language that compiles to JavaScript",
5
5
  "type": "module",
6
6
  "main": "src/compiler.js",
@@ -66,5 +66,8 @@
66
66
  },
67
67
  "homepage": "https://github.com/shreeve/rip-lang#readme",
68
68
  "author": "Steve Shreeve <steve.shreeve@gmail.com>",
69
- "license": "MIT"
69
+ "license": "MIT",
70
+ "devDependencies": {
71
+ "typescript": "5.9.3"
72
+ }
70
73
  }
package/src/compiler.js CHANGED
@@ -297,6 +297,11 @@ export class CodeGenerator {
297
297
  if (entry.loc) {
298
298
  this.sourceMap.addMapping(lineOffset, 0, entry.loc.r, entry.loc.c);
299
299
  }
300
+ if (entry.subLocs) {
301
+ for (const { lineOffset: lo, loc } of entry.subLocs) {
302
+ if (loc) this.sourceMap.addMapping(lineOffset + lo, 0, loc.r, loc.c);
303
+ }
304
+ }
300
305
  lineOffset += entry.code.split('\n').length;
301
306
  }
302
307
  }
@@ -619,7 +624,12 @@ export class CodeGenerator {
619
624
  if (!blockStmts.includes(h) || !generated.endsWith('}')) generated += ';';
620
625
  }
621
626
  let loc = Array.isArray(stmt) ? stmt.loc : null;
622
- return { code: generated, loc };
627
+ let entry = { code: generated, loc };
628
+ if (this._pendingComponentLineLocs) {
629
+ entry.subLocs = this._pendingComponentLineLocs;
630
+ this._pendingComponentLineLocs = null;
631
+ }
632
+ return entry;
623
633
  });
624
634
  let statementsCode = stmtEntries.map(e => e.code).join('\n');
625
635
 
@@ -3397,10 +3407,14 @@ declare function __computed<T>(fn: () => T): Computed<T>;
3397
3407
  declare function __effect(fn: () => void | (() => void)): () => void;
3398
3408
  declare function __batch<T>(fn: () => T): T;
3399
3409
  declare function __readonly<T>(v: T): Readonly<{ value: T }>;
3410
+ declare function __pushComponent(component: any): any;
3411
+ declare function __popComponent(prev: any): void;
3412
+ declare function __handleComponentError(error: any, component: any): void;
3413
+ declare function __clsx(...args: any[]): string;
3400
3414
  declare function setContext(key: string, value: any): void;
3401
3415
  declare function getContext(key: string): any;
3402
3416
  declare function hasContext(key: string): boolean;
3403
- declare class __Component { constructor(props?: any); [key: string]: any; }
3417
+ declare class __Component { constructor(props?: any); _create?(): any; _setup?(): void; _root?: any; _children?: any[]; [key: string]: any; }
3404
3418
  `;
3405
3419
  }
3406
3420
 
package/src/components.js CHANGED
@@ -107,6 +107,16 @@ function isPublicProp(target) {
107
107
  return Array.isArray(target) && target[0] === '.' && target[1] === 'this';
108
108
  }
109
109
 
110
+ /**
111
+ * Extract type annotation from s-expression target node.
112
+ * Type annotations are stored as .type on String objects by the type rewriter.
113
+ */
114
+ function getMemberType(target) {
115
+ if (target instanceof String && target.type) return target.type;
116
+ if (Array.isArray(target) && target[2] instanceof String && target[2].type) return target[2].type;
117
+ return null;
118
+ }
119
+
110
120
  // ============================================================================
111
121
  // Prototype Installation
112
122
  // ============================================================================
@@ -703,35 +713,35 @@ export function installComponentSupport(CodeGenerator, Lexer) {
703
713
  } else if (op === 'state') {
704
714
  const varName = getMemberName(stmt[1]);
705
715
  if (varName) {
706
- stateVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]) });
716
+ stateVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]), type: getMemberType(stmt[1]), loc: stmt.loc });
707
717
  memberNames.add(varName);
708
718
  reactiveMembers.add(varName);
709
719
  }
710
720
  } else if (op === 'computed') {
711
721
  const varName = getMemberName(stmt[1]);
712
722
  if (varName) {
713
- derivedVars.push({ name: varName, expr: stmt[2] });
723
+ derivedVars.push({ name: varName, expr: stmt[2], loc: stmt.loc });
714
724
  memberNames.add(varName);
715
725
  reactiveMembers.add(varName);
716
726
  }
717
727
  } else if (op === 'readonly') {
718
728
  const varName = getMemberName(stmt[1]);
719
729
  if (varName) {
720
- readonlyVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]) });
730
+ readonlyVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]), type: getMemberType(stmt[1]), loc: stmt.loc });
721
731
  memberNames.add(varName);
722
732
  }
723
733
  } else if (op === '=') {
724
734
  const varName = getMemberName(stmt[1]);
725
735
  if (varName) {
726
736
  if (LIFECYCLE_HOOKS.has(varName)) {
727
- lifecycleHooks.push({ name: varName, value: stmt[2] });
737
+ lifecycleHooks.push({ name: varName, value: stmt[2], loc: stmt.loc });
728
738
  } else {
729
739
  const val = stmt[2];
730
740
  if (Array.isArray(val) && (val[0] === '->' || val[0] === '=>')) {
731
- methods.push({ name: varName, func: val });
741
+ methods.push({ name: varName, func: val, loc: stmt.loc });
732
742
  memberNames.add(varName);
733
743
  } else {
734
- stateVars.push({ name: varName, value: val, isPublic: isPublicProp(stmt[1]) });
744
+ stateVars.push({ name: varName, value: val, isPublic: isPublicProp(stmt[1]), loc: stmt.loc });
735
745
  memberNames.add(varName);
736
746
  reactiveMembers.add(varName);
737
747
  }
@@ -747,9 +757,9 @@ export function installComponentSupport(CodeGenerator, Lexer) {
747
757
  if (!Array.isArray(pair)) continue;
748
758
  const [methodName, funcDef] = pair;
749
759
  if (typeof methodName === 'string' && LIFECYCLE_HOOKS.has(methodName)) {
750
- lifecycleHooks.push({ name: methodName, value: funcDef });
760
+ lifecycleHooks.push({ name: methodName, value: funcDef, loc: pair.loc });
751
761
  } else if (typeof methodName === 'string') {
752
- methods.push({ name: methodName, func: funcDef });
762
+ methods.push({ name: methodName, func: funcDef, loc: pair.loc });
753
763
  memberNames.add(methodName);
754
764
  }
755
765
  }
@@ -773,49 +783,76 @@ export function installComponentSupport(CodeGenerator, Lexer) {
773
783
  this._autoEventHandlers = autoEventHandlers.size > 0 ? autoEventHandlers : null;
774
784
 
775
785
  const lines = [];
786
+ const lineLocs = [];
776
787
  let blockFactoriesCode = '';
777
788
 
778
- lines.push('class extends __Component {');
789
+ let totalLines = 0;
790
+ const pushLine = (line, loc) => {
791
+ if (loc) lineLocs.push({ lineOffset: totalLines, loc });
792
+ lines.push(line);
793
+ totalLines += line.split('\n').length;
794
+ };
795
+ const pushPlain = (line) => {
796
+ lines.push(line);
797
+ totalLines += line.split('\n').length;
798
+ };
799
+
800
+ pushPlain('class extends __Component {');
779
801
 
780
802
  // --- Init (called by __Component constructor) ---
781
- lines.push(' _init(props) {');
803
+ if (this.options.lspMode) {
804
+ const typedProps = [];
805
+ for (const v of [...readonlyVars, ...stateVars]) {
806
+ if (v.isPublic) {
807
+ const t = v.type || 'any';
808
+ typedProps.push(`${v.name}?: ${t}`);
809
+ typedProps.push(`__bind_${v.name}__?: ${t}`);
810
+ }
811
+ }
812
+ const propsType = typedProps.length > 0
813
+ ? `{ ${typedProps.join(', ')}, [key: string]: any }`
814
+ : 'any';
815
+ pushPlain(` _init(props: ${propsType}) {`);
816
+ } else {
817
+ pushPlain(' _init(props) {');
818
+ }
782
819
 
783
820
  // Constants (readonly)
784
- for (const { name, value, isPublic } of readonlyVars) {
821
+ for (const { name, value, isPublic, loc } of readonlyVars) {
785
822
  const val = this.generateInComponent(value, 'value');
786
- lines.push(isPublic
823
+ pushLine(isPublic
787
824
  ? ` this.${name} = props.${name} ?? ${val};`
788
- : ` this.${name} = ${val};`);
825
+ : ` this.${name} = ${val};`, loc);
789
826
  }
790
827
 
791
828
  // Accepted vars (from ancestor context via getContext)
792
829
  for (const name of acceptedVars) {
793
- lines.push(` this.${name} = getContext('${name}');`);
830
+ pushPlain(` this.${name} = getContext('${name}');`);
794
831
  }
795
832
 
796
833
  // State variables (__state handles signal passthrough)
797
- for (const { name, value, isPublic } of stateVars) {
834
+ for (const { name, value, isPublic, loc } of stateVars) {
798
835
  const val = this.generateInComponent(value, 'value');
799
- lines.push(isPublic
836
+ pushLine(isPublic
800
837
  ? ` this.${name} = __state(props.__bind_${name}__ ?? props.${name} ?? ${val});`
801
- : ` this.${name} = __state(${val});`);
838
+ : ` this.${name} = __state(${val});`, loc);
802
839
  }
803
840
 
804
841
  // Computed (derived)
805
- for (const { name, expr } of derivedVars) {
842
+ for (const { name, expr, loc } of derivedVars) {
806
843
  if (this.is(expr, 'block')) {
807
844
  const transformed = this.transformComponentMembers(expr);
808
845
  const body = this.generateFunctionBody(transformed);
809
- lines.push(` this.${name} = __computed(() => ${body});`);
846
+ pushLine(` this.${name} = __computed(() => ${body});`, loc);
810
847
  } else {
811
848
  const val = this.generateInComponent(expr, 'value');
812
- lines.push(` this.${name} = __computed(() => ${val});`);
849
+ pushLine(` this.${name} = __computed(() => ${val});`, loc);
813
850
  }
814
851
  }
815
852
 
816
853
  // Offered vars (share with descendants via setContext — after all members are initialized)
817
854
  for (const name of offeredVars) {
818
- lines.push(` setContext('${name}', this.${name});`);
855
+ pushPlain(` setContext('${name}', this.${name});`);
819
856
  }
820
857
 
821
858
  // Effects
@@ -825,73 +862,81 @@ export function installComponentSupport(CodeGenerator, Lexer) {
825
862
  if (this.is(effectBody, 'block')) {
826
863
  const transformed = this.transformComponentMembers(effectBody);
827
864
  const body = this.generateFunctionBody(transformed, [], true);
828
- lines.push(` __effect(${isAsync}() => ${body});`);
865
+ pushLine(` __effect(${isAsync}() => ${body});`, effect.loc);
829
866
  } else {
830
867
  const effectCode = this.generateInComponent(effectBody, 'value');
831
- lines.push(` __effect(${isAsync}() => { ${effectCode}; });`);
868
+ pushLine(` __effect(${isAsync}() => { ${effectCode}; });`, effect.loc);
832
869
  }
833
870
  }
834
871
 
835
- lines.push(' }');
872
+ pushPlain(' }');
836
873
 
837
874
  // --- Methods ---
838
- for (const { name, func } of methods) {
875
+ for (const { name, func, loc } of methods) {
839
876
  if (Array.isArray(func) && (func[0] === '->' || func[0] === '=>')) {
840
877
  const [, params, methodBody] = func;
841
878
  const paramStr = Array.isArray(params) ? params.map(p => this.formatParam(p)).join(', ') : '';
842
879
  const transformed = this.reactiveMembers ? this.transformComponentMembers(methodBody) : methodBody;
843
880
  const isAsync = this.containsAwait(methodBody);
844
881
  const bodyCode = this.generateFunctionBody(transformed, params || []);
845
- lines.push(` ${isAsync ? 'async ' : ''}${name}(${paramStr}) ${bodyCode}`);
882
+ pushLine(` ${isAsync ? 'async ' : ''}${name}(${paramStr}) ${bodyCode}`, loc);
846
883
  }
847
884
  }
848
885
 
849
886
  // --- Lifecycle hooks ---
850
- for (const { name, value } of lifecycleHooks) {
887
+ for (const { name, value, loc } of lifecycleHooks) {
851
888
  if (Array.isArray(value) && (value[0] === '->' || value[0] === '=>')) {
852
889
  const [, params, hookBody] = value;
853
890
  const paramStr = Array.isArray(params) ? params.map(p => this.formatParam(p)).join(', ') : '';
854
891
  const transformed = this.reactiveMembers ? this.transformComponentMembers(hookBody) : hookBody;
855
892
  const isAsync = this.containsAwait(hookBody);
856
893
  const bodyCode = this.generateFunctionBody(transformed, params || []);
857
- lines.push(` ${isAsync ? 'async ' : ''}${name}(${paramStr}) ${bodyCode}`);
894
+ pushLine(` ${isAsync ? 'async ' : ''}${name}(${paramStr}) ${bodyCode}`, loc);
858
895
  }
859
896
  }
860
897
 
861
898
  // --- Render block (fine-grained) ---
862
- if (renderBlock && !this.options.lspMode) {
899
+ if (renderBlock) {
863
900
  const renderBody = renderBlock[1];
864
901
  const result = this.buildRender(renderBody);
865
902
 
866
- if (result.blockFactories.length > 0) {
903
+ if (!this.options.lspMode && result.blockFactories.length > 0) {
867
904
  blockFactoriesCode = result.blockFactories.join('\n\n') + '\n\n';
868
905
  }
869
906
 
870
- lines.push(' _create() {');
907
+ pushLine(' _create() {', renderBlock.loc);
871
908
  for (const line of result.createLines) {
872
- lines.push(` ${line}`);
909
+ pushPlain(` ${line}`);
873
910
  }
874
- lines.push(` return ${result.rootVar};`);
875
- lines.push(' }');
911
+ pushPlain(` return ${result.rootVar};`);
912
+ pushPlain(' }');
876
913
 
877
- if (result.setupLines.length > 0) {
878
- lines.push(' _setup() {');
914
+ if (!this.options.lspMode && result.setupLines.length > 0) {
915
+ pushPlain(' _setup() {');
879
916
  for (const line of result.setupLines) {
880
- lines.push(` ${line}`);
917
+ pushPlain(` ${line}`);
881
918
  }
882
- lines.push(' }');
919
+ pushPlain(' }');
883
920
  }
884
921
  }
885
922
 
886
- lines.push('}');
923
+ pushPlain('}');
887
924
 
888
925
  // Restore context
889
926
  this.componentMembers = prevComponentMembers;
890
927
  this.reactiveMembers = prevReactiveMembers;
891
928
  this._autoEventHandlers = prevAutoEventHandlers;
892
929
 
930
+ // Store line-level source mappings for the parent statement entry
931
+ if (lineLocs.length > 0) {
932
+ this._pendingComponentLineLocs = lineLocs;
933
+ }
934
+
893
935
  // If block factories exist, wrap in IIFE so they're in scope
894
936
  if (blockFactoriesCode) {
937
+ // Adjust lineOffsets for the IIFE wrapper + block factories prefix
938
+ const prefixLines = blockFactoriesCode.split('\n').length;
939
+ for (const entry of lineLocs) entry.lineOffset += prefixLines;
895
940
  return `(() => {\n${blockFactoriesCode}return ${lines.join('\n')};\n})()`;
896
941
  }
897
942
 
package/src/typecheck.js CHANGED
@@ -41,6 +41,8 @@ export const SKIP_CODES = new Set([
41
41
  2307, // Cannot find module
42
42
  2393, // Duplicate function implementation
43
43
  2451, // Cannot redeclare block-scoped variable
44
+ 2554, // Expected N arguments but got M (generated event handler wrappers pass event arg)
45
+ 7006, // Parameter implicitly has 'any' type (generated event callback params)
44
46
  1064, // Return type of async function must be Promise
45
47
  2582, // Cannot find name 'test' (test runner globals)
46
48
  2593, // Cannot find name 'describe' (test runner globals)