@mojir/lits 2.3.1 → 2.4.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.
- package/README.md +18 -22
- package/dist/bundler.esm.js +2 -0
- package/dist/bundler.esm.js.map +1 -0
- package/dist/bundler.js +2 -0
- package/dist/bundler.js.map +1 -0
- package/dist/cli/cli/src/js-interop/Cli/Fs/index.d.ts +2 -2
- package/dist/cli/cli/src/js-interop/Cli/Proc/index.d.ts +2 -2
- package/dist/cli/cli/src/js-interop/Cli/index.d.ts +2 -3
- package/dist/cli/cli.js +2642 -2313
- package/dist/cli/reference/api.d.ts +3 -3
- package/dist/cli/reference/examples.d.ts +2 -2
- package/dist/cli/reference/index.d.ts +0 -1
- package/dist/cli/src/Lits/Lits.d.ts +6 -7
- package/dist/cli/src/builtin/index.d.ts +1 -1
- package/dist/cli/src/builtin/specialExpressionTypes.d.ts +15 -15
- package/dist/cli/src/builtin/specialExpressions/import.d.ts +6 -0
- package/dist/cli/src/bundler/index.d.ts +9 -0
- package/dist/cli/src/bundler/interface.d.ts +15 -0
- package/dist/cli/src/bundler.d.ts +3 -0
- package/dist/cli/src/evaluator/ContextStack.d.ts +10 -4
- package/dist/cli/src/index.d.ts +2 -0
- package/dist/cli/src/js-interop/Cli/Fs/index.d.ts +2 -2
- package/dist/cli/src/js-interop/Cli/Proc/index.d.ts +2 -2
- package/dist/cli/src/js-interop/Cli/index.d.ts +2 -3
- package/dist/cli/src/parser/ParserContext.d.ts +1 -1
- package/dist/cli/src/parser/getPrecedence.d.ts +3 -0
- package/dist/cli/src/parser/index.d.ts +2 -0
- package/dist/cli/src/parser/subParsers/parseExpression.d.ts +5 -0
- package/dist/cli/src/parser/types.d.ts +0 -3
- package/dist/cli/src/tokenizer/reservedNames.d.ts +0 -1
- package/dist/full.esm.js +1 -1
- package/dist/full.esm.js.map +1 -1
- package/dist/full.js +1 -1
- package/dist/full.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lits.iife.js +1 -1
- package/dist/lits.iife.js.map +1 -1
- package/dist/modules/assert.esm.js +1 -1
- package/dist/modules/assert.esm.js.map +1 -1
- package/dist/modules/assert.js +1 -1
- package/dist/modules/assert.js.map +1 -1
- package/dist/modules/bitwise.esm.js +1 -1
- package/dist/modules/bitwise.esm.js.map +1 -1
- package/dist/modules/bitwise.js +1 -1
- package/dist/modules/bitwise.js.map +1 -1
- package/dist/modules/cli/src/js-interop/Cli/Fs/index.d.ts +2 -2
- package/dist/modules/cli/src/js-interop/Cli/Proc/index.d.ts +2 -2
- package/dist/modules/cli/src/js-interop/Cli/index.d.ts +2 -3
- package/dist/modules/collection.esm.js +1 -1
- package/dist/modules/collection.esm.js.map +1 -1
- package/dist/modules/collection.js +1 -1
- package/dist/modules/collection.js.map +1 -1
- package/dist/modules/functional.esm.js +1 -1
- package/dist/modules/functional.esm.js.map +1 -1
- package/dist/modules/functional.js +1 -1
- package/dist/modules/functional.js.map +1 -1
- package/dist/modules/grid.esm.js +1 -1
- package/dist/modules/grid.esm.js.map +1 -1
- package/dist/modules/grid.js +1 -1
- package/dist/modules/grid.js.map +1 -1
- package/dist/modules/linear-algebra.esm.js +1 -1
- package/dist/modules/linear-algebra.esm.js.map +1 -1
- package/dist/modules/linear-algebra.js +1 -1
- package/dist/modules/linear-algebra.js.map +1 -1
- package/dist/modules/math.esm.js +1 -1
- package/dist/modules/math.esm.js.map +1 -1
- package/dist/modules/math.js +1 -1
- package/dist/modules/math.js.map +1 -1
- package/dist/modules/matrix.esm.js +1 -1
- package/dist/modules/matrix.esm.js.map +1 -1
- package/dist/modules/matrix.js +1 -1
- package/dist/modules/matrix.js.map +1 -1
- package/dist/modules/number-theory.esm.js +1 -1
- package/dist/modules/number-theory.esm.js.map +1 -1
- package/dist/modules/number-theory.js +1 -1
- package/dist/modules/number-theory.js.map +1 -1
- package/dist/modules/random.esm.js +1 -1
- package/dist/modules/random.esm.js.map +1 -1
- package/dist/modules/random.js +1 -1
- package/dist/modules/random.js.map +1 -1
- package/dist/modules/reference/api.d.ts +3 -3
- package/dist/modules/reference/index.d.ts +0 -1
- package/dist/modules/sequence.esm.js +1 -1
- package/dist/modules/sequence.esm.js.map +1 -1
- package/dist/modules/sequence.js +1 -1
- package/dist/modules/sequence.js.map +1 -1
- package/dist/modules/src/Lits/Lits.d.ts +6 -7
- package/dist/modules/src/builtin/index.d.ts +1 -1
- package/dist/modules/src/builtin/specialExpressionTypes.d.ts +15 -15
- package/dist/modules/src/builtin/specialExpressions/import.d.ts +6 -0
- package/dist/modules/src/bundler/index.d.ts +9 -0
- package/dist/modules/src/bundler/interface.d.ts +15 -0
- package/dist/modules/src/bundler.d.ts +3 -0
- package/dist/modules/src/evaluator/ContextStack.d.ts +10 -4
- package/dist/modules/src/index.d.ts +2 -0
- package/dist/modules/src/parser/ParserContext.d.ts +1 -1
- package/dist/modules/src/parser/getPrecedence.d.ts +3 -0
- package/dist/modules/src/parser/index.d.ts +2 -0
- package/dist/modules/src/parser/subParsers/parseExpression.d.ts +5 -0
- package/dist/modules/src/parser/types.d.ts +0 -3
- package/dist/modules/src/tokenizer/reservedNames.d.ts +0 -1
- package/dist/modules/string.esm.js +1 -1
- package/dist/modules/string.esm.js.map +1 -1
- package/dist/modules/string.js +1 -1
- package/dist/modules/string.js.map +1 -1
- package/dist/modules/vector.esm.js +1 -1
- package/dist/modules/vector.esm.js.map +1 -1
- package/dist/modules/vector.js +1 -1
- package/dist/modules/vector.js.map +1 -1
- package/dist/reference/api.d.ts +3 -3
- package/dist/reference/index.d.ts +0 -1
- package/dist/src/Lits/Lits.d.ts +6 -7
- package/dist/src/builtin/index.d.ts +1 -1
- package/dist/src/builtin/specialExpressionTypes.d.ts +15 -15
- package/dist/src/builtin/specialExpressions/import.d.ts +6 -0
- package/dist/src/bundler/index.d.ts +9 -0
- package/dist/src/bundler/interface.d.ts +15 -0
- package/dist/src/bundler.d.ts +3 -0
- package/dist/src/evaluator/ContextStack.d.ts +10 -4
- package/dist/src/index.d.ts +2 -0
- package/dist/src/parser/ParserContext.d.ts +1 -1
- package/dist/src/parser/getPrecedence.d.ts +3 -0
- package/dist/src/parser/index.d.ts +2 -0
- package/dist/src/parser/subParsers/parseExpression.d.ts +5 -0
- package/dist/src/parser/types.d.ts +0 -3
- package/dist/src/tokenizer/reservedNames.d.ts +0 -1
- package/dist/testFramework.esm.js +1 -1
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +1 -1
- package/dist/testFramework.js.map +1 -1
- package/package.json +6 -1
- package/dist/cli/cli/src/js-interop/utils.d.ts +0 -2
- package/dist/cli/src/builtin/specialExpressions/def.d.ts +0 -6
- package/dist/cli/src/js-interop/utils.d.ts +0 -2
- package/dist/cli/src/parser/subParsers/getPrecedence.d.ts +0 -3
- package/dist/modules/cli/src/js-interop/utils.d.ts +0 -2
- package/dist/modules/src/builtin/specialExpressions/def.d.ts +0 -6
- package/dist/modules/src/parser/subParsers/getPrecedence.d.ts +0 -3
- package/dist/src/builtin/specialExpressions/def.d.ts +0 -6
- package/dist/src/parser/subParsers/getPrecedence.d.ts +0 -3
package/README.md
CHANGED
|
@@ -164,8 +164,8 @@ A vector is simply a non-empty array containing only numbers. The `vec` module p
|
|
|
164
164
|
|
|
165
165
|
```lits
|
|
166
166
|
// Import vector and linear algebra modules
|
|
167
|
-
let vec = import(
|
|
168
|
-
let lin = import(
|
|
167
|
+
let vec = import(vector);
|
|
168
|
+
let lin = import(linear-algebra);
|
|
169
169
|
|
|
170
170
|
// Vectors are just number arrays
|
|
171
171
|
[1, 2, 3, 4, 5]; // This is a vector
|
|
@@ -218,7 +218,7 @@ A matrix is a 2D array where each row is a vector (non-empty array of numbers) a
|
|
|
218
218
|
|
|
219
219
|
```lits
|
|
220
220
|
// Import matrix module
|
|
221
|
-
let mat = import(
|
|
221
|
+
let mat = import(matrix);
|
|
222
222
|
|
|
223
223
|
// Matrices are 2D number arrays with consistent row lengths
|
|
224
224
|
[[1, 2], [3, 4]]; // This is a 2x2 matrix
|
|
@@ -1302,7 +1302,7 @@ Here's the complete precedence table, from highest to lowest:
|
|
|
1302
1302
|
3 > 2 && 1 < 2; // => true && true = true
|
|
1303
1303
|
|
|
1304
1304
|
// Pipe has very low precedence
|
|
1305
|
-
let vec = import(
|
|
1305
|
+
let vec = import(vector);
|
|
1306
1306
|
[1, 2, 3] |> map(_, inc) |> vec.sum; // Evaluates left to right
|
|
1307
1307
|
|
|
1308
1308
|
// Conditional has lowest precedence
|
|
@@ -1383,13 +1383,15 @@ let config = {
|
|
|
1383
1383
|
// back into working Lits values, preserving their functionality
|
|
1384
1384
|
```
|
|
1385
1385
|
|
|
1386
|
-
##
|
|
1386
|
+
## File Value
|
|
1387
|
+
|
|
1388
|
+
A Lits file evaluates to the value of its last expression:
|
|
1387
1389
|
|
|
1388
1390
|
```lits
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1391
|
+
let pi = 3.14159;
|
|
1392
|
+
let square = x -> x * x;
|
|
1393
|
+
// The file's value is the result of the last expression
|
|
1394
|
+
{pi: pi, square: square}
|
|
1393
1395
|
```
|
|
1394
1396
|
|
|
1395
1397
|
## Examples
|
|
@@ -1442,7 +1444,7 @@ let longWords = text
|
|
|
1442
1444
|
### Data Transformation
|
|
1443
1445
|
|
|
1444
1446
|
```lits
|
|
1445
|
-
let su = import(
|
|
1447
|
+
let su = import(sequence);
|
|
1446
1448
|
let users = [
|
|
1447
1449
|
{ name: "Alice", age: 30, department: "Engineering" },
|
|
1448
1450
|
{ name: "Bob", age: 25, department: "Marketing" },
|
|
@@ -1496,8 +1498,8 @@ import { matrixModule } from '@mojir/lits/modules/matrix';
|
|
|
1496
1498
|
|
|
1497
1499
|
const lits = new Lits({ modules: [vectorModule, matrixModule] });
|
|
1498
1500
|
|
|
1499
|
-
// Now you can use import(
|
|
1500
|
-
lits.run('let v = import(
|
|
1501
|
+
// Now you can use import(vector) and import(matrix) in Lits code
|
|
1502
|
+
lits.run('let v = import(vector); v.dot([1, 2, 3], [4, 5, 6])'); // => 32
|
|
1501
1503
|
```
|
|
1502
1504
|
|
|
1503
1505
|
### Using Lits in JavaScript
|
|
@@ -1527,10 +1529,8 @@ const result3 = lits.run('myAlert("Hello from Lits!")', {
|
|
|
1527
1529
|
}
|
|
1528
1530
|
});
|
|
1529
1531
|
|
|
1530
|
-
//
|
|
1531
|
-
const
|
|
1532
|
-
const ast = lits.parse(tokens);
|
|
1533
|
-
const result4 = lits.evaluate(ast, {});
|
|
1532
|
+
// Execute Lits code
|
|
1533
|
+
const result4 = lits.run('+(5, 3)');
|
|
1534
1534
|
```
|
|
1535
1535
|
|
|
1536
1536
|
### Lits Class Methods
|
|
@@ -1538,10 +1538,7 @@ const result4 = lits.evaluate(ast, {});
|
|
|
1538
1538
|
```typescript
|
|
1539
1539
|
interface Lits {
|
|
1540
1540
|
// Execute Lits code directly
|
|
1541
|
-
run(
|
|
1542
|
-
|
|
1543
|
-
// Get execution context after running code
|
|
1544
|
-
context(programOrAst: string | Ast, params?: ContextParams & FilePathParams): Context
|
|
1541
|
+
run(programOrBundle: string | LitsBundle, params?: ContextParams & FilePathParams): unknown
|
|
1545
1542
|
|
|
1546
1543
|
// Find undefined symbols in code
|
|
1547
1544
|
getUndefinedSymbols(programOrAst: string | Ast, params?: ContextParams): Set<string>
|
|
@@ -1549,7 +1546,6 @@ interface Lits {
|
|
|
1549
1546
|
// Parse pipeline
|
|
1550
1547
|
tokenize(program: string, params?: FilePathParams & MinifyParams): TokenStream
|
|
1551
1548
|
parse(tokenStream: TokenStream): Ast
|
|
1552
|
-
evaluate(ast: Ast, params: ContextParams): unknown
|
|
1553
1549
|
|
|
1554
1550
|
// Apply Lits function with JavaScript arguments
|
|
1555
1551
|
apply(fn: LitsFunction, fnParams: unknown[], params?: ContextParams): unknown
|
|
@@ -1569,7 +1565,7 @@ interface ContextParams {
|
|
|
1569
1565
|
contexts?: Context[] // Additional context layers
|
|
1570
1566
|
values?: Record<string, unknown> // JavaScript values to expose
|
|
1571
1567
|
jsFunctions?: Record<string, JsFunction> // JavaScript functions to expose
|
|
1572
|
-
globalModuleScope?: boolean //
|
|
1568
|
+
globalModuleScope?: boolean // Make top-level let bindings persist in global context
|
|
1573
1569
|
}
|
|
1574
1570
|
|
|
1575
1571
|
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":"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"}
|
package/dist/bundler.js
ADDED
|
@@ -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 {
|
|
2
|
-
export declare
|
|
1
|
+
import type { LitsModule } from '../../../../../src/builtin/modules/interface';
|
|
2
|
+
export declare function getFsModule(): LitsModule;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LitsModule } from '../../../../../src/builtin/modules/interface';
|
|
2
2
|
export declare function sys_cwd(): string;
|
|
3
|
-
export declare
|
|
3
|
+
export declare function getProcModule(): LitsModule;
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
};
|
|
1
|
+
import type { LitsModule } from '../../../../src/builtin/modules/interface';
|
|
2
|
+
export declare function getCliModules(): LitsModule[];
|