@mojir/lits 2.3.1 → 2.4.1

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 (143) hide show
  1. package/README.md +52 -26
  2. package/dist/bundler.esm.js +2 -0
  3. package/dist/bundler.esm.js.map +1 -0
  4. package/dist/bundler.js +2 -0
  5. package/dist/bundler.js.map +1 -0
  6. package/dist/cli/cli/src/js-interop/Cli/Fs/index.d.ts +2 -2
  7. package/dist/cli/cli/src/js-interop/Cli/Proc/index.d.ts +2 -2
  8. package/dist/cli/cli/src/js-interop/Cli/index.d.ts +2 -3
  9. package/dist/cli/cli.js +2672 -2316
  10. package/dist/cli/reference/api.d.ts +3 -3
  11. package/dist/cli/reference/examples.d.ts +2 -2
  12. package/dist/cli/reference/index.d.ts +0 -1
  13. package/dist/cli/src/Lits/Lits.d.ts +6 -7
  14. package/dist/cli/src/builtin/index.d.ts +1 -1
  15. package/dist/cli/src/builtin/specialExpressionTypes.d.ts +15 -15
  16. package/dist/cli/src/builtin/specialExpressions/import.d.ts +6 -0
  17. package/dist/cli/src/bundler/index.d.ts +9 -0
  18. package/dist/cli/src/bundler/interface.d.ts +15 -0
  19. package/dist/cli/src/bundler.d.ts +3 -0
  20. package/dist/cli/src/evaluator/ContextStack.d.ts +10 -4
  21. package/dist/cli/src/index.d.ts +2 -0
  22. package/dist/cli/src/js-interop/Cli/Fs/index.d.ts +2 -2
  23. package/dist/cli/src/js-interop/Cli/Proc/index.d.ts +2 -2
  24. package/dist/cli/src/js-interop/Cli/index.d.ts +2 -3
  25. package/dist/cli/src/parser/ParserContext.d.ts +1 -1
  26. package/dist/cli/src/parser/getPrecedence.d.ts +3 -0
  27. package/dist/cli/src/parser/index.d.ts +2 -0
  28. package/dist/cli/src/parser/subParsers/parseExpression.d.ts +5 -0
  29. package/dist/cli/src/parser/types.d.ts +0 -3
  30. package/dist/cli/src/tokenizer/reservedNames.d.ts +0 -1
  31. package/dist/full.esm.js +1 -1
  32. package/dist/full.esm.js.map +1 -1
  33. package/dist/full.js +1 -1
  34. package/dist/full.js.map +1 -1
  35. package/dist/index.esm.js +1 -1
  36. package/dist/index.esm.js.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/lits.iife.js +1 -1
  40. package/dist/lits.iife.js.map +1 -1
  41. package/dist/modules/assert.esm.js +1 -1
  42. package/dist/modules/assert.esm.js.map +1 -1
  43. package/dist/modules/assert.js +1 -1
  44. package/dist/modules/assert.js.map +1 -1
  45. package/dist/modules/bitwise.esm.js +1 -1
  46. package/dist/modules/bitwise.esm.js.map +1 -1
  47. package/dist/modules/bitwise.js +1 -1
  48. package/dist/modules/bitwise.js.map +1 -1
  49. package/dist/modules/cli/src/js-interop/Cli/Fs/index.d.ts +2 -2
  50. package/dist/modules/cli/src/js-interop/Cli/Proc/index.d.ts +2 -2
  51. package/dist/modules/cli/src/js-interop/Cli/index.d.ts +2 -3
  52. package/dist/modules/collection.esm.js +1 -1
  53. package/dist/modules/collection.esm.js.map +1 -1
  54. package/dist/modules/collection.js +1 -1
  55. package/dist/modules/collection.js.map +1 -1
  56. package/dist/modules/functional.esm.js +1 -1
  57. package/dist/modules/functional.esm.js.map +1 -1
  58. package/dist/modules/functional.js +1 -1
  59. package/dist/modules/functional.js.map +1 -1
  60. package/dist/modules/grid.esm.js +1 -1
  61. package/dist/modules/grid.esm.js.map +1 -1
  62. package/dist/modules/grid.js +1 -1
  63. package/dist/modules/grid.js.map +1 -1
  64. package/dist/modules/linear-algebra.esm.js +1 -1
  65. package/dist/modules/linear-algebra.esm.js.map +1 -1
  66. package/dist/modules/linear-algebra.js +1 -1
  67. package/dist/modules/linear-algebra.js.map +1 -1
  68. package/dist/modules/math.esm.js +1 -1
  69. package/dist/modules/math.esm.js.map +1 -1
  70. package/dist/modules/math.js +1 -1
  71. package/dist/modules/math.js.map +1 -1
  72. package/dist/modules/matrix.esm.js +1 -1
  73. package/dist/modules/matrix.esm.js.map +1 -1
  74. package/dist/modules/matrix.js +1 -1
  75. package/dist/modules/matrix.js.map +1 -1
  76. package/dist/modules/number-theory.esm.js +1 -1
  77. package/dist/modules/number-theory.esm.js.map +1 -1
  78. package/dist/modules/number-theory.js +1 -1
  79. package/dist/modules/number-theory.js.map +1 -1
  80. package/dist/modules/random.esm.js +1 -1
  81. package/dist/modules/random.esm.js.map +1 -1
  82. package/dist/modules/random.js +1 -1
  83. package/dist/modules/random.js.map +1 -1
  84. package/dist/modules/reference/api.d.ts +3 -3
  85. package/dist/modules/reference/index.d.ts +0 -1
  86. package/dist/modules/sequence.esm.js +1 -1
  87. package/dist/modules/sequence.esm.js.map +1 -1
  88. package/dist/modules/sequence.js +1 -1
  89. package/dist/modules/sequence.js.map +1 -1
  90. package/dist/modules/src/Lits/Lits.d.ts +6 -7
  91. package/dist/modules/src/builtin/index.d.ts +1 -1
  92. package/dist/modules/src/builtin/specialExpressionTypes.d.ts +15 -15
  93. package/dist/modules/src/builtin/specialExpressions/import.d.ts +6 -0
  94. package/dist/modules/src/bundler/index.d.ts +9 -0
  95. package/dist/modules/src/bundler/interface.d.ts +15 -0
  96. package/dist/modules/src/bundler.d.ts +3 -0
  97. package/dist/modules/src/evaluator/ContextStack.d.ts +10 -4
  98. package/dist/modules/src/index.d.ts +2 -0
  99. package/dist/modules/src/parser/ParserContext.d.ts +1 -1
  100. package/dist/modules/src/parser/getPrecedence.d.ts +3 -0
  101. package/dist/modules/src/parser/index.d.ts +2 -0
  102. package/dist/modules/src/parser/subParsers/parseExpression.d.ts +5 -0
  103. package/dist/modules/src/parser/types.d.ts +0 -3
  104. package/dist/modules/src/tokenizer/reservedNames.d.ts +0 -1
  105. package/dist/modules/string.esm.js +1 -1
  106. package/dist/modules/string.esm.js.map +1 -1
  107. package/dist/modules/string.js +1 -1
  108. package/dist/modules/string.js.map +1 -1
  109. package/dist/modules/vector.esm.js +1 -1
  110. package/dist/modules/vector.esm.js.map +1 -1
  111. package/dist/modules/vector.js +1 -1
  112. package/dist/modules/vector.js.map +1 -1
  113. package/dist/reference/api.d.ts +3 -3
  114. package/dist/reference/index.d.ts +0 -1
  115. package/dist/src/Lits/Lits.d.ts +6 -7
  116. package/dist/src/builtin/index.d.ts +1 -1
  117. package/dist/src/builtin/specialExpressionTypes.d.ts +15 -15
  118. package/dist/src/builtin/specialExpressions/import.d.ts +6 -0
  119. package/dist/src/bundler/index.d.ts +9 -0
  120. package/dist/src/bundler/interface.d.ts +15 -0
  121. package/dist/src/bundler.d.ts +3 -0
  122. package/dist/src/evaluator/ContextStack.d.ts +10 -4
  123. package/dist/src/index.d.ts +2 -0
  124. package/dist/src/parser/ParserContext.d.ts +1 -1
  125. package/dist/src/parser/getPrecedence.d.ts +3 -0
  126. package/dist/src/parser/index.d.ts +2 -0
  127. package/dist/src/parser/subParsers/parseExpression.d.ts +5 -0
  128. package/dist/src/parser/types.d.ts +0 -3
  129. package/dist/src/tokenizer/reservedNames.d.ts +0 -1
  130. package/dist/testFramework.esm.js +1 -1
  131. package/dist/testFramework.esm.js.map +1 -1
  132. package/dist/testFramework.js +1 -1
  133. package/dist/testFramework.js.map +1 -1
  134. package/package.json +6 -1
  135. package/dist/cli/cli/src/js-interop/utils.d.ts +0 -2
  136. package/dist/cli/src/builtin/specialExpressions/def.d.ts +0 -6
  137. package/dist/cli/src/js-interop/utils.d.ts +0 -2
  138. package/dist/cli/src/parser/subParsers/getPrecedence.d.ts +0 -3
  139. package/dist/modules/cli/src/js-interop/utils.d.ts +0 -2
  140. package/dist/modules/src/builtin/specialExpressions/def.d.ts +0 -6
  141. package/dist/modules/src/parser/subParsers/getPrecedence.d.ts +0 -3
  142. package/dist/src/builtin/specialExpressions/def.d.ts +0 -6
  143. package/dist/src/parser/subParsers/getPrecedence.d.ts +0 -3
