@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.
Files changed (52) hide show
  1. package/README.md +666 -0
  2. package/package.json +55 -0
  3. package/packages/slim/.spm +7 -0
  4. package/packages/slim/converters/main.slim +106 -0
  5. package/packages/slim/helpers/array.slim +25 -0
  6. package/packages/slim/helpers/path.slim +3 -0
  7. package/packages/slim/helpers/request.slim +102 -0
  8. package/packages/slim/helpers/string.slim +27 -0
  9. package/packages/slim/main.slim +42 -0
  10. package/packages/slim/parse/main.slim +25 -0
  11. package/packages/slim/server/main.slim +423 -0
  12. package/packages/slim/time/main.slim +66 -0
  13. package/packages/slim/types/common.slim +6 -0
  14. package/packages/slim/types/formats.slim +23 -0
  15. package/packages/slim/types/hash.slim +6 -0
  16. package/packages/slim/types/mails.slim +3 -0
  17. package/packages/slim/types/numerical.slim +9 -0
  18. package/packages/slim/types/time.slim +3 -0
  19. package/run-dev-slim.js +133 -0
  20. package/run-slim.js +20 -0
  21. package/src/bin/api/github_auth.js +89 -0
  22. package/src/bin/api/github_get.js +139 -0
  23. package/src/bin/api/github_req.js +455 -0
  24. package/src/bin/api/lock.js +37 -0
  25. package/src/bin/api/spm.js +103 -0
  26. package/src/bin/api/storage.js +30 -0
  27. package/src/bin/cli.js +404 -0
  28. package/src/bin/config.default.json +5 -0
  29. package/src/bin/helpers.js +147 -0
  30. package/src/bin/parsers/spm.js +174 -0
  31. package/src/bin/spm.js +519 -0
  32. package/src/checker.js +926 -0
  33. package/src/compile.js +230 -0
  34. package/src/external/classErrors.js +202 -0
  35. package/src/external/client.js +38 -0
  36. package/src/external/core.js +861 -0
  37. package/src/external/defaults.js +25 -0
  38. package/src/external/helpers.js +541 -0
  39. package/src/external/slim-globals.d.ts +65 -0
  40. package/src/external/types.js +38 -0
  41. package/src/format.js +81 -0
  42. package/src/handlers/errorHandler.js +43 -0
  43. package/src/handlers/parser/components.js +250 -0
  44. package/src/handlers/parserHandler.js +793 -0
  45. package/src/jsdoc.js +273 -0
  46. package/src/lexer.js +174 -0
  47. package/src/modulePaths.js +74 -0
  48. package/src/parser.js +818 -0
  49. package/src/repl.js +32 -0
  50. package/src/sourcemap.js +0 -0
  51. package/src/test-runner.js +62 -0
  52. package/src/transform.js +765 -0
