@slim-lang/core 1.2.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 +666 -0
- package/package.json +55 -0
- package/packages/slim/.spm +7 -0
- package/packages/slim/converters/main.slim +106 -0
- package/packages/slim/helpers/array.slim +25 -0
- package/packages/slim/helpers/path.slim +3 -0
- package/packages/slim/helpers/request.slim +102 -0
- package/packages/slim/helpers/string.slim +27 -0
- package/packages/slim/main.slim +42 -0
- package/packages/slim/parse/main.slim +25 -0
- package/packages/slim/server/main.slim +423 -0
- package/packages/slim/time/main.slim +66 -0
- package/packages/slim/types/common.slim +6 -0
- package/packages/slim/types/formats.slim +23 -0
- package/packages/slim/types/hash.slim +6 -0
- package/packages/slim/types/mails.slim +3 -0
- package/packages/slim/types/numerical.slim +9 -0
- package/packages/slim/types/time.slim +3 -0
- package/run-dev-slim.js +133 -0
- package/run-slim.js +20 -0
- package/src/bin/api/github_auth.js +89 -0
- package/src/bin/api/github_get.js +139 -0
- package/src/bin/api/github_req.js +455 -0
- package/src/bin/api/lock.js +37 -0
- package/src/bin/api/spm.js +103 -0
- package/src/bin/api/storage.js +30 -0
- package/src/bin/cli.js +404 -0
- package/src/bin/config.default.json +5 -0
- package/src/bin/helpers.js +147 -0
- package/src/bin/parsers/spm.js +174 -0
- package/src/bin/spm.js +519 -0
- package/src/checker.js +926 -0
- package/src/compile.js +230 -0
- package/src/external/classErrors.js +202 -0
- package/src/external/client.js +38 -0
- package/src/external/core.js +861 -0
- package/src/external/defaults.js +25 -0
- package/src/external/helpers.js +541 -0
- package/src/external/slim-globals.d.ts +65 -0
- package/src/external/types.js +38 -0
- package/src/format.js +81 -0
- package/src/handlers/errorHandler.js +43 -0
- package/src/handlers/parser/components.js +250 -0
- package/src/handlers/parserHandler.js +793 -0
- package/src/jsdoc.js +273 -0
- package/src/lexer.js +174 -0
- package/src/modulePaths.js +74 -0
- package/src/parser.js +818 -0
- package/src/repl.js +32 -0
- package/src/sourcemap.js +0 -0
- package/src/test-runner.js +62 -0
- package/src/transform.js +765 -0
package/src/compile.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import "./handlers/errorHandler.js"
|
|
2
|
+
import fs from "fs"
|
|
3
|
+
import path from "path"
|
|
4
|
+
import { transform } from "./transform.js"
|
|
5
|
+
|
|
6
|
+
import { readFile } from 'fs/promises';
|
|
7
|
+
import { Debug } from "./external/core.js";
|
|
8
|
+
import { stripComments } from "./parser.js";
|
|
9
|
+
import { UseError } from "./external/classErrors.js";
|
|
10
|
+
import { getDistPath, resolveSlimSource } from "./modulePaths.js";
|
|
11
|
+
|
|
12
|
+
const compiled = new Set()
|
|
13
|
+
|
|
14
|
+
let usePackages = true
|
|
15
|
+
let jsdoc = false
|
|
16
|
+
let declarations = false
|
|
17
|
+
let check = true
|
|
18
|
+
let useStyle = "import"
|
|
19
|
+
|
|
20
|
+
function syncExternal() {
|
|
21
|
+
const srcExternal = path.resolve("src/external")
|
|
22
|
+
const distExternal = path.resolve("dist/external")
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(srcExternal)) return
|
|
25
|
+
|
|
26
|
+
function syncDir(srcDir, distDir) {
|
|
27
|
+
fs.mkdirSync(distDir, { recursive: true })
|
|
28
|
+
|
|
29
|
+
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
30
|
+
const srcFull = path.join(srcDir, entry.name)
|
|
31
|
+
const distFull = path.join(distDir, entry.name)
|
|
32
|
+
|
|
33
|
+
if (entry.isDirectory()) {
|
|
34
|
+
syncDir(srcFull, distFull)
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (fs.existsSync(distFull)) {
|
|
39
|
+
const srcMtime = fs.statSync(srcFull).mtimeMs
|
|
40
|
+
const distMtime = fs.statSync(distFull).mtimeMs
|
|
41
|
+
if (srcMtime <= distMtime) continue
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fs.copyFileSync(srcFull, distFull)
|
|
45
|
+
Debug.log(`Synced: ${path.relative(".", distFull)}`)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
syncDir(srcExternal, distExternal)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function extractUses(code) {
|
|
53
|
+
code = stripComments(code)
|
|
54
|
+
const uses = []
|
|
55
|
+
|
|
56
|
+
const patterns = [
|
|
57
|
+
/\buse\s+(@[\w$\/.-]+)\s*;?$/gm,
|
|
58
|
+
/\buse\s+(?:\{[^}]+\}|\*\s+as\s+[\w$]+|[\w$]+\s+as\s+[\w$]+|[\w$]+)\s+from\s+(@[\w$\/.-]+)\s*;?$/gm,
|
|
59
|
+
/\buse\s+(?:\{[^}]+\}|\*\s+as\s+[\w$]+|[\w$]+\s+as\s+[\w$]+|[\w$]+)\s+from\s+["']([^"']+)["']\s*;?$/gm,
|
|
60
|
+
/\buse\s+["']([^"']+)["']\s*;?$/gm,
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
for (const pattern of patterns) {
|
|
64
|
+
let match
|
|
65
|
+
while ((match = pattern.exec(code)) !== null) {
|
|
66
|
+
const raw = match[1]
|
|
67
|
+
if (raw) uses.push(raw)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return [...new Set(uses)]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function compileFile(slimFile, isEntry = false, mainEntry = null) {
|
|
75
|
+
const hasSilmExtension = slimFile.endsWith(".slim")
|
|
76
|
+
const file = hasSilmExtension ? slimFile : slimFile + ".slim"
|
|
77
|
+
const abs = path.resolve(file)
|
|
78
|
+
|
|
79
|
+
if (compiled.has(abs)) return
|
|
80
|
+
compiled.add(abs)
|
|
81
|
+
|
|
82
|
+
if (!fs.existsSync(abs)) {
|
|
83
|
+
console.error(`\nError: File not found: ${abs}\n`)
|
|
84
|
+
process.exit(1)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const code = fs.readFileSync(abs, "utf8")
|
|
88
|
+
|
|
89
|
+
const uses = extractUses(code)
|
|
90
|
+
|
|
91
|
+
if (!usePackages && uses.length > 0) {
|
|
92
|
+
const err = new UseError(
|
|
93
|
+
`The "use" feature is disabled. Set "usePackages": true in slimconfig.json to enable imports (in ${abs}, found: use ${uses[0]})`
|
|
94
|
+
)
|
|
95
|
+
console.error(err)
|
|
96
|
+
process.exit(1)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const raw of uses) {
|
|
100
|
+
const depPath = resolveSlimSource(raw, abs)
|
|
101
|
+
|
|
102
|
+
if (depPath === null) continue
|
|
103
|
+
|
|
104
|
+
if (!fs.existsSync(depPath)) {
|
|
105
|
+
const err = new UseError(`No lib/file founded by the path: ${raw}`)
|
|
106
|
+
console.error(err)
|
|
107
|
+
process.exit(1)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (depPath === abs) {
|
|
111
|
+
console.error(`\nError: Circular dependency detected in ${abs}\n`)
|
|
112
|
+
process.exit(1)
|
|
113
|
+
}
|
|
114
|
+
compileFile(depPath, false, mainEntry)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const { code: output, declarations: dts } = transform(code, abs, { jsdoc, declarations, check, uses: useStyle })
|
|
118
|
+
|
|
119
|
+
const outputPath = isEntry
|
|
120
|
+
? path.resolve(`dist/${mainEntry}.js`)
|
|
121
|
+
: getDistPath(abs)
|
|
122
|
+
|
|
123
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true })
|
|
124
|
+
fs.writeFileSync(outputPath, output)
|
|
125
|
+
|
|
126
|
+
if (dts) fs.writeFileSync(outputPath.replace(/\.js$/, ".d.ts"), dts)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function cleanDist(slimFileClear) {
|
|
130
|
+
const keep = new Set([
|
|
131
|
+
path.resolve(`dist/${slimFileClear}.js`),
|
|
132
|
+
path.resolve("dist/mappings.json"),
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
function addDirToKeep(dir) {
|
|
136
|
+
if (!fs.existsSync(dir)) return
|
|
137
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
138
|
+
const full = path.resolve(dir, entry.name)
|
|
139
|
+
keep.add(full)
|
|
140
|
+
if (entry.isDirectory()) addDirToKeep(full)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
addDirToKeep(path.resolve("dist/external"))
|
|
144
|
+
|
|
145
|
+
for (const slimFile of compiled) {
|
|
146
|
+
if (slimFile === path.resolve(`${slimFileClear}.slim`)) {
|
|
147
|
+
keep.add(path.resolve(`dist/${slimFileClear}.js`))
|
|
148
|
+
} else {
|
|
149
|
+
keep.add(getDistPath(slimFile))
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
for (const kept of [...keep]) {
|
|
154
|
+
if (kept.endsWith(".js")) keep.add(kept.replace(/\.js$/, ".d.ts"))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function walkAndClean(dir) {
|
|
158
|
+
if (!fs.existsSync(dir)) return
|
|
159
|
+
|
|
160
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
161
|
+
const full = path.resolve(dir, entry.name)
|
|
162
|
+
|
|
163
|
+
if (entry.isDirectory()) {
|
|
164
|
+
walkAndClean(full)
|
|
165
|
+
|
|
166
|
+
if (fs.readdirSync(full).length === 0) {
|
|
167
|
+
fs.rmdirSync(full)
|
|
168
|
+
}
|
|
169
|
+
} else if (!keep.has(full)) {
|
|
170
|
+
fs.rmSync(full)
|
|
171
|
+
Debug.log(`Cleaned: ${path.relative(".", full)}`)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
walkAndClean(path.resolve("dist"))
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function writeJsConfig() {
|
|
180
|
+
const configPath = path.resolve("jsconfig.json")
|
|
181
|
+
if (fs.existsSync(configPath)) return
|
|
182
|
+
|
|
183
|
+
const config = {
|
|
184
|
+
compilerOptions: {
|
|
185
|
+
allowJs: true,
|
|
186
|
+
checkJs: false,
|
|
187
|
+
noEmit: true,
|
|
188
|
+
module: "esnext",
|
|
189
|
+
target: "es2020",
|
|
190
|
+
moduleResolution: "bundler",
|
|
191
|
+
strict: false,
|
|
192
|
+
skipLibCheck: true
|
|
193
|
+
},
|
|
194
|
+
include: ["dist"]
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 4) + "\n")
|
|
198
|
+
Debug.log("Created jsconfig.json for TypeScript checking")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function main() {
|
|
202
|
+
let data
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
const contents = await readFile("slimconfig.json", "utf8")
|
|
206
|
+
data = JSON.parse(contents)
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error("Error reading or parsing slimconfig.json:", error)
|
|
209
|
+
process.exit(1)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
usePackages = data.usePackages !== false
|
|
213
|
+
jsdoc = data.jsdoc === true
|
|
214
|
+
declarations = data.declarations === true
|
|
215
|
+
check = data.check !== false && process.env.SLIM_NO_CHECK !== "1"
|
|
216
|
+
useStyle = typeof data.uses === "string" ? data.uses : "import"
|
|
217
|
+
|
|
218
|
+
if (!("main" in data)) return
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
syncExternal()
|
|
222
|
+
compileFile(data.main, true, data.main)
|
|
223
|
+
cleanDist(data.main)
|
|
224
|
+
if (jsdoc) writeJsConfig()
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error(`\n${error.slimTypeErrors || error.slimSyntaxError ? error.message : error}\n`)
|
|
227
|
+
process.exit(1)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
main()
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Source frames require a host-provided file reader.
|
|
2
|
+
let readSource = null
|
|
3
|
+
|
|
4
|
+
export function setSourceReader(reader) {
|
|
5
|
+
readSource = typeof reader === "function" ? reader : null
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let __mappings__ = null
|
|
9
|
+
let __sourceFile__ = null
|
|
10
|
+
|
|
11
|
+
function loadMappings() {
|
|
12
|
+
if (__mappings__) return
|
|
13
|
+
try {
|
|
14
|
+
const data = JSON.parse(readSource(new URL("../../dist/mappings.json", import.meta.url)))
|
|
15
|
+
__mappings__ = data.mappings
|
|
16
|
+
__sourceFile__ = data.sourceFile
|
|
17
|
+
} catch {
|
|
18
|
+
__mappings__ = []
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function resolveOriginalLine(generatedLine) {
|
|
23
|
+
loadMappings()
|
|
24
|
+
if (!__mappings__?.length) return { line: generatedLine, file: __sourceFile__ }
|
|
25
|
+
|
|
26
|
+
const mapping = __mappings__
|
|
27
|
+
.filter(m => m.generatedLine <= generatedLine)
|
|
28
|
+
.at(-1)
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
line: mapping?.originalLine ?? generatedLine,
|
|
32
|
+
file: __sourceFile__
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isInternalFrame(normalized) {
|
|
37
|
+
return (
|
|
38
|
+
normalized.includes("node_modules") ||
|
|
39
|
+
normalized.includes("node:") ||
|
|
40
|
+
normalized.includes("/external/") ||
|
|
41
|
+
normalized.includes("/src/handlers/") ||
|
|
42
|
+
normalized.includes("/src/compile.js") ||
|
|
43
|
+
normalized.includes("/src/transform.js") ||
|
|
44
|
+
normalized.includes("/src/parser.js")
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseStack(stack, skip = 0) {
|
|
49
|
+
if (!stack) return null
|
|
50
|
+
|
|
51
|
+
const frames = []
|
|
52
|
+
for (const line of stack.split("\n")) {
|
|
53
|
+
const match = line.match(/at .+ \((.+):(\d+):(\d+)\)/)
|
|
54
|
+
?? line.match(/at (.+):(\d+):(\d+)/)
|
|
55
|
+
|
|
56
|
+
if (!match) continue
|
|
57
|
+
|
|
58
|
+
const [, file, ln, col] = match
|
|
59
|
+
const normalized = file.replace(/^file:\/\/\//, "").replace(/\\/g, "/")
|
|
60
|
+
|
|
61
|
+
if (isInternalFrame(normalized)) continue
|
|
62
|
+
|
|
63
|
+
frames.push({ file: normalized, line: parseInt(ln), col: parseInt(col) })
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (frames.length) {
|
|
67
|
+
const slimFrames = frames.filter(f => f.file.endsWith(".slim"))
|
|
68
|
+
const pool = slimFrames.length ? slimFrames : frames
|
|
69
|
+
return pool[Math.min(skip, pool.length - 1)]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const line of stack.split("\n")) {
|
|
73
|
+
const match = line.match(/at .+ \((.+dist\/output\.js):(\d+):(\d+)\)/)
|
|
74
|
+
?? line.match(/at (.+dist\/output\.js):(\d+):(\d+)/)
|
|
75
|
+
|
|
76
|
+
if (!match) continue
|
|
77
|
+
|
|
78
|
+
const [, , ln, col] = match
|
|
79
|
+
const resolved = resolveOriginalLine(parseInt(ln))
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
file: resolved.file,
|
|
83
|
+
line: resolved.line,
|
|
84
|
+
col: parseInt(col)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getSourceLine(file, line) {
|
|
92
|
+
if (!readSource) return null
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const content = readSource(file.replace(/\\/g, "/"))
|
|
96
|
+
return content?.split("\n")[line - 1]?.replace(/\r$/, "") ?? null
|
|
97
|
+
} catch {
|
|
98
|
+
return null
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function resolveErrorLocation(err) {
|
|
103
|
+
if (err?.file && err?.line) {
|
|
104
|
+
return {
|
|
105
|
+
file: err.file,
|
|
106
|
+
line: err.line,
|
|
107
|
+
col: err.col ?? null,
|
|
108
|
+
sourceLine: err.sourceLine ?? getSourceLine(err.file, err.line)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const loc = parseStack(err?.stack)
|
|
113
|
+
if (!loc) return null
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
file: loc.file,
|
|
117
|
+
line: loc.line,
|
|
118
|
+
col: loc.col ?? null,
|
|
119
|
+
sourceLine: getSourceLine(loc.file, loc.line)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function formatError(tag, message, file, line, col, sourceLine) {
|
|
124
|
+
const parts = [`\n${tag}: ${message}`]
|
|
125
|
+
|
|
126
|
+
if (file && line) {
|
|
127
|
+
parts.push(` at ${file}:${line}:${col ?? 1}`)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (sourceLine) {
|
|
131
|
+
const trimmed = sourceLine.trim()
|
|
132
|
+
const indent = sourceLine.search(/\S/)
|
|
133
|
+
const pointer = col
|
|
134
|
+
? " ".repeat(Math.max(0, col - indent - 1)) + "^"
|
|
135
|
+
: "^"
|
|
136
|
+
|
|
137
|
+
parts.push(`\n ${trimmed}`)
|
|
138
|
+
parts.push(` ${pointer}`)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
parts.push("")
|
|
142
|
+
return parts.join("\n")
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export class LangError extends Error {
|
|
146
|
+
constructor(message, tag = "Error", meta = {}) {
|
|
147
|
+
super(message)
|
|
148
|
+
this.tag = tag
|
|
149
|
+
this.name = tag
|
|
150
|
+
|
|
151
|
+
const loc = parseStack(this.stack, meta.skipUserFrames ?? 0)
|
|
152
|
+
|
|
153
|
+
this.file = meta.file ?? loc?.file ?? null
|
|
154
|
+
this.line = meta.line ?? loc?.line ?? null
|
|
155
|
+
this.col = meta.col ?? loc?.col ?? null
|
|
156
|
+
this.sourceLine = meta.sourceLine ?? (
|
|
157
|
+
this.file && this.line
|
|
158
|
+
? getSourceLine(this.file, this.line)
|
|
159
|
+
: null
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if (Error.captureStackTrace) {
|
|
163
|
+
Error.captureStackTrace(this, this.constructor)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export class StructError extends LangError {
|
|
169
|
+
constructor(m, meta) { super(m, "StructError", meta) }
|
|
170
|
+
}
|
|
171
|
+
export class StructPassedError extends LangError {
|
|
172
|
+
constructor(m, meta) { super(m, "StructPassedError", meta) }
|
|
173
|
+
}
|
|
174
|
+
export class StructExpectError extends LangError {
|
|
175
|
+
constructor(m, meta) { super(m, "StructExpectError", meta) }
|
|
176
|
+
}
|
|
177
|
+
export class StructResultError extends StructError {
|
|
178
|
+
constructor(m, meta) { super(m, "StructResultError", meta) }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export class TypeError_ extends LangError {
|
|
182
|
+
constructor(m, meta) { super(m, "TypeError", meta) }
|
|
183
|
+
}
|
|
184
|
+
export class RuntimeError extends LangError {
|
|
185
|
+
constructor(m, meta) { super(m, "RuntimeError", meta) }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export class ArgumentDeclarationTypeError extends TypeError_ {
|
|
189
|
+
constructor(m, meta) { super(m, meta) }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export class EnumError extends LangError {
|
|
193
|
+
constructor(m, meta) { super(m, "EnumError", meta) }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export class UseError extends Error {
|
|
197
|
+
constructor(m, meta) { super(m, "UseError", meta) }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export class TypeDefError extends TypeError {
|
|
201
|
+
constructor(m, meta) { super(m, "TypeDefError", meta) }
|
|
202
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Browser-safe runtime subset serialized into client handlers.
|
|
2
|
+
|
|
3
|
+
export function log(...args) { console.log(...args) }
|
|
4
|
+
export function warn(...args) { console.warn(...args) }
|
|
5
|
+
export function error(...args) { console.error(...args) }
|
|
6
|
+
export function info(...args) { console.info(...args) }
|
|
7
|
+
export function debug(...args) { console.log(...args) }
|
|
8
|
+
|
|
9
|
+
export function type(obj) {
|
|
10
|
+
if (obj === null) return "null"
|
|
11
|
+
if (obj === undefined) return "undefined"
|
|
12
|
+
if (typeof obj === "number" && Number.isNaN(obj)) return "NaN"
|
|
13
|
+
|
|
14
|
+
if (typeof HTMLElement !== "undefined" && obj instanceof HTMLElement) return "element"
|
|
15
|
+
if (obj && typeof obj === "object" && obj.nodeType === 11) return "fragment"
|
|
16
|
+
|
|
17
|
+
if (typeof obj === "function" && obj.__type__ === true) return "type"
|
|
18
|
+
if (typeof obj === "function" && obj.__component__ === true) return "component"
|
|
19
|
+
|
|
20
|
+
if (Array.isArray(obj)) {
|
|
21
|
+
if (obj.length > 0) {
|
|
22
|
+
const first = type(obj[0])
|
|
23
|
+
if (obj.every(el => type(el) === first)) return first + "[]"
|
|
24
|
+
}
|
|
25
|
+
return "array"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof obj === "object") return "object"
|
|
29
|
+
if (typeof obj === "string") return "string"
|
|
30
|
+
if (typeof obj === "number") return Number.isInteger(obj) ? "int" : "float"
|
|
31
|
+
if (typeof obj === "boolean") return "bool"
|
|
32
|
+
if (typeof obj === "function") return /^\s*class\s+/.test(obj.toString()) ? "class" : "function"
|
|
33
|
+
|
|
34
|
+
return undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Client declarations are emitted before the handler table.
|
|
38
|
+
export const CLIENT_RUNTIME = [log, warn, error, info, debug, type]
|