package/README.md CHANGED
@@ -41,17 +41,47 @@ npm install --global @mojir/lits
41
41
  $ lits
42
42
 
43
43
  # Evaluate Lits code directly
44
- $ lits -e "5 + 3"
45
- $ lits -e "[1, 2, 3, 4] filter odd? map inc"
44
+ $ lits eval "5 + 3"
45
+ $ lits eval "[1, 2, 3, 4] filter odd? map inc"
46
46
 
47
47
  # Run a Lits file
48
- $ lits -f script.lits
49
- $ lits -f examples/factorial.lits
48
+ $ lits run script.lits
49
+
50
+ # Bundle a multi-file project into a single .json file
51
+ $ lits bundle main.lits -o bundle.json
52
+
53
+ # Run a bundle
54
+ $ lits run-bundle bundle.json
55
+
56
+ # Run tests
57
+ $ lits test tests.test.lits
50
58
 
51
59
  # Get help
52
60
  $ lits --help
53
61
  ```
54
62
 
63
+ **Subcommands:**
64
+
65
+ | Subcommand | Description |
66
+ |---|---|
67
+ | `run <file>` | Run a `.lits` source file |
68
+ | `run-bundle <file>` | Run a `.json` bundle (with validation) |
69
+ | `eval <expression>` | Evaluate a Lits expression |
70
+ | `bundle <entry>` | Bundle a multi-file project into a single JSON file |
71
+ | `test <file>` | Run a `.test.lits` test file |
72
+ | `repl` | Start an interactive REPL (default when no subcommand) |
73
+
74
+ **Common options:**
75
+
76
+ | Option | Applies to | Description |
77
+ |---|---|---|
78
+ | `-c, --context=<json>` | `run`, `run-bundle`, `eval`, `repl` | Provide context as a JSON string |
79
+ | `-C, --context-file=<file>` | `run`, `run-bundle`, `eval`, `repl` | Provide context from a `.json` file |
80
+ | `-s, --silent` | `run`, `run-bundle`, `eval` | Suppress printing the result |
81
+ | `-o, --output=<file>` | `bundle` | Write bundle to file (default: stdout) |
82
+ | `--pattern=<regex>` | `test` | Only run tests matching pattern |
83
+ | `-l, --load=<file>` | `repl` | Preload a `.lits` file into the REPL |
84
+
55
85
  The REPL provides an interactive environment where you can experiment with Lits code, test functions, and explore the language features in real-time.
56
86
 
57
87
  ## Quick Start
@@ -164,8 +194,8 @@ A vector is simply a non-empty array containing only numbers. The `vec` module p
164
194
 
165
195
  ```lits
