tjs-lang 0.7.7 → 0.8.0

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 (70) hide show
  1. package/CLAUDE.md +99 -33
  2. package/bin/docs.js +4 -1
  3. package/demo/docs.json +104 -22
  4. package/demo/src/examples.test.ts +1 -0
  5. package/demo/src/imports.test.ts +16 -4
  6. package/demo/src/imports.ts +60 -15
  7. package/demo/src/playground-shared.ts +9 -8
  8. package/demo/src/tfs-worker.js +205 -147
  9. package/demo/src/tjs-playground.ts +34 -10
  10. package/demo/src/ts-examples.ts +8 -8
  11. package/demo/src/ts-playground.ts +24 -8
  12. package/dist/index.js +118 -101
  13. package/dist/index.js.map +4 -4
  14. package/dist/src/lang/bool-coercion.d.ts +50 -0
  15. package/dist/src/lang/docs.d.ts +31 -6
  16. package/dist/src/lang/linter.d.ts +8 -0
  17. package/dist/src/lang/parser-transforms.d.ts +18 -0
  18. package/dist/src/lang/parser-types.d.ts +2 -0
  19. package/dist/src/lang/parser.d.ts +3 -0
  20. package/dist/src/lang/runtime.d.ts +34 -0
  21. package/dist/src/lang/types.d.ts +9 -1
  22. package/dist/src/rbac/index.d.ts +1 -1
  23. package/dist/src/vm/runtime.d.ts +1 -1
  24. package/dist/tjs-eval.js +38 -36
  25. package/dist/tjs-eval.js.map +4 -4
  26. package/dist/tjs-from-ts.js +20 -20
  27. package/dist/tjs-from-ts.js.map +3 -3
  28. package/dist/tjs-lang.js +85 -83
  29. package/dist/tjs-lang.js.map +4 -4
  30. package/dist/tjs-vm.js +47 -45
  31. package/dist/tjs-vm.js.map +4 -4
  32. package/llms.txt +79 -0
  33. package/package.json +9 -4
  34. package/src/cli/commands/convert.test.ts +16 -21
  35. package/src/lang/bool-coercion.test.ts +203 -0
  36. package/src/lang/bool-coercion.ts +314 -0
  37. package/src/lang/codegen.test.ts +137 -0
  38. package/src/lang/docs.test.ts +476 -1
  39. package/src/lang/docs.ts +471 -37
  40. package/src/lang/emitters/ast.ts +11 -12
  41. package/src/lang/emitters/dts.test.ts +41 -0
  42. package/src/lang/emitters/dts.ts +9 -0
  43. package/src/lang/emitters/js-tests.ts +9 -4
  44. package/src/lang/emitters/js-wasm.ts +57 -65
  45. package/src/lang/emitters/js.ts +198 -3
  46. package/src/lang/features.test.ts +4 -3
  47. package/src/lang/index.ts +9 -0
  48. package/src/lang/inference.ts +54 -0
  49. package/src/lang/linter.test.ts +104 -1
  50. package/src/lang/linter.ts +124 -1
  51. package/src/lang/module-loader.test.ts +318 -0
  52. package/src/lang/module-loader.ts +419 -0
  53. package/src/lang/parser-params.ts +31 -0
  54. package/src/lang/parser-transforms.ts +640 -0
  55. package/src/lang/parser-types.ts +35 -0
  56. package/src/lang/parser.test.ts +73 -1
  57. package/src/lang/parser.ts +77 -3
  58. package/src/lang/runtime.ts +98 -0
  59. package/src/lang/types.ts +6 -0
  60. package/src/lang/wasm.test.ts +1293 -2
  61. package/src/lang/wasm.ts +470 -87
  62. package/src/linalg/index.tjs +119 -0
  63. package/src/linalg/linalg.test.ts +294 -0
  64. package/src/linalg/vector-search.bench.test.ts +395 -0
  65. package/src/rbac/index.ts +2 -2
  66. package/src/rbac/rules.tjs.d.ts +9 -0
  67. package/src/vm/atoms/batteries.ts +2 -2
  68. package/src/vm/runtime.ts +10 -3
  69. package/dist/src/rbac/rules.d.ts +0 -184
  70. package/src/rbac/rules.js +0 -338