@@ -0,0 +1,861 @@
1
+ // Portable core runtime with no Node or DOM dependencies.
2
+
3
+ import {
4
+ StructPassedError, StructError, StructExpectError, ArgumentDeclarationTypeError,
5
+ EnumError
6
+ } from "./classErrors.js"
7
+ import {
8
+ SlimVariableType, SlimVariableTypes, Struct, Component, Enum, EnumValue,
9
+ isSameType
10
+ } from "./types.js"
11
+ import { formatError, resolveErrorLocation } from "./classErrors.js"
12
+
13
+ const __structs__ = {}
14
+ const __enums__ = {}
15
+ const __RESERVED_DEFINES__ = new Set([
16
+ "Error", "Object", "Array", "String", "Number",
17
+ "Boolean", "Function", "Symbol", "Map", "Set",
18
+ "Promise", "Proxy", "Reflect", "Math", "JSON",
19
+ "Date", "RegExp", "WeakMap", "WeakSet", "WeakRef",
20
+ "ArrayBuffer", "DataView", "Iterator",
21
+ "Int8Array", "Uint8Array", "Uint8ClampedArray",
22
+ "Int16Array", "Uint16Array", "Int32Array",
23
+ "Uint32Array", "Float32Array", "Float64Array",
24
+ "undefined", "null", "NaN", "Infinity",
25
+ "globalThis", "global", "process", "console",
26
+ "setTimeout", "setInterval", "clearTimeout", "clearInterval",
27
+ "queueMicrotask", "structuredClone",
28
+ "eval", "isNaN", "isFinite", "parseFloat", "parseInt",
29
+ "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent",
30
+ "type", "schemeArray", "verify", "values", "verifySafe"
31
+ ])
32
+ export const __custom_types__ = {}
33
+
34
+ const RELEASE = typeof process !== "undefined" && process.env?.SLIM_RELEASE === "1"
35
+
36
+ function writeError(text) {
37
+ if (typeof process !== "undefined" && process.stderr) process.stderr.write(text)
38
+ else console.error(text)
39
+ }
40
+
41
+ function reportError(err) {
42
+ const loc = resolveErrorLocation(err)
43
+ writeError(formatError(
44
+ err?.tag ?? err?.name ?? "Error",
45
+ err?.message ?? String(err),
46
+ loc?.file ?? null,
47
+ loc?.line ?? null,
48
+ loc?.col ?? null,
49
+ loc?.sourceLine ?? null,
50
+ ) + "\n")
51
+ }
52
+
53
+ let __error_handler__ = null
54
+
55
+ export function onError(handler) {
56
+ __error_handler__ = typeof handler === "function" ? handler : null
57
+ }
58
+
59
+ function finalizeError(err) {
60
+ if (__error_handler__) {
61
+ __error_handler__(err)
62
+ return
63
+ }
64
+ reportError(err)
65
+ if (typeof process !== "undefined" && typeof process.exit === "function") {
66
+ process.exit(1)
67
+ }
68
+ }
69
+
70
+ export function __handle_async_error__(err) {
71
+ finalizeError(err)
72
+ }
73
+ export function __handle_sync_error__(err) {
74
+ finalizeError(err)
75
+ }
76
+
77
+ function logProcessed(args) {
78
+ return args.map(arg => {
79
+ if (Type.isTyped(arg) && "value" in arg) {
80
+ return arg.value
81
+ }
82
+ if (Type.isTyped(arg) && "scheme" in arg) {
83
+ return arg.scheme
84
+ }
85
+ return arg
86
+ })
87
+ }
88
+ export const log = (...args) => {
89
+ const processed = logProcessed(args)
90
+ console.log(...processed)
91
+ }
92
+ export const warn = (...args) => {
93
+ const processed = logProcessed(args)
94
+ console.warn(...processed)
95
+ }
96
+ export const error = (...args) => {
97
+ const processed = logProcessed(args)
98
+ console.error(...processed)
99
+ }
100
+ export const info = (...args) => {
101
+ const processed = logProcessed(args)
102
+ console.info(...processed)
103
+ }
104
+ export const debug = (...args) => {
105
+ console.log(...args)
106
+ }
107
+
108
+ export const PI = Math.PI
109
+
110
+ const __test_stats__ = { passed: 0, failed: 0 }
111
+
112
+ export function test(name, fn) {
113
+ try {
114
+ fn()
115
+ __test_stats__.passed++
116
+ console.log(` ✓ ${name}`)
117
+ } catch (err) {
118
+ __test_stats__.failed++
119
+ if (typeof process !== "undefined") process.exitCode = 1
120
+ console.log(` ✗ ${name}\n ${err?.message ?? err}`)
121
+ }
122
+ }
123
+
124
+ export function assert(condition, message = "assertion failed") {
125
+ if (!condition) throw new Error(message)
126
+ }
127
+
128
+ export function assertEqual(actual, expected, message) {
129
+ if (actual !== expected) {
130
+ throw new Error(message ?? `expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`)
131
+ }
132
+ }
133
+
134
+ if (typeof process !== "undefined" && typeof process.on === "function") {
135
+ process.on("exit", () => {
136
+ const total = __test_stats__.passed + __test_stats__.failed
137
+ if (total > 0) console.log(`\n${__test_stats__.passed} passed, ${__test_stats__.failed} failed`)
138
+ })
139
+ }
140
+
141
+ export class Type {
142
+ static isStruct(obj) {
143
+ return type(obj) == "struct"
144
+ }
145
+ static isEnum(obj) {
146
+ return type(obj) == "enum"
147
+ }
148
+ static isEnumValue(obj) {
149
+ return obj instanceof EnumValue
150
+ }
151
+ static isObj(obj) {
152
+ return type(obj) == "object"
153
+ }
154
+ static isTyped(obj) {
155
+ if (obj instanceof SlimVariableType || obj instanceof EnumValue || obj instanceof Struct) {
156
+ return true
157
+ }
158
+ else {
159
+ return false
160
+ }
161
+ }
162
+ static isAnyArray(obj) {
163
+ if (type(obj) == "array") return true
164
+ else if (type(obj).endsWith("[]")) return true
165
+ else return false
166
+ }
167
+
168
+ static isRegistredCustom(type) {
169
+ return Object.keys(__custom_types__).includes(type)
170
+ }
171
+
172
+ static Customs = __custom_types__
173
+ }
174
+ export class Debug {
175
+ static log(...args) {
176
+ console.log(`[SLIM]`, ...args)
177
+ }
178
+ }
179
+
180
+ export function type(obj, properties = {}) {
181
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
182
+ const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/
183
+
184
+ const isArray = (obj) => {
185
+ return typeof obj === "object" && Array.isArray(obj)
186
+ }
187
+ const isTypedArray = (arr, t) => {
188
+ return arr.every(element => type(element) === t)
189
+ }
190
+ const isTypedOfArray = (arr, t) => {
191
+ return arr.every(element => typeof element === t)
192
+ }
193
+
194
+ if (obj === null) return "null"
195
+ if (obj === undefined) return "undefined"
196
+ if (Number.isNaN(obj)) return "NaN"
197
+
198
+ // The optional DOM layer requires structural element detection.
199
+ if (obj && typeof obj === "object" && obj.nodeType === 1) return "element"
200
+ if (obj && obj.nodeType === 11) return "fragment"
201
+
202
+ if(typeof obj == "function" && obj.__type__ == true) return "type"
203
+
204
+ if (typeof obj == "object" && obj instanceof SlimVariableType) {
205
+ return obj.kind
206
+ }
207
+
208
+ if (typeof obj == "object" && !Array.isArray(obj) && "type" in obj && obj.type == Struct) {
209
+ return "struct"
210
+ }
211
+ if (typeof obj == "object" && !Array.isArray(obj) && "type" in obj && obj.type instanceof Enum) {
212
+ return "enum"
213
+ }
214
+ if (typeof obj == "object" && !Array.isArray(obj) && obj instanceof EnumValue) {
215
+ return "enum"
216
+ }
217
+
218
+ if (typeof obj === "function" && obj.__component__ == true) return "component"
219
+
220
+ if (isArray(obj) && isTypedArray(obj, "undefined")) return "null[]"
221
+ if (isArray(obj) && isTypedArray(obj, "string")) return "string[]"
222
+ if (isArray(obj) && isTypedArray(obj, "int")) return "int[]"
223
+ if (isArray(obj) && isTypedArray(obj, "float")) return "float[]"
224
+ if (isArray(obj) && isTypedArray(obj, "object")) return "object[]"
225
+ if (isArray(obj) && isTypedOfArray(obj, "number")) return "number[]"
226
+ if (isArray(obj) && isTypedArray(obj, "enum")) return "enum[]"
227
+ if (isArray(obj) && isTypedArray(obj, "struct")) return "struct[]"
228
+ if (isArray(obj) && isTypedArray(obj, "array")) return "array[]"
229
+
230
+ if (isArray(obj)) return "array"
231
+
232
+ if (obj instanceof Map) return "map"
233
+ if (obj instanceof Set) return "set"
234
+ if (obj instanceof Date) return "date"
235
+ if (obj instanceof Promise) return "promise"
236
+ if (obj instanceof RegExp) return "regexp"
237
+ if (obj instanceof Error) return "error"
238
+
239
+ if (typeof obj === "object" && !Array.isArray(obj)) return "object"
240
+
241
+ if (typeof obj === "string") return "string"
242
+ if (typeof obj === "number" && Number.isInteger(obj)) return "int"
243
+ if (typeof obj === "number" && !Number.isInteger(obj)) return "float"
244
+
245
+ if (typeof obj === "boolean") return "bool"
246
+ if (typeof obj === "bigint") return "bigint"
247
+ if (typeof obj === "symbol") return "symbol"
248
+
249
+ if (typeof obj === "function" && /^\s*class\s+/.test(obj.toString())) return "class"
250
+ if (typeof obj == "function") return "function"
251
+
252
+ return undefined
253
+ }
254
+
255
+
256
+ export function __type_ref__(label, resolve = null) {
257
+ return { __slim_type_ref__: true, label, resolve }
258
+ }
259
+
260
+ export function __type_spec__(...references) {
261
+ return references
262
+ }
263
+
264
+ export function __type_spec_all__(...references) {
265
+ return { __slim_all__: true, references }
266
+ }
267
+
268
+ function referenceLabel(reference) {
269
+ return typeof reference === "string" ? reference : reference?.label ?? String(reference)
270
+ }
271
+
272
+ export function __type_label__(specification) {
273
+ if (specification && specification.__slim_all__) {
274
+ return specification.references.map(referenceLabel).join(" & ")
275
+ }
276
+ const refs = Array.isArray(specification) ? specification : [specification]
277
+ return refs.map(referenceLabel).join(" | ")
278
+ }
279
+
280
+ function resolveTypeReference(reference) {
281
+ if (reference && typeof reference === "object" && reference.__slim_type_ref__) {
282
+ if (typeof reference.resolve === "function") return reference.resolve()
283
+
284
+ const name = reference.label.replace(/(?:\[\])+$/, "").split("::")[0]
285
+ return __custom_types__[name] ?? __structs__[name] ?? __enums__[name]
286
+ }
287
+
288
+ if (typeof reference === "string") {
289
+ const name = reference.replace(/(?:\[\])+$/, "").split("::")[0]
290
+ return __custom_types__[name] ?? __structs__[name] ?? __enums__[name]
291
+ }
292
+
293
+ return reference
294
+ }
295
+
296
+ function isClass(value) {
297
+ return typeof value === "function" && /^\s*class\s+/.test(Function.prototype.toString.call(value))
298
+ }
299
+
300
+ function matchesDefinition(definition, value) {
301
+ if (Array.isArray(definition)) return __type_matches__(definition, value)
302
+
303
+ if (typeof definition === "function") {
304
+ if (isClass(definition)) return value instanceof definition
305
+ return definition(value) === true
306
+ }
307
+
308
+ return isSameType(definition, value)
309
+ }
310
+
311
+ function matchesResolvedType(resolved, label, value) {
312
+ if (resolved === undefined || resolved === null) return false
313
+
314
+ if (resolved?.type === Struct) {
315
+ return __typed__(value, resolved, "errorResult").success
316
+ }
317
+
318
+ if (resolved?.type instanceof Enum) return resolved.has(value)
319
+ if (resolved instanceof EnumValue) return resolved === value
320
+
321
+ if (typeof resolved === "function" && resolved.__type__ === true) {
322
+ return resolved(value) === true
323
+ }
324
+
325
+ return matchesDefinition(resolved, value)
326
+ }
327
+
328
+ const BUILTIN_CLASSES = { Map, Set, Date, Promise, RegExp, Error }
329
+
330
+ // Split tuple and generic members only at top-level commas.
331
+ function splitTypeList(text) {
332
+ const parts = []
333
+ let depth = 0
334
+ let current = ""
335
+
336
+ for (const char of text) {
337
+ if (char === "<" || char === "[" || char === "(") depth++
338
+ else if (char === ">" || char === "]" || char === ")") depth--
339
+ else if (char === "," && depth === 0) { parts.push(current.trim()); current = ""; continue }
340
+ current += char
341
+ }
342
+ if (current.trim()) parts.push(current.trim())
343
+ return parts
344
+ }
345
+
346
+ function matchesLabel(label, value) {
347
+ return __type_matches__(__type_spec__(__type_ref__(label)), value)
348
+ }
349
+
350
+ function matchesNamedType(label, resolved, value) {
351
+ if (label === "any") return true
352
+
353
+ if (label.length > 2 && label.startsWith("[") && label.endsWith("]")) {
354
+ if (!Array.isArray(value)) return false
355
+
356
+ const parts = splitTypeList(label.slice(1, -1))
357
+ if (value.length !== parts.length) return false
358
+ return parts.every((part, index) => matchesLabel(part, value[index]))
359
+ }
360
+
361
+ const generic = label.indexOf("<")
362
+ if (generic !== -1 && label.endsWith(">")) {
363
+ const container = label.slice(0, generic).trim()
364
+ const args = splitTypeList(label.slice(generic + 1, -1))
365
+ const first = args[0] ?? "any"
366
+
367
+ if (container === "Array") {
368
+ return Array.isArray(value) && value.every(item => matchesLabel(first, item))
369
+ }
370
+ if (container === "Set") {
371
+ return value instanceof Set && [...value].every(item => matchesLabel(first, item))
372
+ }
373
+ if (container === "Map") {
374
+ const second = args[1] ?? "any"
375
+ return value instanceof Map && [...value].every(([key, entry]) =>
376
+ matchesLabel(first, key) && matchesLabel(second, entry))
377
+ }
378
+ if (container === "Promise") return value instanceof Promise
379
+
380
+ return matchesNamedType(container, resolved, value)
381
+ }
382
+
383
+ if (label.endsWith("[]")) {
384
+ if (!Array.isArray(value)) return false
385
+
386
+ const elementLabel = label.slice(0, -2)
387
+ if (value.length === 0) return type(value) === label || elementLabel === "any"
388
+
389
+ if (resolved !== undefined) {
390
+ return value.every(item => matchesResolvedType(resolved, elementLabel, item))
391
+ }
392
+
393
+ return type(value) === label
394
+ }
395
+
396
+ const enumSeparator = label.indexOf("::")
397
+ if (enumSeparator !== -1) {
398
+ const enumName = label.slice(0, enumSeparator)
399
+ const member = label.slice(enumSeparator + 2)
400
+ const enumDef = resolved ?? __enums__[enumName]
401
+ return !!enumDef && enumDef[member] === value
402
+ }
403
+
404
+ if (resolved !== undefined) return matchesResolvedType(resolved, label, value)
405
+ if (label === "number") return type(value) === "int" || type(value) === "float"
406
+
407
+ if (label in BUILTIN_CLASSES) return value instanceof BUILTIN_CLASSES[label]
408
+
409
+ return type(value) === label
410
+ }
411
+
412
+ function matchesReference(reference, value) {
413
+ const label = typeof reference === "string" ? reference : reference?.label
414
+ if (!label) return false
415
+ return matchesNamedType(label, resolveTypeReference(reference), value)
416
+ }
417
+
418
+ export function __type_matches__(specification, value) {
419
+ if (specification && specification.__slim_all__) {
420
+ return specification.references.every(reference => matchesReference(reference, value))
421
+ }
422
+ const references = Array.isArray(specification) ? specification : [specification]
423
+ return references.some(reference => matchesReference(reference, value))
424
+ }
425
+
426
+ function previewValue(value) {
427
+ try {
428
+ if (typeof value === "string") return JSON.stringify(value)
429
+ if (typeof value === "function") return type(value)
430
+ const text = JSON.stringify(value)
431
+ if (text === undefined) return String(value)
432
+ return text.length > 40 ? text.slice(0, 40) + "…" : text
433
+ } catch {
434
+ return String(value)
435
+ }
436
+ }
437
+
438
+ function typeError(varName, expected, value, action = "assigned") {
439
+ const actual = type(value)
440
+ const preview = previewValue(value)
441
+ if (action === "redefined") {
442
+ throw new TypeError(`The variable "${varName}" is of type ${expected}, but it was redefined with type ${actual}: ${preview}`)
443
+ }
444
+ if (action === "mutated") {
445
+ throw new TypeError(`The variable "${varName}" is of type ${expected}, but it was mutated into type ${actual}: ${preview}`)
446
+ }
447
+ throw new TypeError(`The "${varName}" is of type ${expected}, but was assigned a ${actual}: ${preview}`)
448
+ }
449
+
450
+ const guardedValues = new WeakMap()
451
+ const scopedVariableTypes = new WeakMap()
452
+ const typedStaticFields = new WeakMap()
453
+
454
+ function setVariableType(bindingId, definition) {
455
+ if (bindingId && (typeof bindingId === "object" || typeof bindingId === "function")) {
456
+ scopedVariableTypes.set(bindingId, definition)
457
+ } else {
458
+ SlimVariableTypes[bindingId] = definition
459
+ }
460
+ }
461
+
462
+ function getVariableType(bindingId) {
463
+ if (bindingId && (typeof bindingId === "object" || typeof bindingId === "function")) {
464
+ return scopedVariableTypes.get(bindingId)
465
+ }
466
+ return SlimVariableTypes[bindingId]
467
+ }
468
+
469
+ function setStaticFieldType(owner, field, definition) {
470
+ const fields = typedStaticFields.get(owner) ?? new Map()
471
+ fields.set(field, definition)
472
+ typedStaticFields.set(owner, fields)
473
+ }
474
+
475
+ function getStaticFieldType(owner, field) {
476
+ return typedStaticFields.get(owner)?.get(field)
477
+ }
478
+
479
+ function guardTypedValue(value, specification, varName) {
480
+ if (!value || typeof value !== "object" || !__type_matches__(specification, value)) return value
481
+ if (__type_label__(specification) === "any") return value
482
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype) return value
483
+
484
+ const cached = guardedValues.get(value)
485
+ if (cached?.has(specification)) return cached.get(specification)
486
+
487
+ const restore = (target, property, descriptor) => {
488
+ if (descriptor) Reflect.defineProperty(target, property, descriptor)
489
+ else Reflect.deleteProperty(target, property)
490
+ }
491
+ const check = (target, property, descriptor) => {
492
+ if (__type_matches__(specification, target)) return
493
+ restore(target, property, descriptor)
494
+ typeError(varName, __type_label__(specification), target, "mutated")
495
+ }
496
+ const proxy = new Proxy(value, {
497
+ set(target, property, next) {
498
+ const descriptor = Object.getOwnPropertyDescriptor(target, property)
499
+ const succeeded = Reflect.set(target, property, next, target)
500
+ if (!succeeded) return false
501
+ check(target, property, descriptor)
502
+ return true
503
+ },
504
+ deleteProperty(target, property) {
505
+ const descriptor = Object.getOwnPropertyDescriptor(target, property)
506
+ const succeeded = Reflect.deleteProperty(target, property)
507
+ if (!succeeded) return false
508
+ check(target, property, descriptor)
509
+ return true
510
+ },
511
+ defineProperty(target, property, descriptor) {
512
+ const previous = Object.getOwnPropertyDescriptor(target, property)
513
+ const succeeded = Reflect.defineProperty(target, property, descriptor)
514
+ if (!succeeded) return false
515
+ check(target, property, previous)
516
+ return true
517
+ }
518
+ })
519
+
520
+ const entries = cached ?? new Map()
521
+ entries.set(specification, proxy)
522
+ guardedValues.set(value, entries)
523
+ return proxy
524
+ }
525
+
526
+
527
+ export function __def_struct__(name, schema, specifications = {}, defaults = {}, extendsName = null, methods = {}) {
528
+ const parent = extendsName ? __structs__[extendsName] : null
529
+ if (extendsName && !parent) throw new StructError(`Struct "${name}" extends unknown struct "${extendsName}"`)
530
+
531
+ const schemeArray = parent ? { ...parent.scheme } : {}
532
+ const mergedDefaults = parent ? { ...parent.__defaults__, ...defaults } : defaults
533
+ const mergedMethods = parent ? { ...parent.__methods__, ...methods } : methods
534
+
535
+ Object.keys(schema).forEach(item => {
536
+ let fieldName = item
537
+ let optional = false
538
+ if (fieldName.startsWith("*")) {
539
+ optional = true
540
+ fieldName = fieldName.slice(1).trim()
541
+ }
542
+
543
+ schemeArray[fieldName] = {
544
+ type: schema[item],
545
+ specification: specifications[fieldName] ?? schema[item],
546
+ optional
547
+ }
548
+ })
549
+
550
+ const definition = {
551
+ type: Struct,
552
+ name,
553
+ scheme: schemeArray,
554
+ __defaults__: mergedDefaults,
555
+ __methods__: mergedMethods,
556
+ verify: object => __typed__(object, definition),
557
+ verifySafe: object => __typed__(object, definition, "errorResult"),
558
+ new: (values = {}) => {
559
+ const filled = {}
560
+ for (const key of Object.keys(mergedDefaults)) {
561
+ if (!(key in values)) filled[key] = mergedDefaults[key]()
562
+ }
563
+ const data = __typed__({ ...filled, ...values }, definition)
564
+ return Object.keys(mergedMethods).length ? Object.assign(Object.create(mergedMethods), data) : data
565
+ }
566
+ }
567
+
568
+ __structs__[name] = definition
569
+ if (__RESERVED_DEFINES__.has(name)) throw new StructError(`Name "${name}" is reserved`)
570
+ globalThis[name] = definition
571
+ return definition
572
+ }
573
+
574
+ export function __def_enum__(name, schema) {
575
+ const values = { ...schema }
576
+ const definition = {
577
+ type: new Enum(name),
578
+ name,
579
+ scheme: () => values,
580
+ values: () => Object.values(values),
581
+ keys: () => Object.keys(values),
582
+ has: value => Object.values(values).some(item =>
583
+ value === item || (value instanceof EnumValue && value.value === item)
584
+ )
585
+ }
586
+
587
+ Object.keys(values).forEach(key => {
588
+ definition[key] = new EnumValue(values[key])
589
+ })
590
+
591
+ __enums__[name] = definition
592
+ if (__RESERVED_DEFINES__.has(name)) throw new EnumError(`Name "${name}" is reserved`)
593
+ globalThis[name] = definition
594
+ return definition
595
+ }
596
+
597
+ export function __typed_variable__(value, specification, bindingId, varName = bindingId) {
598
+ if (RELEASE) return value
599
+ const expected = __type_label__(specification)
600
+ if (!__type_matches__(specification, value)) typeError(varName, expected, value)
601
+
602
+ setVariableType(bindingId, {
603
+ expected: specification,
604
+ label: expected,
605
+ name: varName
606
+ })
607
+ return guardTypedValue(value, specification, varName)
608
+ }
609
+
610
+ export function __typed_return__(value, specification, fnName) {
611
+ if (RELEASE) return value
612
+
613
+ if (!__type_matches__(specification, value)) {
614
+ throw new TypeError(
615
+ `function "${fnName}" must return ${__type_label__(specification)}, got ${type(value)}: ${previewValue(value)}`
616
+ )
617
+ }
618
+ return value
619
+ }
620
+
621
+ export function __typed_pattern__(value, typeLabel) {
622
+ if (RELEASE) return value
623
+ if (!__type_matches__(typeLabel, value)) {
624
+ throw new TypeError(`destructured value does not match type ${typeLabel}: ${previewValue(value)}`)
625
+ }
626
+ return value
627
+ }
628
+
629
+ export function __typed_variable_check__(bindingId, value, varName = bindingId) {
630
+ if (RELEASE) return value
631
+ const typed = getVariableType(bindingId)
632
+ if (!typed) return value
633
+ if (!__type_matches__(typed.expected, value)) typeError(varName, typed.label, value, "redefined")
634
+ return guardTypedValue(value, typed.expected, varName)
635
+ }
636
+
637
+ export function __typed_parameter__(value, specification, bindingId, varName, optional, message) {
638
+ if (RELEASE) return value
639
+ if (optional && (value === undefined || value === null)) {
640
+ setVariableType(bindingId, {
641
+ expected: specification,
642
+ label: __type_label__(specification),
643
+ name: varName
644
+ })
645
+ return value
646
+ }
647
+
648
+ if (!__type_matches__(specification, value)) {
649
+ throw new ArgumentDeclarationTypeError(message, { skipUserFrames: 1 })
650
+ }
651
+
652
+ setVariableType(bindingId, {
653
+ expected: specification,
654
+ label: __type_label__(specification),
655
+ name: varName
656
+ })
657
+ return guardTypedValue(value, specification, varName)
658
+ }
659
+
660
+ export function __typed_static_field__(owner, field, value, specification, displayName) {
661
+ if (RELEASE) return value
662
+ const label = __type_label__(specification)
663
+ if (!__type_matches__(specification, value)) typeError(displayName, label, value)
664
+ setStaticFieldType(owner, field, { expected: specification, label })
665
+ return guardTypedValue(value, specification, displayName)
666
+ }
667
+
668
+ export function __typed_static_field_check__(owner, field, value, displayName) {
669
+ if (RELEASE) return value
670
+ const definition = getStaticFieldType(owner, field)
671
+ if (!definition) return value
672
+ if (!__type_matches__(definition.expected, value)) {
673
+ typeError(displayName, definition.label, value, "redefined")
674
+ }
675
+ return guardTypedValue(value, definition.expected, displayName)
676
+ }
677
+
678
+ export function __argument_typed__(value, expectedType) {
679
+ return __type_matches__(expectedType, value)
680
+ }
681
+
682
+ export function __type_def__(name, definition, properties = {}) {
683
+ const inherited = properties.extends ?? null
684
+ const customType = value => {
685
+ if (inherited && !__type_matches__(inherited, value)) return false
686
+ return matchesDefinition(definition, value)
687
+ }
688
+
689
+ customType.__type__ = true
690
+ customType.__slim_type_name__ = name
691
+ customType.value = definition
692
+ __custom_types__[name] = customType
693
+ return customType
694
+ }
695
+
696
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
697
+ __type_def__("email", value => typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
698
+ __type_def__("url", value => typeof value === "string" && /^https?:\/\/[^\s]+$/.test(value))
699
+ __type_def__("uuid", value => typeof value === "string" && UUID.test(value))
700
+ __type_def__("positive", value => typeof value === "number" && value > 0)
701
+ __type_def__("negative", value => typeof value === "number" && value < 0)
702
+ __type_def__("natural", value => Number.isInteger(value) && value >= 0)
703
+ __type_def__("nonempty", value => (typeof value === "string" || Array.isArray(value)) && value.length > 0)
704
+
705
+ export function __typed__(value, structName, returnMethod = "default") {
706
+ const name = typeof structName === "string" ? structName : structName?.name
707
+ const structDef = typeof structName === "string" ? __structs__[structName] : structName
708
+ if (!structDef) throw new StructError(`Unknown struct "${structName}"`)
709
+
710
+ const fail = (error, properties = {}) => {
711
+ if (returnMethod === "errorResult") {
712
+ return { success: false, result: { type: error.tag, msg: String(error) }, properties }
713
+ }
714
+ throw error
715
+ }
716
+
717
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
718
+ return fail(new StructError(`Expected object for "${name}"`))
719
+ }
720
+
721
+ const schema = structDef.scheme
722
+ const extra = Object.keys(value).filter(key => !(key in schema))
723
+ if (extra.length > 0) {
724
+ return fail(new StructPassedError(
725
+ `"${name}" does not contain any keys named "${extra.join(", ")}", but it receives them`
726
+ ))
727
+ }
728
+
729
+ for (const [field, definition] of Object.entries(schema)) {
730
+ if (!(field in value)) {
731
+ if (!definition.optional) {
732
+ return fail(new StructExpectError(
733
+ `"${name}" is receiving fewer keys than expected. The key "${field}" have not been received`
734
+ ))
735
+ }
736
+ continue
737
+ }
738
+
739
+ if (!__type_matches__(definition.specification, value[field])) {
740
+ return fail(new StructError(
741
+ `"${name}.${field}" expected ${__type_label__(definition.specification)}, got ${type(value[field])}: ${previewValue(value[field])}`
742
+ ), {
743
+ name: name,
744
+ field: field,
745
+ expected: __type_label__(definition.specification),
746
+ got: type(value[field]),
747
+ fieldName: `${name}.${field}`
748
+ })
749
+ }
750
+ }
751
+
752
+ return returnMethod === "errorResult"
753
+ ? { success: true, result: value }
754
+ : value
755
+ }
756
+
757
+ export function __sizeof__(value) {
758
+ if (value === null || value === undefined) return 0
759
+ if (typeof value === "string") return value.length
760
+ if (Array.isArray(value)) return value.length
761
+ if (typeof value === "object") return Object.keys(value).length
762
+ if (typeof value === "number") return value.toString().length
763
+ if (typeof value === "boolean") return 1
764
+ return 0
765
+ }
766
+
767
+ export function __is_empty__(obj) {
768
+ if (__sizeof__(obj) == 0) {
769
+ return true
770
+ }
771
+ else {
772
+ return false
773
+ }
774
+ }
775
+
776
+ export function __copyof__(obj) {
777
+ if (Type.isObj(obj)) {
778
+ return { ...obj }
779
+ }
780
+ else if (Type.isAnyArray(obj)) {
781
+ const arrCopy = []
782
+ obj.forEach(item => arrCopy.push(item))
783
+ return arrCopy
784
+ }
785
+ else {
786
+ throw TypeError(`Copy target must be object or array, not ${type(obj)}`)
787
+ }
788
+ }
789
+
790
+ export function __intdiv__(a, b) {
791
+ return Math.trunc(a / b)
792
+ }
793
+
794
+ export function __match_eq__(subject, pattern) {
795
+ const a = subject instanceof EnumValue ? subject.value : subject
796
+ const b = pattern instanceof EnumValue ? pattern.value : pattern
797
+ return a === b
798
+ }
799
+
800
+ const IMMUTABLE = new WeakMap()
801
+
802
+ export function __lock_object__(obj) {
803
+ if (obj === null || typeof obj !== "object") return obj
804
+
805
+ if (IMMUTABLE.has(obj)) return IMMUTABLE.get(obj)
806
+
807
+ const handler = {
808
+ set() {
809
+ throw new Error("locked object mutation")
810
+ },
811
+ deleteProperty() {
812
+ throw new Error("locked object mutation")
813
+ },
814
+ defineProperty() {
815
+ throw new Error("locked object mutation")
816
+ },
817
+ setPrototypeOf() {
818
+ throw new Error("locked object mutation")
819
+ }
820
+ }
821
+
822
+ const wrapped = new Proxy(obj, handler)
823
+
824
+ IMMUTABLE.set(obj, wrapped)
825
+
826
+ const keys = Reflect.ownKeys(obj)
827
+
828
+ for (const key of keys) {
829
+ const value = obj[key]
830
+
831
+ if (value && typeof value === "object") {
832
+ obj[key] = __lock_object__(value)
833
+ }
834
+ }
835
+
836
+ Object.freeze(obj)
837
+
838
+ return wrapped
839
+ }
840
+
841
+ Object.assign(globalThis, {
842
+ log, warn, error, info, debug,
843
+
844
+ type,
845
+
846
+ Component, Type, Struct,
847
+
848
+ onError, test, assert, assertEqual,
849
+
850
+ __def_struct__, __def_enum__, __typed__, __handle_async_error__,
851
+ __handle_sync_error__, __sizeof__, __is_empty__, __lock_object__,
852
+ __typed_variable__, __typed_variable_check__, __typed_pattern__, __typed_return__,
853
+ __intdiv__, __copyof__, __match_eq__,
854
+ __typed_parameter__, __typed_static_field__, __typed_static_field_check__,
855
+ __type_def__, __argument_typed__,
856
+ __type_ref__, __type_spec__, __type_spec_all__, __type_matches__, __type_label__,
857
+
858
+ StructError, StructPassedError, StructExpectError, ArgumentDeclarationTypeError,
859
+
860
+ PI
861
+ })