166
196
  // Import vector and linear algebra modules
167
- let vec = import("vector");
168
- let lin = import("linear-algebra");
197
+ let vec = import(vector);
198
+ let lin = import(linear-algebra);
169
199
 
170
200
  // Vectors are just number arrays
171
201
  [1, 2, 3, 4, 5]; // This is a vector
@@ -218,7 +248,7 @@ A matrix is a 2D array where each row is a vector (non-empty array of numbers) a
218
248
 
219
249
  ```lits
220
250
  // Import matrix module
221
- let mat = import("matrix");
251
+ let mat = import(matrix);
222
252
 
223
253
  // Matrices are 2D number arrays with consistent row lengths
224
254
  [[1, 2], [3, 4]]; // This is a 2x2 matrix
@@ -1302,7 +1332,7 @@ Here's the complete precedence table, from highest to lowest:
1302
1332
  3 > 2 && 1 < 2; // => true && true = true
1303
1333
 
1304
1334
  // Pipe has very low precedence
1305
- let vec = import("vector");
1335
+ let vec = import(vector);
1306
1336
  [1, 2, 3] |> map(_, inc) |> vec.sum; // Evaluates left to right
1307
1337
 
1308
1338
  // Conditional has lowest precedence
@@ -1383,13 +1413,15 @@ let config = {
1383
1413
  // back into working Lits values, preserving their functionality
1384
1414
  ```
1385
1415
 
1386
- ## Modules and Exports
1416
+ ## File Value
1417
+
1418
+ A Lits file evaluates to the value of its last expression:
1387
1419
 
1388
1420
  ```lits
1389
- // Export variables and functions
1390
- export let pi = 3.14159;
1391
- export let square = x -> x * x;
1392
- // Exported values become available to other modules
1421
+ let pi = 3.14159;
1422
+ let square = x -> x * x;
1423
+ // The file's value is the result of the last expression
1424
+ {pi: pi, square: square}
1393
1425
  ```
1394
1426
 
1395
1427
  ## Examples
@@ -1442,7 +1474,7 @@ let longWords = text
1442
1474
  ### Data Transformation
1443
1475
 
1444
1476
  ```lits
1445
- let su = import("sequence");
1477
+ let su = import(sequence);
1446
1478
  let users = [
1447
1479
  { name: "Alice", age: 30, department: "Engineering" },
1448
1480
  { name: "Bob", age: 25, department: "Marketing" },
@@ -1496,8 +1528,8 @@ import { matrixModule } from '@mojir/lits/modules/matrix';
1496
1528
 
1497
1529
  const lits = new Lits({ modules: [vectorModule, matrixModule] });
1498
1530
 
1499
- // Now you can use import("vector") and import("matrix") in Lits code
1500
- lits.run('let v = import("vector"); v.dot([1, 2, 3], [4, 5, 6])'); // => 32
1531
+ // Now you can use import(vector) and import(matrix) in Lits code
1532
+ lits.run('let v = import(vector); v.dot([1, 2, 3], [4, 5, 6])'); // => 32
1501
1533
  ```
1502
1534
 
1503
1535
  ### Using Lits in JavaScript
@@ -1527,10 +1559,8 @@ const result3 = lits.run('myAlert("Hello from Lits!")', {
1527
1559
  }
1528
1560
  });
1529
1561
 
1530
- // Parse and evaluate separately for better performance
1531
- const tokens = lits.tokenize('+(5, 3)');
1532
- const ast = lits.parse(tokens);
1533
- const result4 = lits.evaluate(ast, {});
1562
+ // Execute Lits code
1563
+ const result4 = lits.run('+(5, 3)');
1534
1564
  ```
1535
1565
 
1536
1566
  ### Lits Class Methods
@@ -1538,10 +1568,7 @@ const result4 = lits.evaluate(ast, {});
1538
1568
  ```typescript