@@ -25,7 +25,11 @@ import {
25
25
  import { codeMirror, CodeMirror } from '../../editors/codemirror/component'
26
26
  import { tjs, generateDTS, type TJSTranspileOptions } from '../../src/lang'
27
27
  import { generateDocsMarkdown } from './docs-utils'
28
- import { rewriteImports, extractImports } from './imports'
28
+ import {
29
+ rewriteImports,
30
+ extractImports,
31
+ registerIframeContent,
32
+ } from './imports'
29
33
  import {
30
34
  buildIframeDoc,
31
35
  createIframeMessageHandler,
@@ -1259,8 +1263,8 @@ export class TJSPlayground extends Component<TJSPlaygroundParts> {
1259
1263
  const cssContent = this.parts.cssEditor.value
1260
1264
  const jsCode = this.lastTranspileResult.code
1261
1265
 
1262
- // Rewrite bare import specifiers to /tfs/ URLs
1263
- // The TFS service worker handles CDN resolution and caching
1266
+ // Rewrite bare import specifiers to absolute JSDelivr /+esm URLs
1267
+ // (sandboxed blob iframes can't reliably use the SW)
1264
1268
  const rewrittenCode = rewriteImports(jsCode)
1265
1269
 
1266
1270
  // Extract import statements — they must be at the top of the module
@@ -1304,18 +1308,38 @@ export class TJSPlayground extends Component<TJSPlaygroundParts> {
1304
1308
  })
1305
1309
  window.addEventListener('message', messageHandler)
1306
1310
 
1307
- // Set iframe content using blob URL instead of srcdoc
1308
- // This allows import maps to work with external URLs
1311
+ // Load the iframe from a same-origin URL the TFS service worker
1312
+ // serves. This makes the iframe SW-controlled, so its module imports
1313
+ // (and future virtual-module reads) go through the SW. blob: URLs
1314
+ // can't do this — Chrome SWs don't intercept fetches from sandboxed
1315
+ // blob iframes.
1309
1316
  const iframe = this.parts.previewFrame
1310
- const blob = new Blob([iframeDoc], { type: 'text/html' })
1311
- const blobUrl = URL.createObjectURL(blob)
1312
1317
 
1313
- // Clean up previous blob URL if any
1318
+ // Clean up previous blob URL if any (legacy fallback path)
1314
1319
  if (iframe.dataset.blobUrl) {
1315
1320
  URL.revokeObjectURL(iframe.dataset.blobUrl)
1321
+ delete iframe.dataset.blobUrl
1322
+ }
1323
+
1324
+ const sessionId = `tjs-${Date.now()}-${Math.random()
1325
+ .toString(36)
1326
+ .slice(2)}`
1327
+ const registered = await registerIframeContent(sessionId, iframeDoc)
1328
+
1329
+ if (registered) {
1330
+ iframe.src = `/iframe/${sessionId}`
1331
+ } else {
1332
+ // SW unavailable — fall back to blob: (no SW interception, but
1333
+ // CDN imports still work via the absolute URLs in the rewritten
1334
+ // /tfs/ paths once the SW is back).
1335
+ console.warn(
1336
+ '[playground] SW unavailable, falling back to blob: iframe'
1337
+ )
1338
+ const blob = new Blob([iframeDoc], { type: 'text/html' })
1339
+ const blobUrl = URL.createObjectURL(blob)
1340
+ iframe.dataset.blobUrl = blobUrl
1341
+ iframe.src = blobUrl
1316
1342
  }
1317
- iframe.dataset.blobUrl = blobUrl
1318
- iframe.src = blobUrl
1319
1343
 
1320
1344
  // Wait a bit for execution, then clean up listener
1321
1345
  setTimeout(() => {
@@ -423,14 +423,14 @@ console.log('(2 + 3) * 4 =', calc.add(2).add(3).multiply(4).getResult())
423
423
  description:
424
424
  'Complete example showing the TS -> TJS -> JS value proposition',
425
425
  group: 'advanced',
426
- code: `/**
427
- * THE FULL PICTURE
428
- *
429
- * TypeScript promises type safety.
430
- * TJS delivers it at RUNTIME.
431
- *
432
- * This is what "TS keeps its promise" means.
433
- */
426
+ code: `/*#
427
+ ## The Full Picture
428
+
429
+ TypeScript promises type safety.
430
+ TJS delivers it at RUNTIME.
431
+
432
+ This is what "TS keeps its promise" means.
433
+ */
434
434
 
435
435
  // Define your types with standard TypeScript syntax
436
436
  interface Product {
@@ -18,7 +18,7 @@ import {
18
18
  } from 'tosijs-ui'
19
19
  import { codeMirror, CodeMirror } from '../../editors/codemirror/component'
20
20
  import { tjs } from '../../src/lang'
21
- import { rewriteImports } from './imports'
21
+ import { rewriteImports, registerIframeContent } from './imports'
22
22
  import { generateDocsMarkdown } from './docs-utils'
23
23
  import {
24
24
  buildIframeDoc,
@@ -710,7 +710,7 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
710
710
  const cssContent = this.parts.cssEditor.value
711
711
  const jsCode = this.lastJsCode
712
712
 
713
- // Rewrite bare imports to /tfs/ URLs
713
+ // Rewrite bare imports to absolute JSDelivr /+esm URLs
714
714
  const rewrittenCode = rewriteImports(jsCode)
715
715
 
716
716
  // Create iframe document
@@ -746,17 +746,33 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
746
746
  })
747
747
  window.addEventListener('message', this._messageHandler)
748
748
 
749
- // Set iframe content using blob URL instead of srcdoc
750
- // (srcdoc can cause double-execution in some browsers)
749
+ // Load iframe from a SW-served same-origin URL so the SW controls
750
+ // the iframe's fetches. blob: URLs do not get SW interception in
751
+ // sandboxed contexts (Chrome quirk). See tjs-playground.ts.
751
752
  const iframe = this.parts.previewFrame
752
- const blob = new Blob([iframeDoc], { type: 'text/html' })
753
- const blobUrl = URL.createObjectURL(blob)
754
753
 
755
754
  if (iframe.dataset.blobUrl) {
756
755
  URL.revokeObjectURL(iframe.dataset.blobUrl)
756
+ delete iframe.dataset.blobUrl
757
+ }
758
+
759
+ const sessionId = `ts-${Date.now()}-${Math.random()
760
+ .toString(36)
761
+ .slice(2)}`
762
+ const registered = await registerIframeContent(sessionId, iframeDoc)
763
+
764
+ if (registered) {
765
+ iframe.src = `/iframe/${sessionId}`
766
+ } else {
767
+ // SW not active — fall back to blob: (no SW; CDN imports will fail)
768
+ console.warn(
769
+ '[ts-playground] SW unavailable, falling back to blob: iframe'
770
+ )
771
+ const blob = new Blob([iframeDoc], { type: 'text/html' })
772
+ const blobUrl = URL.createObjectURL(blob)
773
+ iframe.dataset.blobUrl = blobUrl
774
+ iframe.src = blobUrl
757
775
  }
758
- iframe.dataset.blobUrl = blobUrl
759
- iframe.src = blobUrl
760
776
  } catch (e: any) {
761
777
  this.log(`Error: ${e.message}`)
762
778
  this.parts.statusBar.textContent = 'Error'