@slim-lang/core 1.2.2 → 1.2.4
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 +1 -1
- package/src/bin/config.default.json +2 -1
- package/src/bin/helpers.js +5 -2
- package/src/bin/spm.js +8 -8
- package/src/checker.js +1 -9
- package/src/compile.js +0 -2
- package/src/modulePaths.js +32 -14
- package/src/parser.js +0 -15
- package/src/transform.js +0 -15
package/package.json
CHANGED
package/src/bin/helpers.js
CHANGED
|
@@ -2,6 +2,9 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { rm, mkdir } from 'node:fs/promises';
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
+
import { projectPackagesDir } from "../modulePaths.js";
|
|
6
|
+
|
|
7
|
+
export { projectPackagesDir };
|
|
5
8
|
|
|
6
9
|
export const formatError = chalk.red.bold
|
|
7
10
|
export const formatSuccess = chalk.green.bold
|
|
@@ -30,10 +33,10 @@ export function error(...text) {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export function isPackageExists(name) {
|
|
33
|
-
return fs.existsSync(path.join(
|
|
36
|
+
return fs.existsSync(path.join(projectPackagesDir(), name))
|
|
34
37
|
}
|
|
35
38
|
export function getPackagePath(name) {
|
|
36
|
-
return path.join(
|
|
39
|
+
return path.join(projectPackagesDir(), name)
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
export async function deleteDirectory(dirPath) {
|
package/src/bin/spm.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { formatError, formatBold, formatItalic, formatSuccess, createFolder, createFile } from "./helpers.js"
|
|
5
5
|
import pkg from "../../package.json" with { type: "json" };
|
|
6
|
-
import { log, isPackageExists, rootPath, deleteDirectory, loading, delay } from "./helpers.js";
|
|
6
|
+
import { log, isPackageExists, rootPath, deleteDirectory, loading, delay, projectPackagesDir } from "./helpers.js";
|
|
7
7
|
|
|
8
8
|
import fs from "node:fs"
|
|
9
9
|
import path from "node:path"
|
|
@@ -27,7 +27,7 @@ function errlog(...args) {
|
|
|
27
27
|
console.log(formatError(...args))
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const packagesPath =
|
|
30
|
+
const packagesPath = projectPackagesDir()
|
|
31
31
|
|
|
32
32
|
function renderObject(obj, indent = 0) {
|
|
33
33
|
let output = "";
|
|
@@ -73,7 +73,7 @@ spm
|
|
|
73
73
|
spm
|
|
74
74
|
.command("list")
|
|
75
75
|
.action(() => {
|
|
76
|
-
const targetDir =
|
|
76
|
+
const targetDir = packagesPath
|
|
77
77
|
if (!fs.existsSync(targetDir)) {
|
|
78
78
|
spmlog("No packages installed (the packages/ directory does not exist)")
|
|
79
79
|
return
|
|
@@ -186,7 +186,7 @@ spm
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
const res = await deleteDirectory(path.join(
|
|
189
|
+
const res = await deleteDirectory(path.join(packagesPath, name))
|
|
190
190
|
|
|
191
191
|
if (res) {
|
|
192
192
|
removeLockEntry(name)
|
|
@@ -257,7 +257,7 @@ spm
|
|
|
257
257
|
await loading({
|
|
258
258
|
startMsg: `Creating path for ${name}`,
|
|
259
259
|
callback: async ({ fail, ok }) => {
|
|
260
|
-
const packagePath = path.join(
|
|
260
|
+
const packagePath = path.join(packagesPath, name)
|
|
261
261
|
|
|
262
262
|
if (isExists) return fail("Package is already exists")
|
|
263
263
|
else {
|
|
@@ -336,7 +336,7 @@ spm
|
|
|
336
336
|
const githubRepo = SPMContent.github.repo
|
|
337
337
|
const version = SPMContent.version
|
|
338
338
|
const description = SPMContent.description
|
|
339
|
-
const packagePath = path.join(
|
|
339
|
+
const packagePath = path.join(packagesPath, name)
|
|
340
340
|
|
|
341
341
|
if ("github" in SPMContent && "repo" in SPMContent.github) {
|
|
342
342
|
await loading({
|
|
@@ -445,7 +445,7 @@ spm
|
|
|
445
445
|
spmlog(formatError("No GitHub repository specified"));
|
|
446
446
|
}
|
|
447
447
|
} else {
|
|
448
|
-
spmlog(formatError(`No package founded:
|
|
448
|
+
spmlog(formatError(`No package founded: ${path.relative(process.cwd(), path.join(packagesPath, name)) || name}`));
|
|
449
449
|
}
|
|
450
450
|
});
|
|
451
451
|
|
package/src/checker.js
CHANGED
|
@@ -5,8 +5,6 @@ import { computeLineStarts, offsetToLineCol } from "./sourcemap.js"
|
|
|
5
5
|
|
|
6
6
|
const traverse = _traverse.default ?? _traverse
|
|
7
7
|
|
|
8
|
-
// Check annotations before lowering; report only definite type conflicts.
|
|
9
|
-
|
|
10
8
|
const NUMERIC = new Set(["int", "float", "number"])
|
|
11
9
|
const KNOWN = new Set([
|
|
12
10
|
"int", "float", "number", "string", "bool", "null", "undefined",
|
|
@@ -87,7 +85,6 @@ function normalize(label) {
|
|
|
87
85
|
return trimmed
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
// Resolve inherited fields so structs can cross module boundaries.
|
|
91
88
|
function resolveStruct(name, env, seen = new Set()) {
|
|
92
89
|
const definition = env.structs.get(name)
|
|
93
90
|
if (!definition) return null
|
|
@@ -135,7 +132,6 @@ export function createEnvironment() {
|
|
|
135
132
|
}
|
|
136
133
|
}
|
|
137
134
|
|
|
138
|
-
// Module declarations keyed by absolute source path.
|
|
139
135
|
const moduleTypes = new Map()
|
|
140
136
|
|
|
141
137
|
function signatureFor(name, path_, env) {
|
|
@@ -149,7 +145,7 @@ const BUILTIN_CLASSES = new Set(["Map", "Set", "Date", "Promise", "RegExp", "Err
|
|
|
149
145
|
function isOpen(label, env) {
|
|
150
146
|
const base = baseName(label)
|
|
151
147
|
if (!base) return true
|
|
152
|
-
|
|
148
|
+
|
|
153
149
|
if (env.customTypes.has(base)) return true
|
|
154
150
|
if (KNOWN.has(base) || BUILTIN_CLASSES.has(base)) return false
|
|
155
151
|
if (env.structs.has(base) || env.enums.has(base)) return false
|
|
@@ -217,7 +213,6 @@ function acceptsAtom(target, source, env) {
|
|
|
217
213
|
return false
|
|
218
214
|
}
|
|
219
215
|
|
|
220
|
-
// A union needs one compatible arm; array literals need every element to fit.
|
|
221
216
|
export function accepts(target, source, env, requireAll = false) {
|
|
222
217
|
if (!target || !source) return true
|
|
223
218
|
|
|
@@ -598,7 +593,6 @@ function checkStructLiteral(structName, node, path_, env, report) {
|
|
|
598
593
|
}
|
|
599
594
|
}
|
|
600
595
|
|
|
601
|
-
// Inspect lowered match expressions to preserve exhaustiveness checks.
|
|
602
596
|
function matchExpression(node) {
|
|
603
597
|
if (!t.isCallExpression(node) || node.arguments.length !== 1) return null
|
|
604
598
|
|
|
@@ -839,7 +833,6 @@ function buildModuleTypes(ast, env) {
|
|
|
839
833
|
return record
|
|
840
834
|
}
|
|
841
835
|
|
|
842
|
-
// Import known declarations; unresolved modules remain unchecked.
|
|
843
836
|
function seedImports(env, imports, wildcards) {
|
|
844
837
|
const merge = (record, name, local) => {
|
|
845
838
|
if (record.structs.has(name)) env.structs.set(local, record.structs.get(name))
|
|
@@ -850,7 +843,6 @@ function seedImports(env, imports, wildcards) {
|
|
|
850
843
|
|
|
851
844
|
const sources = new Set([...wildcards, ...imports.map(entry => entry.source)])
|
|
852
845
|
|
|
853
|
-
// Local declarations override explicit and transitive imports.
|
|
854
846
|
for (const source of sources) {
|
|
855
847
|
const record = moduleTypes.get(source)
|
|
856
848
|
if (!record) continue
|
package/src/compile.js
CHANGED
|
@@ -18,8 +18,6 @@ let check = true
|
|
|
18
18
|
let useStyle = "import"
|
|
19
19
|
|
|
20
20
|
function syncExternal() {
|
|
21
|
-
// The runtime ships inside the package; the compiled output goes to the
|
|
22
|
-
// project's own dist/ (so this works both locally and when installed).
|
|
23
21
|
const srcExternal = path.join(PACKAGE_ROOT, "src/external")
|
|
24
22
|
const distExternal = path.resolve("dist/external")
|
|
25
23
|
|
package/src/modulePaths.js
CHANGED
|
@@ -5,16 +5,24 @@ import { fileURLToPath } from "node:url"
|
|
|
5
5
|
|
|
6
6
|
const slimExtension = ".slim"
|
|
7
7
|
|
|
8
|
-
// Root of the installed toolchain package (…/src/modulePaths.js -> package root).
|
|
9
|
-
// Locally this equals the project root; when installed it points into
|
|
10
|
-
// node_modules/@slim-lang/core, where the shipped stdlib (@slim/*) lives.
|
|
11
8
|
export const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
let projectPackagesCache = null
|
|
11
|
+
export function projectPackagesDir() {
|
|
12
|
+
if (projectPackagesCache) return projectPackagesCache
|
|
13
|
+
|
|
14
|
+
let dir = "packages"
|
|
15
|
+
try {
|
|
16
|
+
const config = JSON.parse(fs.readFileSync(path.join(process.cwd(), "slimconfig.json"), "utf8"))
|
|
17
|
+
if (typeof config.packages === "string" && config.packages.trim()) dir = config.packages
|
|
18
|
+
} catch {}
|
|
19
|
+
|
|
20
|
+
projectPackagesCache = path.resolve(dir)
|
|
21
|
+
return projectPackagesCache
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
function packageRoots() {
|
|
17
|
-
const projectPackages =
|
|
25
|
+
const projectPackages = projectPackagesDir()
|
|
18
26
|
const shippedPackages = path.join(PACKAGE_ROOT, "packages")
|
|
19
27
|
|
|
20
28
|
return projectPackages === shippedPackages
|
|
@@ -41,16 +49,28 @@ export function getDistPath(slimFile) {
|
|
|
41
49
|
const abs = path.resolve(slimFile)
|
|
42
50
|
const srcRoot = path.resolve("src")
|
|
43
51
|
const projectRoot = path.resolve(".")
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
const shippedPackages = path.join(PACKAGE_ROOT, "packages")
|
|
53
|
+
const projectPackages = projectPackagesDir()
|
|
54
|
+
|
|
55
|
+
let relative
|
|
56
|
+
|
|
57
|
+
if (isWithin(shippedPackages, abs)) {
|
|
58
|
+
relative = path.join("packages", path.relative(shippedPackages, abs))
|
|
59
|
+
} else if (isWithin(projectPackages, abs)) {
|
|
60
|
+
relative = path.join(path.basename(projectPackages), path.relative(projectPackages, abs))
|
|
61
|
+
} else if (isWithin(srcRoot, abs)) {
|
|
62
|
+
relative = path.relative(srcRoot, abs)
|
|
63
|
+
} else if (isWithin(projectRoot, abs)) {
|
|
64
|
+
relative = path.relative(projectRoot, abs)
|
|
65
|
+
} else {
|
|
66
|
+
const stripped = path.relative(projectRoot, abs).split(path.sep).filter(seg => seg !== "..")
|
|
67
|
+
relative = stripped.length ? path.join(...stripped) : path.basename(abs)
|
|
68
|
+
}
|
|
47
69
|
|
|
48
70
|
return path.resolve("dist", relative.replace(/\.slim$/, ".js"))
|
|
49
71
|
}
|
|
50
72
|
|
|
51
73
|
export function resolveSlimSource(raw, fromFile) {
|
|
52
|
-
// Node builtins (e.g. "node:crypto", "fs", "path") are not Slim sources;
|
|
53
|
-
// leave them for the JS import to resolve untouched.
|
|
54
74
|
if (isBuiltin(raw)) return null
|
|
55
75
|
|
|
56
76
|
if (raw.startsWith("@")) {
|
|
@@ -67,8 +87,6 @@ export function resolveSlimSource(raw, fromFile) {
|
|
|
67
87
|
|
|
68
88
|
if (isNodeModule(raw)) return null
|
|
69
89
|
|
|
70
|
-
// Not found in any root: return the project-local path so errors point
|
|
71
|
-
// at the user's own packages/ directory.
|
|
72
90
|
return path.join(roots[0], packageName + slimExtension)
|
|
73
91
|
}
|
|
74
92
|
|
package/src/parser.js
CHANGED
|
@@ -43,7 +43,6 @@ function wordOperatorEdits(code) {
|
|
|
43
43
|
for (const token of tokenize(code)) {
|
|
44
44
|
if (token.type === "ws" || token.type === "newline" || token.type === "comment") continue
|
|
45
45
|
|
|
46
|
-
// Lower word operators only after an operand.
|
|
47
46
|
const replacement = token.type === "name" ? replacements[token.value] : undefined
|
|
48
47
|
if (replacement && endsExpression(prev)) {
|
|
49
48
|
edits.push({ start: token.start, end: token.end, replacement })
|
|
@@ -290,7 +289,6 @@ function functionEdits(text) {
|
|
|
290
289
|
})
|
|
291
290
|
}
|
|
292
291
|
|
|
293
|
-
// Cache tokens for whole-file and extracted-body scans.
|
|
294
292
|
const tokenCache = new Map()
|
|
295
293
|
|
|
296
294
|
function tokensFor(src) {
|
|
@@ -309,7 +307,6 @@ function tokensFor(src) {
|
|
|
309
307
|
return entry
|
|
310
308
|
}
|
|
311
309
|
|
|
312
|
-
// Match brackets by tokens so literals and comments do not affect depth.
|
|
313
310
|
function readBalanced(src, pos, open = "{", close = "}") {
|
|
314
311
|
const { tokens, starts } = tokensFor(src)
|
|
315
312
|
let index = starts.get(pos)
|
|
@@ -329,8 +326,6 @@ function readBalanced(src, pos, open = "{", close = "}") {
|
|
|
329
326
|
return -1
|
|
330
327
|
}
|
|
331
328
|
|
|
332
|
-
// Read balanced arguments after matching a construct head.
|
|
333
|
-
// Return type may be introduced by `->` or `:` (e.g. `func f(): number`).
|
|
334
329
|
const returnArrow = /\s*(?:->|:)\s*/y
|
|
335
330
|
|
|
336
331
|
function headMatcher(head, tail) {
|
|
@@ -462,7 +457,6 @@ function topLevelWhen(str) {
|
|
|
462
457
|
return -1
|
|
463
458
|
}
|
|
464
459
|
|
|
465
|
-
// Recursively lower nested match expressions without touching strings.
|
|
466
460
|
function lowerMatches(str) {
|
|
467
461
|
if (!str.includes("match")) return str
|
|
468
462
|
|
|
@@ -627,8 +621,6 @@ function structuralEdits(text) {
|
|
|
627
621
|
let rest = line.slice(idx + 1).trim()
|
|
628
622
|
if (!field) continue
|
|
629
623
|
|
|
630
|
-
// Optional fields may be written as `*key` or `key?`; normalize
|
|
631
|
-
// both to the `*key` form the struct runtime understands.
|
|
632
624
|
let optional = false
|
|
633
625
|
if (field.startsWith("*")) { optional = true; field = field.slice(1).trim() }
|
|
634
626
|
if (field.endsWith("?")) { optional = true; field = field.slice(0, -1).trim() }
|
|
@@ -688,8 +680,6 @@ function structuralEdits(text) {
|
|
|
688
680
|
const head = declarationHead.exec(src)
|
|
689
681
|
if (!head) return null
|
|
690
682
|
|
|
691
|
-
// `export default const X: T = ...` is not valid JS as a single
|
|
692
|
-
// statement; lower it to a typed declaration plus `export default X`.
|
|
693
683
|
const leadingDefault = src.slice(0, i).match(/export\s+default\s+$/)
|
|
694
684
|
const start = leadingDefault ? i - leadingDefault[0].length : i
|
|
695
685
|
|
|
@@ -708,10 +698,6 @@ function structuralEdits(text) {
|
|
|
708
698
|
},
|
|
709
699
|
({ keyword, name, type, expr, exprStart, defaultExport }) => {
|
|
710
700
|
const pattern = name.startsWith("{") || name.startsWith("[")
|
|
711
|
-
// Keep the declaration exported so the module wrapper leaves it at
|
|
712
|
-
// top level, then re-export the binding as default. Emitting a bare
|
|
713
|
-
// `const` plus `export default X` would trap the `const` in the
|
|
714
|
-
// module's try/catch, leaving the default export undefined.
|
|
715
701
|
const prefix = defaultExport ? "export " : ""
|
|
716
702
|
const head = pattern
|
|
717
703
|
? `${prefix}${keyword} ${name} = __typed_pattern__(`
|
|
@@ -730,7 +716,6 @@ function structuralEdits(text) {
|
|
|
730
716
|
/(\w[\w$.]*(?:\[.*?\])?)\s*(?:=>\s*([\w$]+))?\s*\n((?:\s*\|(?!\|)[^\n]+\n?)+)/g,
|
|
731
717
|
(match, source, alias, pipes) => {
|
|
732
718
|
const steps = [...pipes.matchAll(/\|\s*([\w$]+)\(([^)]*)\)/g)]
|
|
733
|
-
// Preserve non-pipe bars, such as multiline union types.
|
|
734
719
|
if (steps.length === 0) return match
|
|
735
720
|
|
|
736
721
|
const callbackMethods = new Set([
|
package/src/transform.js
CHANGED
|
@@ -28,9 +28,6 @@ function getTypeReferenceName(typeText) {
|
|
|
28
28
|
return withoutGeneric.split("::")[0]
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
// Builtin type names are always matched by label; they must never be resolved
|
|
32
|
-
// through a same-named binding in scope (e.g. a `const string` variable would
|
|
33
|
-
// otherwise shadow the primitive `string` type).
|
|
34
31
|
const BUILTIN_TYPE_NAMES = new Set([
|
|
35
32
|
"int", "float", "number", "string", "bool", "null", "undefined",
|
|
36
33
|
"object", "array", "function", "any", "element"
|
|
@@ -439,7 +436,6 @@ function getRuntimePath(sourceFile, entry) {
|
|
|
439
436
|
return relFixed.startsWith(".") ? relFixed : "./" + relFixed
|
|
440
437
|
}
|
|
441
438
|
|
|
442
|
-
// DOM globals select the full runtime; pure code uses the portable core.
|
|
443
439
|
const DOM_RUNTIME = new Set([
|
|
444
440
|
"htmlToVdom", "HTMLElement", "__html__",
|
|
445
441
|
"__flush_events__", "__bind_events__", "__lifecycle__",
|
|
@@ -460,13 +456,6 @@ function usesDom(ast) {
|
|
|
460
456
|
return found
|
|
461
457
|
}
|
|
462
458
|
|
|
463
|
-
// `use` mirrors `import`: `use { X } from Y` is a named import, `use * as X`
|
|
464
|
-
// a namespace import, and a bare `use X from Y` a default import — exactly like
|
|
465
|
-
// `import X from Y`. Named exports (including Slim's `export const`/`export func`)
|
|
466
|
-
// must therefore be brought in with braces: `use { X } from Y`.
|
|
467
|
-
//
|
|
468
|
-
// When `bareIsDefault` is false (the legacy `"uses": "named"` config style), a
|
|
469
|
-
// bare `use X from Y` instead lowers to a named import `import { X } from Y`.
|
|
470
459
|
function parseSpecifiers(name, bareIsDefault = true) {
|
|
471
460
|
const trimmed = name.trim()
|
|
472
461
|
|
|
@@ -485,7 +474,6 @@ function parseSpecifiers(name, bareIsDefault = true) {
|
|
|
485
474
|
})
|
|
486
475
|
}
|
|
487
476
|
|
|
488
|
-
// `use X as Y from Z` renames a named export (there is no `import X as Y`).
|
|
489
477
|
const aliasMatch = trimmed.match(/^([\w$]+)\s+as\s+([\w$]+)$/)
|
|
490
478
|
if (aliasMatch) {
|
|
491
479
|
return [t.importSpecifier(t.identifier(aliasMatch[2]), t.identifier(aliasMatch[1]))]
|
|
@@ -530,8 +518,6 @@ function formatSyntaxError(err, originalCode, sourceFile, mapped) {
|
|
|
530
518
|
}
|
|
531
519
|
|
|
532
520
|
export function transform(code, sourceFile = "input.ps", options = {}) {
|
|
533
|
-
// `"uses": "named"` (or "legacy") restores the old bare-import style where a
|
|
534
|
-
// bare `use X from Y` is a named import; the default mirrors `import`.
|
|
535
521
|
const bareIsDefault = options.uses !== "named" && options.uses !== "legacy"
|
|
536
522
|
const asyncFunctions = new Set()
|
|
537
523
|
const imports = new Map()
|
|
@@ -601,7 +587,6 @@ export function transform(code, sourceFile = "input.ps", options = {}) {
|
|
|
601
587
|
}
|
|
602
588
|
})
|
|
603
589
|
|
|
604
|
-
// Check annotations before lowering or writing output.
|
|
605
590
|
if (options.check !== false) {
|
|
606
591
|
const moduleImports = []
|
|
607
592
|
const moduleWildcards = []
|