1539
1569
  interface Lits {
1540
1570
  // Execute Lits code directly
1541
- run(program: string, params?: ContextParams & FilePathParams): unknown
1542
-
1543
- // Get execution context after running code
1544
- context(programOrAst: string | Ast, params?: ContextParams & FilePathParams): Context
1571
+ run(programOrBundle: string | LitsBundle, params?: ContextParams & FilePathParams): unknown
1545
1572
 
1546
1573
  // Find undefined symbols in code
1547
1574
  getUndefinedSymbols(programOrAst: string | Ast, params?: ContextParams): Set<string>
@@ -1549,7 +1576,6 @@ interface Lits {
1549
1576
  // Parse pipeline
1550
1577
  tokenize(program: string, params?: FilePathParams & MinifyParams): TokenStream
1551
1578
  parse(tokenStream: TokenStream): Ast
1552
- evaluate(ast: Ast, params: ContextParams): unknown
1553
1579
 
1554
1580
  // Apply Lits function with JavaScript arguments
1555
1581
  apply(fn: LitsFunction, fnParams: unknown[], params?: ContextParams): unknown
@@ -1569,7 +1595,7 @@ interface ContextParams {
1569
1595
  contexts?: Context[] // Additional context layers
1570
1596
  values?: Record<string, unknown> // JavaScript values to expose
1571
1597
  jsFunctions?: Record<string, JsFunction> // JavaScript functions to expose
1572
- globalModuleScope?: boolean // Module scoping behavior
1598
+ globalModuleScope?: boolean // Make top-level let bindings persist in global context
1573
1599
  }
1574
1600
 
1575
1601
  interface JsFunction {
@@ -0,0 +1,2 @@
1
+ import e from"node:fs";import t from"node:path";const n=new Set(["assert","grid","random","vector","linear-algebra","matrix","number-theory","math","functional","string","collection","sequence","bitwise"]),r=/import\(\s*"([^"]+)"\s*\)|import\(\s*'([^']+)'\s*\)/g;function o(o){const i=t.resolve(o),s=t.dirname(i),c=new Map,a=new Map,f=new Map;!function n(o,i){if(i.includes(o)){const e=[...i.slice(i.indexOf(o)),o];throw new Error(`Circular dependency detected: ${e.join(" → ")}`)}if(c.has(o))return;if(!e.existsSync(o))throw new Error(`File not found: ${o}`);const s=e.readFileSync(o,"utf-8");c.set(o,s);const a=new Set;f.set(o,a);const u=t.dirname(o);for(const e of s.matchAll(r)){const r=e[1]??e[2],s=t.resolve(u,r);a.add(s),n(s,[...i,o])}}(i,[]),function(e){const t=new Set;for(const r of c.keys()){if(r===i)continue;let o=l(r,e);for(;n.has(o)||t.has(o);)o=`_${o}`;t.add(o),a.set(r,o)}}(s);const u=function(e){const t=[],n=new Set,r=new Set;return function o(i){if(n.has(i))return;if(r.has(i))throw new Error(`Circular dependency detected during topological sort: ${i}`);r.add(i);const s=f.get(i);if(s)for(const e of s)o(e);r.delete(i),n.add(i),i!==e&&t.push(i)}(e),t}(i).map(e=>{const t=p(c.get(e),e);return[a.get(e),t]});return{program:p(c.get(i),i),fileModules:u};function l(e,n){const r=t.relative(n,e);if(!r.startsWith(".."))return d(r);return d(e.split(t.sep).slice(-2).join("/"))}function d(e){return e.endsWith(".lits")?e.slice(0,-5):e}function p(e,n){const o=t.dirname(n);return e.replace(r,(e,n,r)=>{const i=n??r,s=t.resolve(o,i),c=a.get(s);if(!c)throw new Error(`No canonical name for: ${s}`);return`import(${c})`})}}function i(e){return"object"==typeof e&&null!==e&&"string"==typeof e.program&&Array.isArray(e.fileModules)}export{o as bundle,i as isLitsBundle};
2
+ //# sourceMappingURL=bundler.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundler.esm.js","sources":["../src/bundler/index.ts","../src/bundler/interface.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { LitsBundle } from './interface'\n\nconst builtinModuleNames = new Set([\n 'assert',\n 'grid',\n 'random',\n 'vector',\n 'linear-algebra',\n 'matrix',\n 'number-theory',\n 'math',\n 'functional',\n 'string',\n 'collection',\n 'sequence',\n 'bitwise',\n])\n\n/**\n * Regex to match `import(\"...\")` or `import('...')` calls in Lits source.\n * Captures the file path inside the quotes.\n */\nconst fileImportPattern = /import\\(\\s*\"([^\"]+)\"\\s*\\)|import\\(\\s*'([^']+)'\\s*\\)/g\n\n/**\n * Bundles a Lits entry file and all its file imports into a LitsBundle.\n *\n * Resolves all `import(\"./path/to/file.lits\")` calls recursively,\n * deduplicates, detects circular dependencies, topologically sorts,\n * and rewrites file imports to bare symbol imports.\n */\nexport function bundle(entryPath: string): LitsBundle {\n const absoluteEntryPath = path.resolve(entryPath)\n const entryDir = path.dirname(absoluteEntryPath)\n\n // Map from absolute file path → source code\n const fileSources = new Map<string, string>()\n // Map from absolute file path → canonical module name\n const canonicalNames = new Map<string, string>()\n // Adjacency list: file → set of files it imports\n const dependencies = new Map<string, Set<string>>()\n\n // Phase 1: Resolve all file imports recursively\n resolveFile(absoluteEntryPath, [])\n\n // Phase 2: Build canonical names\n buildCanonicalNames(entryDir)\n\n // Phase 3: Topological sort (exclude entry file — it becomes the program)\n const sorted = topologicalSort(absoluteEntryPath)\n\n // Phase 4: Rewrite imports and build bundle\n const fileModules: [string, string][] = sorted.map((filePath) => {\n const source = fileSources.get(filePath)!\n const rewritten = rewriteImports(source, filePath)\n return [canonicalNames.get(filePath)!, rewritten]\n })\n\n const entrySource = fileSources.get(absoluteEntryPath)!\n const program = rewriteImports(entrySource, absoluteEntryPath)\n\n return { program, fileModules }\n\n // --- Helper functions (closures over the maps above) ---\n\n function resolveFile(absoluteFilePath: string, stack: string[]): void {\n // Circular dependency detection\n if (stack.includes(absoluteFilePath)) {\n const cycle = [...stack.slice(stack.indexOf(absoluteFilePath)), absoluteFilePath]\n throw new Error(`Circular dependency detected: ${cycle.join(' → ')}`)\n }\n\n // Already resolved (deduplication)\n if (fileSources.has(absoluteFilePath)) {\n return\n }\n\n if (!fs.existsSync(absoluteFilePath)) {\n throw new Error(`File not found: ${absoluteFilePath}`)\n }\n\n const source = fs.readFileSync(absoluteFilePath, 'utf-8')\n fileSources.set(absoluteFilePath, source)\n\n const deps = new Set<string>()\n dependencies.set(absoluteFilePath, deps)\n\n const dir = path.dirname(absoluteFilePath)\n\n for (const match of source.matchAll(fileImportPattern)) {\n const importPath = (match[1] ?? match[2])!\n const resolvedPath = path.resolve(dir, importPath)\n\n deps.add(resolvedPath)\n resolveFile(resolvedPath, [...stack, absoluteFilePath])\n }\n }\n\n function buildCanonicalNames(entryDirectory: string): void {\n const usedNames = new Set<string>()\n\n for (const absoluteFilePath of fileSources.keys()) {\n // Skip the entry file — it doesn't need a canonical name\n if (absoluteFilePath === absoluteEntryPath) {\n continue\n }\n\n let name = deriveCanonicalName(absoluteFilePath, entryDirectory)\n\n // Resolve collisions with builtin modules\n while (builtinModuleNames.has(name) || usedNames.has(name)) {\n name = `_${name}`\n }\n\n usedNames.add(name)\n canonicalNames.set(absoluteFilePath, name)\n }\n }\n\n function deriveCanonicalName(absoluteFilePath: string, entryDirectory: string): string {\n const relativePath = path.relative(entryDirectory, absoluteFilePath)\n\n // If the file is under the entry directory (no leading ..)\n if (!relativePath.startsWith('..')) {\n // Strip .lits extension\n return stripExtension(relativePath)\n }\n\n // File is outside the entry directory — use last N path segments\n const segments = absoluteFilePath.split(path.sep)\n // Use last 2 segments (directory + filename) for readability\n const fallback = segments.slice(-2).join('/')\n return stripExtension(fallback)\n }\n\n function stripExtension(filePath: string): string {\n if (filePath.endsWith('.lits')) {\n return filePath.slice(0, -5)\n }\n return filePath\n }\n\n function topologicalSort(entryFilePath: string): string[] {\n const result: string[] = []\n const visited = new Set<string>()\n const visiting = new Set<string>()\n\n function visit(filePath: string): void {\n if (visited.has(filePath)) {\n return\n }\n /* v8 ignore next 3 */\n if (visiting.has(filePath))\n throw new Error(`Circular dependency detected during topological sort: ${filePath}`)\n\n visiting.add(filePath)\n\n const deps = dependencies.get(filePath)\n if (deps) {\n for (const dep of deps) {\n visit(dep)\n }\n }\n\n visiting.delete(filePath)\n visited.add(filePath)\n\n // Don't add the entry file — it becomes the program\n if (filePath !== entryFilePath) {\n result.push(filePath)\n }\n }\n\n // Start from entry file to ensure all reachable files are visited\n visit(entryFilePath)\n\n return result\n }\n\n function rewriteImports(source: string, sourceFilePath: string): string {\n const dir = path.dirname(sourceFilePath)\n\n return source.replace(fileImportPattern, (_fullMatch, doubleQuoted: string | undefined, singleQuoted: string | undefined) => {\n const importPath = (doubleQuoted ?? singleQuoted)!\n const resolvedPath = path.resolve(dir, importPath)\n const canonicalName = canonicalNames.get(resolvedPath)\n\n /* v8 ignore next 3 */\n if (!canonicalName)\n throw new Error(`No canonical name for: ${resolvedPath}`)\n\n return `import(${canonicalName})`\n })\n }\n}\n","/**\n * A bundle produced by the bundler. Contains the main program source\n * with file imports rewritten to canonical module names, plus an ordered\n * array of file module sources keyed by canonical name.\n *\n * The bundle is pure JSON — fully serializable and portable\n * (e.g., build on a server, run in a browser).\n */\nexport interface LitsBundle {\n /** The main program source, with file imports rewritten to bare symbols. */\n program: string\n /** Ordered array of [canonicalName, source] pairs. Dependencies come before dependents. */\n fileModules: [string, string][]\n}\n\nexport function isLitsBundle(value: unknown): value is LitsBundle {\n return (\n typeof value === 'object'\n && value !== null\n && typeof (value as LitsBundle).program === 'string'\n && Array.isArray((value as LitsBundle).fileModules)\n )\n}\n"],"names":["builtinModuleNames","Set","fileImportPattern","bundle","entryPath","absoluteEntryPath","path","resolve","entryDir","dirname","fileSources","Map","canonicalNames","dependencies","resolveFile","absoluteFilePath","stack","includes","cycle","slice","indexOf","Error","join","has","fs","existsSync","source","readFileSync","set","deps","dir","match","matchAll","importPath","resolvedPath","add","entryDirectory","usedNames","keys","name","deriveCanonicalName","buildCanonicalNames","fileModules","entryFilePath","result","visited","visiting","visit","filePath","get","dep","delete","push","topologicalSort","map","rewritten","rewriteImports","program","relativePath","relative","startsWith","stripExtension","split","sep","endsWith","sourceFilePath","replace","_fullMatch","doubleQuoted","singleQuoted","canonicalName","isLitsBundle","value","Array","isArray"],"mappings":"gDAIA,MAAMA,EAAqB,IAAIC,IAAI,CACjC,SACA,OACA,SACA,SACA,iBACA,SACA,gBACA,OACA,aACA,SACA,aACA,WACA,YAOIC,EAAoB,uDASpB,SAAUC,EAAOC,GACrB,MAAMC,EAAoBC,EAAKC,QAAQH,GACjCI,EAAWF,EAAKG,QAAQJ,GAGxBK,EAAc,IAAIC,IAElBC,EAAiB,IAAID,IAErBE,EAAe,IAAIF,KAyBzB,SAASG,EAAYC,EAA0BC,GAE7C,GAAIA,EAAMC,SAASF,GAAmB,CACpC,MAAMG,EAAQ,IAAIF,EAAMG,MAAMH,EAAMI,QAAQL,IAAoBA,GAChE,MAAM,IAAIM,MAAM,iCAAiCH,EAAMI,KAAK,SAC7D,CAGD,GAAIZ,EAAYa,IAAIR,GAClB,OAGF,IAAKS,EAAGC,WAAWV,GACjB,MAAM,IAAIM,MAAM,mBAAmBN,KAGrC,MAAMW,EAASF,EAAGG,aAAaZ,EAAkB,SACjDL,EAAYkB,IAAIb,EAAkBW,GAElC,MAAMG,EAAO,IAAI5B,IACjBY,EAAae,IAAIb,EAAkBc,GAEnC,MAAMC,EAAMxB,EAAKG,QAAQM,GAEzB,IAAK,MAAMgB,KAASL,EAAOM,SAAS9B,GAAoB,CACtD,MAAM+B,EAAcF,EAAM,IAAMA,EAAM,GAChCG,EAAe5B,EAAKC,QAAQuB,EAAKG,GAEvCJ,EAAKM,IAAID,GACTpB,EAAYoB,EAAc,IAAIlB,EAAOD,GACtC,CACF,CArDDD,CAAYT,EAAmB,IAuD/B,SAA6B+B,GAC3B,MAAMC,EAAY,IAAIpC,IAEtB,IAAK,MAAMc,KAAoBL,EAAY4B,OAAQ,CAEjD,GAAIvB,IAAqBV,EACvB,SAGF,IAAIkC,EAAOC,EAAoBzB,EAAkBqB,GAGjD,KAAOpC,EAAmBuB,IAAIgB,IAASF,EAAUd,IAAIgB,IACnDA,EAAO,IAAIA,IAGbF,EAAUF,IAAII,GACd3B,EAAegB,IAAIb,EAAkBwB,EACtC,CACF,CAvEDE,CAAoBjC,GAGpB,MAGMkC,EA0FN,SAAyBC,GACvB,MAAMC,EAAmB,GACnBC,EAAU,IAAI5C,IACd6C,EAAW,IAAI7C,IA+BrB,OA7BA,SAAS8C,EAAMC,GACb,GAAIH,EAAQtB,IAAIyB,GACd,OAGF,GAAIF,EAASvB,IAAIyB,GACf,MAAM,IAAI3B,MAAM,yDAAyD2B,KAE3EF,EAASX,IAAIa,GAEb,MAAMnB,EAAOhB,EAAaoC,IAAID,GAC9B,GAAInB,EACF,IAAK,MAAMqB,KAAOrB,EAChBkB,EAAMG,GAIVJ,EAASK,OAAOH,GAChBH,EAAQV,IAAIa,GAGRA,IAAaL,GACfC,EAAOQ,KAAKJ,EAEf,CAGDD,CAAMJ,GAECC,CACR,CAhIcS,CAAgBhD,GAGgBiD,IAAKN,IAClD,MACMO,EAAYC,EADH9C,EAAYuC,IAAID,GACUA,GACzC,MAAO,CAACpC,EAAeqC,IAAID,GAAYO,KAMzC,MAAO,CAAEE,QAFOD,EADI9C,EAAYuC,IAAI5C,GACQA,GAE1BqC,eA0DlB,SAASF,EAAoBzB,EAA0BqB,GACrD,MAAMsB,EAAepD,EAAKqD,SAASvB,EAAgBrB,GAGnD,IAAK2C,EAAaE,WAAW,MAE3B,OAAOC,EAAeH,GAOxB,OAAOG,EAHU9C,EAAiB+C,MAAMxD,EAAKyD,KAEnB5C,OAAO,GAAGG,KAAK,KAE1C,CAED,SAASuC,EAAeb,GACtB,OAAIA,EAASgB,SAAS,SACbhB,EAAS7B,MAAM,GAAI,GAErB6B,CACR,CAuCD,SAASQ,EAAe9B,EAAgBuC,GACtC,MAAMnC,EAAMxB,EAAKG,QAAQwD,GAEzB,OAAOvC,EAAOwC,QAAQhE,EAAmB,CAACiE,EAAYC,EAAkCC,KACtF,MAAMpC,EAAcmC,GAAgBC,EAC9BnC,EAAe5B,EAAKC,QAAQuB,EAAKG,GACjCqC,EAAgB1D,EAAeqC,IAAIf,GAGzC,IAAKoC,EACH,MAAM,IAAIjD,MAAM,0BAA0Ba,KAE5C,MAAO,UAAUoC,MAEpB,CACH,CCrLM,SAAUC,EAAaC,GAC3B,MACmB,iBAAVA,GACM,OAAVA,GACyC,iBAAjCA,EAAqBf,SAC7BgB,MAAMC,QAASF,EAAqB9B,YAE3C"}
@@ -0,0 +1,2 @@
1
+ "use strict";var e=require("node:fs"),t=require("node:path");const n=new Set(["assert","grid","random","vector","linear-algebra","matrix","number-theory","math","functional","string","collection","sequence","bitwise"]),r=/import\(\s*"([^"]+)"\s*\)|import\(\s*'([^']+)'\s*\)/g;exports.bundle=function(o){const s=t.resolve(o),i=t.dirname(s),c=new Map,a=new Map,u=new Map;!function n(o,s){if(s.includes(o)){const e=[...s.slice(s.indexOf(o)),o];throw new Error(`Circular dependency detected: ${e.join(" → ")}`)}if(c.has(o))return;if(!e.existsSync(o))throw new Error(`File not found: ${o}`);const i=e.readFileSync(o,"utf-8");c.set(o,i);const a=new Set;u.set(o,a);const f=t.dirname(o);for(const e of i.matchAll(r)){const r=e[1]??e[2],i=t.resolve(f,r);a.add(i),n(i,[...s,o])}}(s,[]),function(e){const t=new Set;for(const r of c.keys()){if(r===s)continue;let o=l(r,e);for(;n.has(o)||t.has(o);)o=`_${o}`;t.add(o),a.set(r,o)}}(i);const f=function(e){const t=[],n=new Set,r=new Set;return function o(s){if(n.has(s))return;if(r.has(s))throw new Error(`Circular dependency detected during topological sort: ${s}`);r.add(s);const i=u.get(s);if(i)for(const e of i)o(e);r.delete(s),n.add(s),s!==e&&t.push(s)}(e),t}(s).map(e=>{const t=p(c.get(e),e);return[a.get(e),t]});return{program:p(c.get(s),s),fileModules:f};function l(e,n){const r=t.relative(n,e);if(!r.startsWith(".."))return d(r);return d(e.split(t.sep).slice(-2).join("/"))}function d(e){return e.endsWith(".lits")?e.slice(0,-5):e}function p(e,n){const o=t.dirname(n);return e.replace(r,(e,n,r)=>{const s=n??r,i=t.resolve(o,s),c=a.get(i);if(!c)throw new Error(`No canonical name for: ${i}`);return`import(${c})`})}},exports.isLitsBundle=function(e){return"object"==typeof e&&null!==e&&"string"==typeof e.program&&Array.isArray(e.fileModules)};
2
+ //# sourceMappingURL=bundler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundler.js","sources":["../src/bundler/index.ts","../src/bundler/interface.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { LitsBundle } from './interface'\n\nconst builtinModuleNames = new Set([\n 'assert',\n 'grid',\n 'random',\n 'vector',\n 'linear-algebra',\n 'matrix',\n 'number-theory',\n 'math',\n 'functional',\n 'string',\n 'collection',\n 'sequence',\n 'bitwise',\n])\n\n/**\n * Regex to match `import(\"...\")` or `import('...')` calls in Lits source.\n * Captures the file path inside the quotes.\n */\nconst fileImportPattern = /import\\(\\s*\"([^\"]+)\"\\s*\\)|import\\(\\s*'([^']+)'\\s*\\)/g\n\n/**\n * Bundles a Lits entry file and all its file imports into a LitsBundle.\n *\n * Resolves all `import(\"./path/to/file.lits\")` calls recursively,\n * deduplicates, detects circular dependencies, topologically sorts,\n * and rewrites file imports to bare symbol imports.\n */\nexport function bundle(entryPath: string): LitsBundle {\n const absoluteEntryPath = path.resolve(entryPath)\n const entryDir = path.dirname(absoluteEntryPath)\n\n // Map from absolute file path → source code\n const fileSources = new Map<string, string>()\n // Map from absolute file path → canonical module name\n const canonicalNames = new Map<string, string>()\n // Adjacency list: file → set of files it imports\n const dependencies = new Map<string, Set<string>>()\n\n // Phase 1: Resolve all file imports recursively\n resolveFile(absoluteEntryPath, [])\n\n // Phase 2: Build canonical names\n buildCanonicalNames(entryDir)\n\n // Phase 3: Topological sort (exclude entry file — it becomes the program)\n const sorted = topologicalSort(absoluteEntryPath)\n\n // Phase 4: Rewrite imports and build bundle\n const fileModules: [string, string][] = sorted.map((filePath) => {\n const source = fileSources.get(filePath)!\n const rewritten = rewriteImports(source, filePath)\n return [canonicalNames.get(filePath)!, rewritten]\n })\n\n const entrySource = fileSources.get(absoluteEntryPath)!\n const program = rewriteImports(entrySource, absoluteEntryPath)\n\n return { program, fileModules }\n\n // --- Helper functions (closures over the maps above) ---\n\n function resolveFile(absoluteFilePath: string, stack: string[]): void {\n // Circular dependency detection\n if (stack.includes(absoluteFilePath)) {\n const cycle = [...stack.slice(stack.indexOf(absoluteFilePath)), absoluteFilePath]\n throw new Error(`Circular dependency detected: ${cycle.join(' → ')}`)\n }\n\n // Already resolved (deduplication)\n if (fileSources.has(absoluteFilePath)) {\n return\n }\n\n if (!fs.existsSync(absoluteFilePath)) {\n throw new Error(`File not found: ${absoluteFilePath}`)\n }\n\n const source = fs.readFileSync(absoluteFilePath, 'utf-8')\n fileSources.set(absoluteFilePath, source)\n\n const deps = new Set<string>()\n dependencies.set(absoluteFilePath, deps)\n\n const dir = path.dirname(absoluteFilePath)\n\n for (const match of source.matchAll(fileImportPattern)) {\n const importPath = (match[1] ?? match[2])!\n const resolvedPath = path.resolve(dir, importPath)\n\n deps.add(resolvedPath)\n resolveFile(resolvedPath, [...stack, absoluteFilePath])\n }\n }\n\n function buildCanonicalNames(entryDirectory: string): void {\n const usedNames = new Set<string>()\n\n for (const absoluteFilePath of fileSources.keys()) {\n // Skip the entry file — it doesn't need a canonical name\n if (absoluteFilePath === absoluteEntryPath) {\n continue\n }\n\n let name = deriveCanonicalName(absoluteFilePath, entryDirectory)\n\n // Resolve collisions with builtin modules\n while (builtinModuleNames.has(name) || usedNames.has(name)) {\n name = `_${name}`\n }\n\n usedNames.add(name)\n canonicalNames.set(absoluteFilePath, name)\n }\n }\n\n function deriveCanonicalName(absoluteFilePath: string, entryDirectory: string): string {\n const relativePath = path.relative(entryDirectory, absoluteFilePath)\n\n // If the file is under the entry directory (no leading ..)\n if (!relativePath.startsWith('..')) {\n // Strip .lits extension\n return stripExtension(relativePath)\n }\n\n // File is outside the entry directory — use last N path segments\n const segments = absoluteFilePath.split(path.sep)\n // Use last 2 segments (directory + filename) for readability\n const fallback = segments.slice(-2).join('/')\n return stripExtension(fallback)\n }\n\n function stripExtension(filePath: string): string {\n if (filePath.endsWith('.lits')) {\n return filePath.slice(0, -5)\n }\n return filePath\n }\n\n function topologicalSort(entryFilePath: string): string[] {\n const result: string[] = []\n const visited = new Set<string>()\n const visiting = new Set<string>()\n\n function visit(filePath: string): void {\n if (visited.has(filePath)) {\n return\n }\n /* v8 ignore next 3 */\n if (visiting.has(filePath))\n throw new Error(`Circular dependency detected during topological sort: ${filePath}`)\n\n visiting.add(filePath)\n\n const deps = dependencies.get(filePath)\n if (deps) {\n for (const dep of deps) {\n visit(dep)\n }\n }\n\n visiting.delete(filePath)\n visited.add(filePath)\n\n // Don't add the entry file — it becomes the program\n if (filePath !== entryFilePath) {\n result.push(filePath)\n }\n }\n\n // Start from entry file to ensure all reachable files are visited\n visit(entryFilePath)\n\n return result\n }\n\n function rewriteImports(source: string, sourceFilePath: string): string {\n const dir = path.dirname(sourceFilePath)\n\n return source.replace(fileImportPattern, (_fullMatch, doubleQuoted: string | undefined, singleQuoted: string | undefined) => {\n const importPath = (doubleQuoted ?? singleQuoted)!\n const resolvedPath = path.resolve(dir, importPath)\n const canonicalName = canonicalNames.get(resolvedPath)\n\n /* v8 ignore next 3 */\n if (!canonicalName)\n throw new Error(`No canonical name for: ${resolvedPath}`)\n\n return `import(${canonicalName})`\n })\n }\n}\n","/**\n * A bundle produced by the bundler. Contains the main program source\n * with file imports rewritten to canonical module names, plus an ordered\n * array of file module sources keyed by canonical name.\n *\n * The bundle is pure JSON — fully serializable and portable\n * (e.g., build on a server, run in a browser).\n */\nexport interface LitsBundle {\n /** The main program source, with file imports rewritten to bare symbols. */\n program: string\n /** Ordered array of [canonicalName, source] pairs. Dependencies come before dependents. */\n fileModules: [string, string][]\n}\n\nexport function isLitsBundle(value: unknown): value is LitsBundle {\n return (\n typeof value === 'object'\n && value !== null\n && typeof (value as LitsBundle).program === 'string'\n && Array.isArray((value as LitsBundle).fileModules)\n )\n}\n"],"names":["builtinModuleNames","Set","fileImportPattern","entryPath","absoluteEntryPath","path","resolve","entryDir","dirname","fileSources","Map","canonicalNames","dependencies","resolveFile","absoluteFilePath","stack","includes","cycle","slice","indexOf","Error","join","has","fs","existsSync","source","readFileSync","set","deps","dir","match","matchAll","importPath","resolvedPath","add","entryDirectory","usedNames","keys","name","deriveCanonicalName","buildCanonicalNames","fileModules","entryFilePath","result","visited","visiting","visit","filePath","get","dep","delete","push","topologicalSort","map","rewritten","rewriteImports","program","relativePath","relative","startsWith","stripExtension","split","sep","endsWith","sourceFilePath","replace","_fullMatch","doubleQuoted","singleQuoted","canonicalName","value","Array","isArray"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import type { GetFsModule } from '../../utils';
2
- export declare const getFsModule: GetFsModule;
1
+ import type { LitsModule } from '../../../../../src/builtin/modules/interface';
2
+ export declare function getFsModule(): LitsModule;
@@ -1,3 +1,3 @@
1
- import type { GetFsModule } from '../../utils';
1
+ import type { LitsModule } from '../../../../../src/builtin/modules/interface';
2
2
  export declare function sys_cwd(): string;
3
- export declare const getProcModule: GetFsModule;
3
+ export declare function getProcModule(): LitsModule;
@@ -1,3 +1,2 @@
1
- export declare function getCliModule(): {
2
- [x: string]: unknown;
3
- };
1
+ import type { LitsModule } from '../../../../src/builtin/modules/interface';
2
+ export declare function getCliModules(): LitsModule[];