rip-lang 3.13.134 → 3.13.136

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/src/repl.js CHANGED
@@ -17,7 +17,7 @@ import * as fs from 'fs';
17
17
  import * as path from 'path';
18
18
  import * as os from 'os';
19
19
  import * as vm from 'vm';
20
- import { Compiler, compileToJS, getStdlibCode, getReactiveRuntime, getComponentRuntime } from './compiler.js';
20
+ import { Compiler, compileToJS, getStdlibCode, getReactiveRuntime, getComponentRuntime, formatError } from './compiler.js';
21
21
  import packageJson from '../package.json' with { type: 'json' };
22
22
 
23
23
  const VERSION = packageJson.version;
@@ -205,6 +205,7 @@ export class RipREPL {
205
205
  async evaluate(code) {
206
206
  try {
207
207
  this.history.push(code);
208
+ this._lastSource = code;
208
209
 
209
210
  const compiler = new Compiler({
210
211
  showTokens: this.showTokens,
@@ -433,7 +434,7 @@ export class RipREPL {
433
434
  }
434
435
 
435
436
  printError(error) {
436
- console.log(`${colors.red}✗${colors.reset} ${colors.red}${error.message}${colors.reset}`);
437
+ console.log(formatError(error, { source: this._lastSource, color: true }));
437
438
  if (error.stack && process.env.RIP_DEBUG) {
438
439
  console.log(`${colors.dim}${error.stack}${colors.reset}`);
439
440
  }
@@ -109,6 +109,10 @@ export function mapToSourcePos(entry, offset) {
109
109
  // match string literals or identifiers in the source.
110
110
  if (/^declare\s+function\s/.test(genLineText)) return null;
111
111
 
112
+ // If genToSrc has a mapping for this header line (e.g. imports, declarations),
113
+ // use it to target the correct source line for word matching.
114
+ const mappedSrcLine = entry.genToSrc.get(tsLine);
115
+
112
116
  let lineStart = 0, curLine = 0;
113
117
  for (let i = 0; i < entry.tsContent.length; i++) {
114
118
  if (curLine === tsLine) { lineStart = i; break; }
@@ -121,6 +125,13 @@ export function mapToSourcePos(entry, offset) {
121
125
  const srcLines = entry.source.split('\n');
122
126
  const re = new RegExp('\\b' + word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b');
123
127
 
128
+ // If we have a direct line mapping, try that source line first
129
+ if (mappedSrcLine !== undefined) {
130
+ const m = re.exec(srcLines[mappedSrcLine]);
131
+ if (m) return { line: mappedSrcLine, col: m.index };
132
+ return { line: mappedSrcLine, col: genCol };
133
+ }
134
+
124
135
  // For let/var declarations, the error word may appear on many source lines
125
136
  // (e.g. `Status` referenced in multiple variable annotations). Narrow the
126
137
  // search to the source line that declares the same variable.
@@ -253,13 +264,17 @@ export function mapToSourcePos(entry, offset) {
253
264
  // Scan ALL source lines for mappings to this gen line — a multi-line Rip
254
265
  // expression (e.g. object literal) may compile to a single gen line, so
255
266
  // multiple source lines can share one gen line. Pick the closest genCol.
267
+ // On ties, prefer the source line that genToSrc already identified (e.g.
268
+ // from an @rip-src annotation) so that stub render-block expressions land
269
+ // on their correct source lines instead of a sibling attribute line.
256
270
  if (entry.srcColToGen) {
271
+ const origSrcLine = srcLine;
257
272
  let bestDist = Infinity;
258
273
  for (const [sl, entries] of entry.srcColToGen) {
259
274
  for (const e of entries) {
260
275
  if (e.genLine === tsLine) {
261
276
  const dist = Math.abs(e.genCol - genCol);
262
- if (dist < bestDist) {
277
+ if (dist < bestDist || (dist === bestDist && sl === origSrcLine)) {
263
278
  bestDist = dist;
264
279
  srcLine = sl;
265
280
  approx = e.srcCol + (genCol - e.genCol);
@@ -310,17 +325,24 @@ export function mapToSourcePos(entry, offset) {
310
325
  }
311
326
  }
312
327
  srcCol = Math.max(0, approx);
328
+ }
313
329
 
314
- // Word not found on mapped line — search nearby lines (handles cases where
315
- // multiple source lines compress to one generated line, e.g. constructor params)
316
- const wordFallback = genText.slice(genCol).match(/^\w+/);
330
+ // Word not found on mapped line (or line was empty) — search nearby lines
331
+ // (handles cases where multiple source lines compress to one generated line,
332
+ // e.g. constructor params, or srcLine is blank)
333
+ {
334
+ let wordFallback = genText.slice(genCol).match(/^\w+/);
335
+ // Quoted string literal — peek inside the quotes (e.g. __RipProps<'inputz'>)
336
+ if (!wordFallback && (genText[genCol] === "'" || genText[genCol] === '"')) {
337
+ wordFallback = genText.slice(genCol + 1).match(/^\w+/);
338
+ }
317
339
  if (wordFallback) {
318
340
  let word = wordFallback[0];
319
341
  if (word.startsWith('__bind_') && word.endsWith('__')) word = word.slice(7, -2);
320
342
  const srcLines = entry.source.split('\n');
321
343
  const re = new RegExp('\\b' + word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b');
322
- for (let delta = 1; delta <= 10; delta++) {
323
- for (const d of [srcLine + delta, srcLine - delta]) {
344
+ for (let delta = 0; delta <= 10; delta++) {
345
+ for (const d of delta === 0 ? [srcLine] : [srcLine + delta, srcLine - delta]) {
324
346
  if (d >= 0 && d < srcLines.length) {
325
347
  const m = re.exec(srcLines[d]);
326
348
  if (m) return { line: d, col: m.index };
@@ -329,5 +351,16 @@ export function mapToSourcePos(entry, offset) {
329
351
  }
330
352
  }
331
353
  }
354
+
355
+ // When text matching failed entirely (generated identifier like _2 doesn't
356
+ // exist in source), srcCol may land on whitespace or past EOL. Fall back to
357
+ // the first word on the source line so the diagnostic highlights something
358
+ // meaningful (e.g. the component name on a `Button` line).
359
+ if (srcText) {
360
+ if (srcCol >= srcText.length || /^\s*$/.test(srcText.slice(srcCol, srcCol + 1))) {
361
+ const firstWord = srcText.match(/^\s*(\w+)/);
362
+ if (firstWord) return { line: srcLine, col: firstWord.index + firstWord[0].length - firstWord[1].length };
363
+ }
364
+ }
332
365
  return { line: srcLine, col: srcCol };
333
366
  }