tjs-lang 0.6.38 → 0.6.39

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tjs-lang",
3
- "version": "0.6.38",
3
+ "version": "0.6.39",
4
4
  "description": "Type-safe JavaScript dialect with runtime validation, sandboxed VM execution, and AI agent orchestration. Transpiles TypeScript to validated JS with fuel-metered execution for untrusted code.",
5
5
  "keywords": [
6
6
  "typescript",
package/src/cli/tjs.ts CHANGED
@@ -20,7 +20,7 @@ import { emit } from './commands/emit'
20
20
  import { convert } from './commands/convert'
21
21
  import { test } from './commands/test'
22
22
 
23
- const VERSION = '0.6.38'
23
+ const VERSION = '0.6.39'
24
24
 
25
25
  const HELP = `
26
26
  tjs - Typed JavaScript CLI
@@ -343,10 +343,38 @@ export function transformParenExpressions(
343
343
  // Look for class method syntax: constructor(, methodName(, get name(, set name(
344
344
  // These appear inside class bodies and need param transformation
345
345
  // Only match if we're actually in a class body (proper context tracking)
346
+ // Must NOT match function calls in expressions (div(), span(), etc.)
346
347
  const methodMatch = source
347
348
  .slice(i)
348
349
  .match(/^(constructor|(?:get|set)\s+\w+|async\s+\w+|\w+)\s*\(/)
349
- if (methodMatch && isInClassBody()) {
350
+ // Check that the preceding non-whitespace character indicates this is a
351
+ // declaration, not a function call in an expression.
352
+ // Method declarations follow: newline, {, ;, or start of file
353
+ // Function calls follow: = => , [ ( . operators etc.
354
+ const prevNonWs = (() => {
355
+ for (let k = result.length - 1; k >= 0; k--) {
356
+ if (!/\s/.test(result[k])) return result[k]
357
+ }
358
+ return '\n' // start of input
359
+ })()
360
+ // Method declarations can follow almost anything (property, }, ;, etc.)
361
+ // Function CALLS in expressions specifically follow: = => , [ (
362
+ const isMethodDecl =
363
+ prevNonWs !== '=' &&
364
+ prevNonWs !== ',' &&
365
+ prevNonWs !== '(' &&
366
+ prevNonWs !== '[' &&
367
+ prevNonWs !== '>' // catches =>
368
+ if (methodMatch && isInClassBody() && !isMethodDecl) {
369
+ // Not a method declaration (it's a function call in an expression).
370
+ // Skip past the identifier to prevent re-matching a suffix
371
+ // (e.g. 'div(' → skip 'div', don't let 'iv(' match next).
372
+ const skipLen = methodMatch[1].length
373
+ result += source.slice(i, i + skipLen)
374
+ i += skipLen
375
+ continue
376
+ }
377
+ if (methodMatch && isInClassBody() && isMethodDecl) {
350
378
  // We're actually in a class body - this is a method definition
351
379
  const methodPart = methodMatch[1]
352
380
  const matchLen = methodMatch[0].length
@@ -202,11 +202,48 @@ class Foo {
202
202
  expect(tjsResult.code).toContain('static set label')
203
203
  })
204
204
 
205
- test('shorthand property assignment in destructuring converts', () => {
206
- // component.test.ts fails to convert with:
205
+ test('destructured arrow param in class property fails TJS parse', () => {
206
+ // In tosijs component.test.ts, a class property is an arrow function
207
+ // with a destructured parameter:
208
+ //
209
+ // content = ({ div, span }: typeof elements) => [...]
210
+ //
211
+ // fromTS (TS→TJS) handles this fine, stripping the type annotation:
212
+ // content = ({ div, span }) => [...]
213
+ //
214
+ // But the TJS parser then chokes on this with:
207
215
  // "Shorthand property assignments are valid only in destructuring patterns"
208
216
  //
209
- // Minimal pattern that triggers the error:
217
+ // The bug is in the TJS→JS step (tjs parser), not the TS→TJS step.
218
+
219
+ const source = `
220
+ class TestComponent {
221
+ content = ({ div, span }: { div: Function, span: Function }) => [
222
+ div({ part: 'container' }, span({ part: 'label' }, 'Test')),
223
+ ]
224
+
225
+ render() {}
226
+ }
227
+ `
228
+ const tjsResult = fromTS(source, {
229
+ emitTJS: true,
230
+ filename: 'destructured-param.ts',
231
+ })
232
+
233
+ // TS→TJS works fine
234
+ expect(tjsResult.code).toContain('content')
235
+
236
+ // TJS→JS fails on the destructured arrow param in class property
237
+ expect(() => {
238
+ tjs(tjsResult.code, {
239
+ filename: 'destructured-param.ts',
240
+ runTests: false,
241
+ })
242
+ }).not.toThrow()
243
+ })
244
+
245
+ test('shorthand property assignment in destructuring converts', () => {
246
+ // Also from component.test.ts — default values in destructuring:
210
247
  // const { mode = 'default' } = getConfig()
211
248
 
212
249
  const source = `