correctly 0.0.0 → 0.1.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/AGENTS.md +6 -2
- package/README.md +21 -15
- package/dist/ajv.d.mts +11 -0
- package/dist/ajv.d.mts.map +1 -0
- package/dist/ajv.mjs +221 -0
- package/dist/ajv.mjs.map +1 -0
- package/dist/check-BI7U3ZLc.mjs +88 -0
- package/dist/check-BI7U3ZLc.mjs.map +1 -0
- package/dist/cli.mjs +14 -62
- package/dist/cli.mjs.map +1 -1
- package/dist/config-Bx1-XXeo.d.mts +189 -0
- package/dist/config-Bx1-XXeo.d.mts.map +1 -0
- package/dist/config-Cb6o4YnJ.mjs +348 -0
- package/dist/config-Cb6o4YnJ.mjs.map +1 -0
- package/dist/core.d.mts +27 -125
- package/dist/core.d.mts.map +1 -1
- package/dist/core.mjs +5 -2
- package/dist/diagnostics-BqD1WOy4.mjs +70 -0
- package/dist/diagnostics-BqD1WOy4.mjs.map +1 -0
- package/dist/engine-VST0hoSk.mjs +111 -0
- package/dist/engine-VST0hoSk.mjs.map +1 -0
- package/dist/extensions-ClclWslY.d.mts +11 -0
- package/dist/extensions-ClclWslY.d.mts.map +1 -0
- package/dist/hints-HvSIhuMM.mjs +57 -0
- package/dist/hints-HvSIhuMM.mjs.map +1 -0
- package/dist/lsp.mjs +40 -91
- package/dist/lsp.mjs.map +1 -1
- package/dist/renovate.d.mts +5 -0
- package/dist/renovate.d.mts.map +1 -0
- package/dist/renovate.mjs +11 -0
- package/dist/renovate.mjs.map +1 -0
- package/dist/schemas-UxCtIdo2.mjs +265 -0
- package/dist/schemas-UxCtIdo2.mjs.map +1 -0
- package/dist/session-DCFav56x.mjs +113 -0
- package/dist/session-DCFav56x.mjs.map +1 -0
- package/dist/worker.mjs +80 -0
- package/dist/worker.mjs.map +1 -0
- package/docs/guide.md +166 -34
- package/examples/basic/correctly.config.ts +13 -0
- package/package.json +69 -60
- package/src/cli/check.ts +41 -11
- package/src/cli/main.ts +3 -2
- package/src/cli/readable.ts +24 -5
- package/src/cli/vsix.ts +1 -0
- package/src/core/adapters.ts +54 -0
- package/src/core/config.ts +201 -64
- package/src/core/engine.ts +118 -218
- package/src/core/extensions.ts +144 -0
- package/src/core/index.ts +3 -0
- package/src/core/parse.ts +26 -2
- package/src/core/parsers.ts +22 -0
- package/src/core/schema-walk.ts +43 -0
- package/src/core/schemas.ts +21 -41
- package/src/core/types.ts +33 -6
- package/src/extensions/renovate.ts +4 -0
- package/src/lsp/hints.ts +22 -12
- package/src/lsp/server.ts +9 -2
- package/src/lsp/workspace.ts +49 -54
- package/src/runtime/session.ts +173 -0
- package/src/runtime/worker.ts +99 -0
- package/src/validators/ajv.ts +257 -0
- package/src/vscode/README.md +1 -1
- package/src/vscode/extension.ts +2 -4
- package/src/vscode/package.json +9 -2
- package/dist/engine-BgWBnb1A.mjs +0 -746
- package/dist/engine-BgWBnb1A.mjs.map +0 -1
- package/examples/basic/correctly.config.json +0 -10
- package/src/core/config.schema.json +0 -47
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-Cb6o4YnJ.mjs","names":[],"sources":["../src/core/parse.ts","../src/core/parsers.ts","../src/core/types.ts","../src/core/config.ts"],"sourcesContent":["import {\n\tfindNodeAtLocation,\n\tgetNodePath,\n\tgetNodeValue,\n\tparseTree,\n\tprintParseErrorCode,\n\ttype Node,\n\ttype ParseError,\n} from \"jsonc-parser\"\nimport type { Diagnostic, Position } from \"./types.ts\"\n\nexport type SourceSpan = { offset: number; length: number }\nexport type ParsedDocument = {\n\tvalue: unknown\n\tdiagnostics: Diagnostic[]\n\tlocate: (pointer: string, key?: boolean) => SourceSpan | undefined\n\t/** Exact numeric lexeme when the parser can preserve it. */\n\trawNumber?: (pointer: string) => string | undefined\n}\nexport type ParsedJsonDocument = ParsedDocument & { root: Node | undefined }\n\nexport function pointer(parts: readonly (string | number)[]): string {\n\treturn parts\n\t\t.map((p) => `/${String(p).replace(/~/g, \"~0\").replace(/\\//g, \"~1\")}`)\n\t\t.join(\"\")\n}\n\nexport function positionAt(text: string, offset: number): Position {\n\tconst end = Math.min(Math.max(0, offset), text.length)\n\tlet line = 0\n\tlet start = 0\n\tfor (let i = 0; i < end; i++) {\n\t\tif (text[i] === \"\\r\") {\n\t\t\tif (text[i + 1] === \"\\n\" && i + 1 < end) i++\n\t\t\tline++\n\t\t\tstart = i + 1\n\t\t} else if (text[i] === \"\\n\") {\n\t\t\tline++\n\t\t\tstart = i + 1\n\t\t}\n\t}\n\treturn { line, character: end - start }\n}\n\nexport function diagnostic(\n\ttext: string,\n\tcode: string,\n\tmessage: string,\n\tjsonPointer = \"\",\n\toffset = 0,\n\tlength = 1,\n): Diagnostic {\n\tconst start = Math.min(offset, text.length)\n\tconst size = Math.min(Math.max(1, length), text.length - start)\n\treturn {\n\t\tcode,\n\t\tmessage,\n\t\tpointer: jsonPointer,\n\t\toffset: start,\n\t\tlength: size,\n\t\trange: {\n\t\t\tstart: positionAt(text, start),\n\t\t\tend: positionAt(text, start + size),\n\t\t},\n\t}\n}\n\nexport function parseDocument(\n\ttext: string,\n\tmode: \"json\" | \"jsonc\",\n): ParsedJsonDocument {\n\tconst errors: ParseError[] = []\n\tconst root = parseTree(text, errors, {\n\t\tdisallowComments: mode === \"json\",\n\t\tallowTrailingComma: mode === \"jsonc\",\n\t\tallowEmptyContent: false,\n\t})\n\tconst diagnostics = errors.map((e) =>\n\t\tdiagnostic(\n\t\t\ttext,\n\t\t\t\"syntax\",\n\t\t\tprintParseErrorCode(e.error),\n\t\t\t\"\",\n\t\t\te.offset,\n\t\t\te.length,\n\t\t),\n\t)\n\tfunction visit(node: Node) {\n\t\tif (node.type === \"object\") {\n\t\t\tconst keys = new Set<string>()\n\t\t\tfor (const property of node.children ?? []) {\n\t\t\t\tconst key = property.children?.[0]\n\t\t\t\tif (!key || typeof key.value !== \"string\") continue\n\t\t\t\tif (keys.has(key.value)) {\n\t\t\t\t\tdiagnostics.push(\n\t\t\t\t\t\tdiagnostic(\n\t\t\t\t\t\t\ttext,\n\t\t\t\t\t\t\t\"duplicate-key\",\n\t\t\t\t\t\t\t`Duplicate key ${JSON.stringify(key.value)}`,\n\t\t\t\t\t\t\tpointer([...getNodePath(node), key.value]),\n\t\t\t\t\t\t\tkey.offset,\n\t\t\t\t\t\t\tkey.length,\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tkeys.add(key.value)\n\t\t\t}\n\t\t}\n\t\tif (node.type === \"number\" && !Number.isFinite(node.value)) {\n\t\t\tdiagnostics.push(\n\t\t\t\tdiagnostic(\n\t\t\t\t\ttext,\n\t\t\t\t\t\"syntax\",\n\t\t\t\t\t\"Number exceeds the supported finite range\",\n\t\t\t\t\tpointer(getNodePath(node)),\n\t\t\t\t\tnode.offset,\n\t\t\t\t\tnode.length,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t\tfor (const child of node.children ?? []) visit(child)\n\t}\n\tif (root) visit(root)\n\t// jsonc-parser's object values have null prototypes. Ajv's deep equality\n\t// expects ordinary JSON objects; Object.fromEntries safely preserves __proto__.\n\tfunction value(node: Node): unknown {\n\t\tif (node.type === \"object\")\n\t\t\treturn Object.fromEntries(\n\t\t\t\t(node.children ?? []).flatMap((property) => {\n\t\t\t\t\tconst key = property.children?.[0]\n\t\t\t\t\tconst child = property.children?.[1]\n\t\t\t\t\treturn key && child ? [[String(key.value), value(child)]] : []\n\t\t\t\t}),\n\t\t\t)\n\t\tif (node.type === \"array\") return (node.children ?? []).map(value)\n\t\treturn getNodeValue(node) as unknown\n\t}\n\treturn {\n\t\troot,\n\t\tvalue: root ? value(root) : undefined,\n\t\tdiagnostics,\n\t\trawNumber: (jsonPointer) => {\n\t\t\tconst parts =\n\t\t\t\tjsonPointer === \"\"\n\t\t\t\t\t? []\n\t\t\t\t\t: jsonPointer\n\t\t\t\t\t\t\t.slice(1)\n\t\t\t\t\t\t\t.split(\"/\")\n\t\t\t\t\t\t\t.map((p) => p.replace(/~1/g, \"/\").replace(/~0/g, \"~\"))\n\t\t\tlet node = root\n\t\t\tfor (const part of parts) {\n\t\t\t\tif (!node) break\n\t\t\t\tnode = findNodeAtLocation(node, [\n\t\t\t\t\tnode.type === \"array\" ? Number(part) : part,\n\t\t\t\t])\n\t\t\t}\n\t\t\treturn node?.type === \"number\"\n\t\t\t\t? text.slice(node.offset, node.offset + node.length)\n\t\t\t\t: undefined\n\t\t},\n\t\tlocate: (jsonPointer, key = false) => {\n\t\t\tconst node = locate(root, jsonPointer, key)\n\t\t\treturn node ? { offset: node.offset, length: node.length } : undefined\n\t\t},\n\t}\n}\n\nexport function locate(\n\troot: Node | undefined,\n\tjsonPointer: string,\n\tkey = false,\n): Node | undefined {\n\tif (!root) return undefined\n\tconst parts =\n\t\tjsonPointer === \"\"\n\t\t\t? []\n\t\t\t: jsonPointer\n\t\t\t\t\t.slice(1)\n\t\t\t\t\t.split(\"/\")\n\t\t\t\t\t.map((p) => p.replace(/~1/g, \"/\").replace(/~0/g, \"~\"))\n\tlet current = root\n\tfor (const part of parts) {\n\t\tconst next = findNodeAtLocation(current, [\n\t\t\tcurrent.type === \"array\" ? Number(part) : part,\n\t\t])\n\t\tif (!next) break\n\t\tcurrent = next\n\t}\n\treturn key && current.parent?.type === \"property\"\n\t\t? (current.parent.children?.[0] ?? current)\n\t\t: current\n}\n","import type { Parser } from \"./adapters.ts\"\nimport { parseDocument } from \"./parse.ts\"\n\nexport function json(): Parser {\n\treturn {\n\t\tid: \"json\",\n\t\tvalueModel: \"json\",\n\t\teditorLanguage: \"json\",\n\t\tparse: (text) => parseDocument(text, \"json\"),\n\t}\n}\nexport function jsonc(): Parser {\n\treturn {\n\t\tid: \"jsonc\",\n\t\tvalueModel: \"json\",\n\t\teditorLanguage: \"jsonc\",\n\t\tparse: (text) => parseDocument(text, \"jsonc\"),\n\t}\n}\nexport function defaultParser(file: string): Parser {\n\treturn file.toLowerCase().endsWith(\".jsonc\") ? jsonc() : json()\n}\n","export type Mode = string\nexport type Position = { line: number; character: number }\nexport type Range = { start: Position; end: Position }\nexport type Diagnostic = {\n\tcode: string\n\tmessage: string\n\tpointer: string\n\toffset: number\n\tlength: number\n\trange: Range\n\tcontext?: { parent: number; label: string }\n}\nexport type ExtensionRequirement = {\n\tschemaUri: string\n\tschemaPointer: string\n\tformat: string\n\tsuggestedExtension?: string\n}\nexport type Failure = {\n\tcode: string\n\tmessage: string\n\tfile?: string\n\tdetails?: ExtensionRequirement\n}\nexport class CorrectlyError extends Error {\n\treadonly code: string\n\treadonly details?: ExtensionRequirement\n\tconstructor(code: string, message: string, details?: ExtensionRequirement) {\n\t\tsuper(message)\n\t\tthis.name = \"CorrectlyError\"\n\t\tthis.code = code\n\t\tif (details) this.details = details\n\t}\n}\nexport function isCorrectlyError(error: unknown): error is CorrectlyError {\n\treturn (\n\t\terror instanceof Error &&\n\t\terror.name === \"CorrectlyError\" &&\n\t\t\"code\" in error &&\n\t\ttypeof error.code === \"string\"\n\t)\n}\nexport function failure(error: unknown, file?: string): Failure {\n\treturn {\n\t\tcode: isCorrectlyError(error) ? error.code : \"execution\",\n\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t...(file === undefined ? {} : { file }),\n\t\t...(isCorrectlyError(error) && error.details\n\t\t\t? { details: error.details }\n\t\t\t: {}),\n\t}\n}\nexport type Association = {\n\tindex: number\n\tname: string\n\tschema: string | null\n\tvalidator: string | null\n\tmode: Mode\n\textensions?: string[]\n}\nexport type FileResult = {\n\tfile: string\n\tmode: Mode\n\tcoverage: \"schema\" | \"validated\" | \"syntax-only\" | \"excluded\"\n\tassociation: Association | null\n\tdiagnostics: Diagnostic[]\n\tfailures: Failure[]\n}\nexport type Report = {\n\treportVersion: 2\n\tconfig: string | null\n\tfiles: FileResult[]\n\tfailures: Failure[]\n\tsummary: {\n\t\tchecked: number\n\t\tvalidated: number\n\t\tschemaCovered: number\n\t\tsyntaxOnly: number\n\t\tinvalid: number\n\t\tfailures: number\n\t}\n\texitCode: 0 | 1 | 2\n}\n","import { readFile, stat } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { fileURLToPath, pathToFileURL } from \"node:url\"\nimport { cli } from \"comline\"\nimport picomatch from \"picomatch\"\nimport type { Parser, Validator } from \"./adapters.ts\"\nimport { defaultParser } from \"./parsers.ts\"\nimport { CorrectlyError, type Association } from \"./types.ts\"\n\nexport const CONFIG_NAME = \"correctly.config.ts\"\nexport const DEFAULT_EXCLUDES = [\n\t\"**/node_modules/**\",\n\t\"**/.git/**\",\n\t\"**/dist/**\",\n\t\"**/artifacts/**\",\n\t\"**/.correctly-cache/**\",\n]\nexport type RemoteOptions = {\n\toffline?: boolean\n\tcacheDir?: string\n\ttimeoutMs?: number\n\tmaxBytes?: number\n\tmaxRequests?: number\n}\nexport type ProjectConfig = {\n\tfiles?: string[]\n\texclude?: string[]\n\tassociations: {\n\t\tname?: string\n\t\tfiles: string[]\n\t\tparse?: Parser\n\t\tvalidate: Validator | null\n\t}[]\n\tremote?: RemoteOptions\n}\nexport type Project = {\n\tconfigPath: string\n\troot: string\n\tconfig: ProjectConfig\n}\nexport type ReadText = (uri: string) => Promise<string>\nexport const readText: ReadText = (uri) => readFile(fileURLToPath(uri), \"utf8\")\n\nfunction object(\n\tvalue: unknown,\n\tlocation: string,\n\tkeys?: string[],\n): asserts value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value))\n\t\tthrow new CorrectlyError(\"config\", `${location} must be an object`)\n\tif (keys)\n\t\tfor (const key of Object.keys(value))\n\t\t\tif (!keys.includes(key))\n\t\t\t\tthrow new CorrectlyError(\"config\", `Unknown option ${location}.${key}`)\n}\nfunction string(value: unknown, location: string): asserts value is string {\n\tif (typeof value !== \"string\" || !value.length)\n\t\tthrow new CorrectlyError(\"config\", `${location} must be a nonempty string`)\n}\nfunction patterns(value: unknown, location: string): void {\n\tif (!Array.isArray(value) || !value.length)\n\t\tthrow new CorrectlyError(\n\t\t\t\"config\",\n\t\t\t`${location} must be a nonempty array of relative patterns`,\n\t\t)\n\tfor (const item of value) {\n\t\tstring(item, location)\n\t\tif (/^(?:[!/]|[A-Za-z]:)|(?:^|\\/)\\.\\.(?:\\/|$)|\\\\/.test(item))\n\t\t\tthrow new CorrectlyError(\n\t\t\t\t\"config\",\n\t\t\t\t`${location}: use relative forward-slash patterns without '..' or leading '!': ${item}`,\n\t\t\t)\n\t}\n}\nexport function defineConfig<T extends ProjectConfig>(config: T): T {\n\tvalidateConfig(config)\n\treturn config\n}\nexport function validateConfig(value: unknown): ProjectConfig {\n\tobject(value, \"config\", [\"files\", \"exclude\", \"associations\", \"remote\"])\n\tfor (const key of [\"files\", \"exclude\"])\n\t\tif (value[key] !== undefined) patterns(value[key], key)\n\tif (!Array.isArray(value.associations))\n\t\tthrow new CorrectlyError(\"config\", \"associations must be an array\")\n\tfor (const [index, rule] of value.associations.entries()) {\n\t\tconst at = `associations[${index}]`\n\t\tobject(rule, at, [\"name\", \"files\", \"parse\", \"validate\"])\n\t\tpatterns(rule.files, `${at}.files`)\n\t\tif (rule.name !== undefined) string(rule.name, `${at}.name`)\n\t\tif (rule.parse !== undefined) {\n\t\t\tobject(rule.parse, `${at}.parse`)\n\t\t\tstring(rule.parse.id, `${at}.parse.id`)\n\t\t\tstring(rule.parse.valueModel, `${at}.parse.valueModel`)\n\t\t\tif (typeof rule.parse.parse !== \"function\")\n\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\"config\",\n\t\t\t\t\t`${at}.parse must be a parser adapter`,\n\t\t\t\t)\n\t\t\tif (\n\t\t\t\trule.parse.editorLanguage !== undefined &&\n\t\t\t\trule.parse.editorLanguage !== \"json\" &&\n\t\t\t\trule.parse.editorLanguage !== \"jsonc\"\n\t\t\t)\n\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\"config\",\n\t\t\t\t\t`${at}.parse.editorLanguage must be json or jsonc`,\n\t\t\t\t)\n\t\t}\n\t\tif (rule.validate !== null) {\n\t\t\tobject(rule.validate, `${at}.validate`)\n\t\t\tstring(rule.validate.id, `${at}.validate.id`)\n\t\t\tif (\n\t\t\t\ttypeof rule.validate.prepare !== \"function\" ||\n\t\t\t\t!Array.isArray(rule.validate.accepts) ||\n\t\t\t\t!rule.validate.accepts.length ||\n\t\t\t\trule.validate.accepts.some((v: unknown) => typeof v !== \"string\" || !v)\n\t\t\t)\n\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\"config\",\n\t\t\t\t\t`${at}.validate must be a validator adapter with accepted value models`,\n\t\t\t\t)\n\t\t\tif (\n\t\t\t\trule.validate.register !== undefined &&\n\t\t\t\ttypeof rule.validate.register !== \"function\"\n\t\t\t)\n\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\"config\",\n\t\t\t\t\t`${at}.validate.register must be a function`,\n\t\t\t\t)\n\t\t\tif (rule.validate.extensions !== undefined) {\n\t\t\t\tif (!Array.isArray(rule.validate.extensions))\n\t\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\t\"config\",\n\t\t\t\t\t\t`${at}.validate.extensions must be an array`,\n\t\t\t\t\t)\n\t\t\t\tfor (const extension of rule.validate.extensions) {\n\t\t\t\t\tobject(extension, `${at}.validate.extensions[]`)\n\t\t\t\t\tstring(extension.id, `${at}.validate.extensions[].id`)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (rule.validate.schema !== undefined)\n\t\t\t\tstring(rule.validate.schema, `${at}.validate.schema`)\n\t\t}\n\t}\n\tif (value.remote !== undefined) {\n\t\tobject(value.remote, \"remote\", [\n\t\t\t\"offline\",\n\t\t\t\"cacheDir\",\n\t\t\t\"timeoutMs\",\n\t\t\t\"maxBytes\",\n\t\t\t\"maxRequests\",\n\t\t])\n\t\tif (\n\t\t\tvalue.remote.offline !== undefined &&\n\t\t\ttypeof value.remote.offline !== \"boolean\"\n\t\t)\n\t\t\tthrow new CorrectlyError(\"config\", \"remote.offline must be a boolean\")\n\t\tif (value.remote.cacheDir !== undefined)\n\t\t\tstring(value.remote.cacheDir, \"remote.cacheDir\")\n\t\tfor (const [key, max] of [\n\t\t\t[\"timeoutMs\", 60000],\n\t\t\t[\"maxBytes\", 16777216],\n\t\t\t[\"maxRequests\", 256],\n\t\t] as const) {\n\t\t\tconst number = value.remote[key]\n\t\t\tif (\n\t\t\t\tnumber !== undefined &&\n\t\t\t\t(typeof number !== \"number\" ||\n\t\t\t\t\t!Number.isInteger(number) ||\n\t\t\t\t\tnumber < 1 ||\n\t\t\t\t\tnumber > max)\n\t\t\t)\n\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\"config\",\n\t\t\t\t\t`remote.${key} must be an integer between 1 and ${max}`,\n\t\t\t\t)\n\t\t}\n\t}\n\treturn value as ProjectConfig\n}\nexport function contains(root: string, file: string): boolean {\n\tconst relative = path.relative(root, file)\n\treturn (\n\t\trelative !== \"..\" &&\n\t\t!relative.startsWith(`..${path.sep}`) &&\n\t\t!path.isAbsolute(relative)\n\t)\n}\nexport async function discoverConfig(\n\tstart: string,\n\tboundary?: string,\n): Promise<string> {\n\tlet directory = path.resolve(start)\n\tif (boundary && !contains(boundary, directory))\n\t\tthrow new CorrectlyError(\"config\", `Path is outside workspace ${boundary}`)\n\twhile (true) {\n\t\tconst candidate = path.join(directory, CONFIG_NAME)\n\t\ttry {\n\t\t\tif ((await stat(candidate)).isFile()) return candidate\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n\t\t}\n\t\tconst parent = path.dirname(directory)\n\t\tif (directory === boundary || parent === directory) break\n\t\tdirectory = parent\n\t}\n\tthrow new CorrectlyError(\n\t\t\"config\",\n\t\t`No ${CONFIG_NAME} found from ${start}${boundary ? ` within ${boundary}` : \"\"}`,\n\t)\n}\n/** Comline owns module loading and invokes our runtime contract validation. */\nexport async function loadProject(configPath: string): Promise<Project> {\n\tconst resolved = path.resolve(configPath)\n\ttry {\n\t\tif (path.extname(resolved) !== \".ts\")\n\t\t\tthrow new Error(\"Correctly configuration must be a TypeScript .ts module\")\n\t\tif (!(await stat(resolved)).isFile())\n\t\t\tthrow new Error(\"Configuration must be a file\")\n\t\tconst schema = {\n\t\t\t\"~standard\": {\n\t\t\t\tversion: 1 as const,\n\t\t\t\tvendor: \"correctly\",\n\t\t\t\tvalidate: (value: unknown) => ({ value: validateConfig(value) }),\n\t\t\t\tjsonSchema: {\n\t\t\t\t\tinput: () => ({ type: \"object\" }),\n\t\t\t\t\toutput: () => ({ type: \"object\" }),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tconst parse = cli({\n\t\t\tcliName: \"correctly\",\n\t\t\tdiscoverConfigPath: () => resolved,\n\t\t\trouteOptions: {\n\t\t\t\t\"\": {\n\t\t\t\t\tdescription: \"Correctly configuration\",\n\t\t\t\t\toptionsSchema: schema,\n\t\t\t\t\toptionConfigs: {},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\tconst config = validateConfig(\n\t\t\tparse([process.execPath, \"correctly\"]).inputs.opts,\n\t\t)\n\t\treturn { configPath: resolved, root: path.dirname(resolved), config }\n\t} catch (error) {\n\t\tthrow new CorrectlyError(\n\t\t\t\"config\",\n\t\t\t`Cannot load ${resolved}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t)\n\t}\n}\n\nexport function schemaUri(value: string, root: string): string {\n\tif (\n\t\t/^[A-Za-z][A-Za-z\\d+.-]*:/.test(value) &&\n\t\t!/^[A-Za-z]:[\\\\/]/.test(value)\n\t) {\n\t\tconst uri = new URL(value)\n\t\tif (![\"file:\", \"http:\", \"https:\"].includes(uri.protocol))\n\t\t\tthrow new CorrectlyError(\n\t\t\t\t\"schema\",\n\t\t\t\t`Unsupported schema protocol: ${uri.protocol}`,\n\t\t\t)\n\t\treturn uri.href\n\t}\n\tconst hash = value.indexOf(\"#\")\n\tconst filename = hash === -1 ? value : value.slice(0, hash)\n\tconst uri = pathToFileURL(path.resolve(root, filename))\n\tif (hash !== -1) uri.hash = value.slice(hash + 1)\n\treturn uri.href\n}\n\nexport function exclusions(project: Project): string[] {\n\tconst cachePath = path.resolve(\n\t\tproject.root,\n\t\tproject.config.remote?.cacheDir ?? \".correctly-cache\",\n\t)\n\tconst relative = path\n\t\t.relative(project.root, cachePath)\n\t\t.split(path.sep)\n\t\t.join(\"/\")\n\treturn [\n\t\t...DEFAULT_EXCLUDES,\n\t\t...(project.config.exclude ?? []),\n\t\t...(relative && contains(project.root, cachePath)\n\t\t\t? [`${relative}/**`]\n\t\t\t: []),\n\t]\n}\n\nexport function isIncluded(project: Project, file: string): boolean {\n\tif (!contains(project.root, file)) return false\n\tconst relative = path.relative(project.root, file).split(path.sep).join(\"/\")\n\tconst options = { dot: true }\n\treturn (\n\t\tpicomatch(\n\t\t\tproject.config.files ?? [\"**/*.json\", \"**/*.jsonc\"],\n\t\t\toptions,\n\t\t)(relative) && !picomatch(exclusions(project), options)(relative)\n\t)\n}\n\nexport function associationFor(\n\tproject: Project,\n\tfile: string,\n): Association | null {\n\tconst relative = path.relative(project.root, file).split(path.sep).join(\"/\")\n\tfor (\n\t\tlet index = project.config.associations.length - 1;\n\t\tindex >= 0;\n\t\tindex--\n\t) {\n\t\tconst rule = project.config.associations[index]!\n\t\tif (picomatch(rule.files, { dot: true })(relative))\n\t\t\treturn {\n\t\t\t\tindex,\n\t\t\t\tname: rule.name ?? `association ${index + 1}`,\n\t\t\t\tmode: (rule.parse ?? defaultParser(file)).id,\n\t\t\t\tschema: rule.validate?.schema\n\t\t\t\t\t? schemaUri(rule.validate.schema, project.root)\n\t\t\t\t\t: null,\n\t\t\t\tvalidator: rule.validate?.id ?? null,\n\t\t\t\t...(rule.validate?.extensions\n\t\t\t\t\t? {\n\t\t\t\t\t\t\textensions: rule.validate.extensions.map(\n\t\t\t\t\t\t\t\t(extension) => extension.id,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t}\n\t}\n\treturn null\n}\nexport function modeFor(file: string): string {\n\treturn defaultParser(file).id\n}\n"],"mappings":"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"}
|
package/dist/core.d.mts
CHANGED
|
@@ -1,121 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
//#region src/core/types.d.ts
|
|
4
|
-
export type Mode = "json" | "jsonc";
|
|
5
|
-
export type Position = {
|
|
6
|
-
line: number;
|
|
7
|
-
character: number;
|
|
8
|
-
};
|
|
9
|
-
export type Range = {
|
|
10
|
-
start: Position;
|
|
11
|
-
end: Position;
|
|
12
|
-
};
|
|
13
|
-
export type Diagnostic = {
|
|
14
|
-
code: string;
|
|
15
|
-
message: string;
|
|
16
|
-
pointer: string;
|
|
17
|
-
offset: number;
|
|
18
|
-
length: number;
|
|
19
|
-
range: Range;
|
|
20
|
-
context?: {
|
|
21
|
-
parent: number;
|
|
22
|
-
label: string;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
export type Failure = {
|
|
26
|
-
code: string;
|
|
27
|
-
message: string;
|
|
28
|
-
file?: string;
|
|
29
|
-
};
|
|
30
|
-
export declare class CorrectlyError extends Error {
|
|
31
|
-
readonly code: string;
|
|
32
|
-
constructor(code: string, message: string);
|
|
33
|
-
}
|
|
34
|
-
export declare function failure(error: unknown, file?: string): Failure;
|
|
35
|
-
export type Association = {
|
|
36
|
-
index: number;
|
|
37
|
-
name: string;
|
|
38
|
-
schema: string | null;
|
|
39
|
-
mode: Mode;
|
|
40
|
-
};
|
|
41
|
-
export type FileResult = {
|
|
42
|
-
file: string;
|
|
43
|
-
mode: Mode;
|
|
44
|
-
coverage: "schema" | "syntax-only" | "excluded";
|
|
45
|
-
association: Association | null;
|
|
46
|
-
diagnostics: Diagnostic[];
|
|
47
|
-
failures: Failure[];
|
|
48
|
-
};
|
|
49
|
-
export type Report = {
|
|
50
|
-
reportVersion: 1;
|
|
51
|
-
config: string | null;
|
|
52
|
-
files: FileResult[];
|
|
53
|
-
failures: Failure[];
|
|
54
|
-
summary: {
|
|
55
|
-
checked: number;
|
|
56
|
-
schemaCovered: number;
|
|
57
|
-
syntaxOnly: number;
|
|
58
|
-
invalid: number;
|
|
59
|
-
failures: number;
|
|
60
|
-
};
|
|
61
|
-
exitCode: 0 | 1 | 2;
|
|
62
|
-
};
|
|
63
|
-
//#endregion
|
|
64
|
-
//#region src/core/parse.d.ts
|
|
65
|
-
export type SourceSpan = {
|
|
66
|
-
offset: number;
|
|
67
|
-
length: number;
|
|
68
|
-
};
|
|
69
|
-
export type ParsedDocument = {
|
|
70
|
-
value: unknown;
|
|
71
|
-
diagnostics: Diagnostic[];
|
|
72
|
-
locate: (pointer: string, key?: boolean) => SourceSpan | undefined;
|
|
73
|
-
};
|
|
74
|
-
export type ParsedJsonDocument = ParsedDocument & {
|
|
75
|
-
root: Node | undefined;
|
|
76
|
-
};
|
|
77
|
-
export declare function pointer(parts: readonly (string | number)[]): string;
|
|
78
|
-
export declare function positionAt(text: string, offset: number): Position;
|
|
79
|
-
export declare function diagnostic(text: string, code: string, message: string, jsonPointer?: string, offset?: number, length?: number): Diagnostic;
|
|
80
|
-
export declare function parseDocument(text: string, mode: Mode): ParsedJsonDocument;
|
|
81
|
-
export declare function locate(root: Node | undefined, jsonPointer: string, key?: boolean): Node | undefined;
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region src/core/config.d.ts
|
|
84
|
-
export declare const CONFIG_NAME = "correctly.config.json";
|
|
85
|
-
export declare const DEFAULT_EXCLUDES: string[];
|
|
86
|
-
export type ProjectConfig = {
|
|
87
|
-
files?: string[];
|
|
88
|
-
exclude?: string[];
|
|
89
|
-
associations: {
|
|
90
|
-
name?: string;
|
|
91
|
-
files: string[];
|
|
92
|
-
schema: string | null;
|
|
93
|
-
mode?: Mode;
|
|
94
|
-
}[];
|
|
95
|
-
remote?: {
|
|
96
|
-
offline?: boolean;
|
|
97
|
-
cacheDir?: string;
|
|
98
|
-
timeoutMs?: number;
|
|
99
|
-
maxBytes?: number;
|
|
100
|
-
maxRequests?: number;
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
|
-
export type Project = {
|
|
104
|
-
configPath: string;
|
|
105
|
-
root: string;
|
|
106
|
-
config: ProjectConfig;
|
|
107
|
-
};
|
|
108
|
-
export type ReadText = (uri: string) => Promise<string>;
|
|
109
|
-
export declare const readText: ReadText;
|
|
110
|
-
export declare function contains(root: string, file: string): boolean;
|
|
111
|
-
export declare function discoverConfig(start: string, boundary?: string, virtualFiles?: ReadonlySet<string>): Promise<string>;
|
|
112
|
-
export declare function loadProject(configPath: string, read?: ReadText): Promise<Project>;
|
|
113
|
-
export declare function schemaUri(value: string, root: string): string;
|
|
114
|
-
export declare function exclusions(project: Project): string[];
|
|
115
|
-
export declare function isIncluded(project: Project, file: string): boolean;
|
|
116
|
-
export declare function associationFor(project: Project, file: string): Association | null;
|
|
117
|
-
export declare function modeFor(file: string): Mode;
|
|
118
|
-
//#endregion
|
|
1
|
+
import { A as pointer, B as Range, C as Validator, D as diagnostic, E as SourceSpan, F as ExtensionRequirement, H as failure, I as Failure, L as FileResult, M as Association, N as CorrectlyError, O as locate, P as Diagnostic, R as Mode, S as ValidationInput, T as ParsedJsonDocument, U as isCorrectlyError, V as Report, _ as validateConfig, a as ReadText, b as PreparedValidator, c as contains, d as exclusions, f as isIncluded, g as schemaUri, h as readText, i as ProjectConfig, j as positionAt, k as parseDocument, l as defineConfig, m as modeFor, n as DEFAULT_EXCLUDES, o as RemoteOptions, p as loadProject, r as Project, s as associationFor, t as CONFIG_NAME, u as discoverConfig, v as JsonSchemaEditorSupport, w as ParsedDocument, x as ValidationContext, y as Parser, z as Position } from "./config-Bx1-XXeo.mjs";
|
|
2
|
+
import { AnySchema } from "ajv";
|
|
119
3
|
//#region src/core/schemas.d.ts
|
|
120
4
|
export type Dialect = "draft7" | "2020-12";
|
|
121
5
|
export declare const DIALECTS: {
|
|
@@ -126,6 +10,7 @@ export type SchemaResource = {
|
|
|
126
10
|
uri: string;
|
|
127
11
|
schema: AnySchema;
|
|
128
12
|
dialect: Dialect;
|
|
13
|
+
pointer?: string;
|
|
129
14
|
};
|
|
130
15
|
export type StoreOptions = {
|
|
131
16
|
offline?: boolean;
|
|
@@ -145,7 +30,9 @@ export declare class SchemaStore {
|
|
|
145
30
|
private readonly read;
|
|
146
31
|
private readonly request;
|
|
147
32
|
private requests;
|
|
148
|
-
constructor(project: Project,
|
|
33
|
+
constructor(project: Pick<Project, "root"> & {
|
|
34
|
+
config: Pick<Project["config"], "remote">;
|
|
35
|
+
}, options?: StoreOptions);
|
|
149
36
|
load(value: string, inherited?: Dialect): Promise<SchemaResource>;
|
|
150
37
|
private loadResource;
|
|
151
38
|
private register;
|
|
@@ -155,15 +42,25 @@ export declare class SchemaStore {
|
|
|
155
42
|
export declare function localSchemaPath(uri: string): string | undefined;
|
|
156
43
|
//#endregion
|
|
157
44
|
//#region src/core/engine.d.ts
|
|
45
|
+
export type EngineOptions = StoreOptions & {
|
|
46
|
+
onDependency?: (uri: string) => void;
|
|
47
|
+
};
|
|
158
48
|
export declare class Engine {
|
|
159
49
|
readonly project: Project;
|
|
160
|
-
readonly
|
|
161
|
-
private readonly
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
private
|
|
50
|
+
readonly context: ValidationContext;
|
|
51
|
+
private readonly prepared;
|
|
52
|
+
private registration;
|
|
53
|
+
constructor(project: Project, options?: EngineOptions);
|
|
54
|
+
private register;
|
|
55
|
+
private validator;
|
|
165
56
|
prepare(): Promise<void>;
|
|
57
|
+
editor(file: string): Promise<{
|
|
58
|
+
support: JsonSchemaEditorSupport;
|
|
59
|
+
language: "json" | "jsonc";
|
|
60
|
+
association: number;
|
|
61
|
+
} | undefined>;
|
|
166
62
|
validate(file: string, text: string): Promise<FileResult>;
|
|
63
|
+
dispose(): Promise<void>;
|
|
167
64
|
}
|
|
168
65
|
//#endregion
|
|
169
66
|
//#region src/core/diagnostics.d.ts
|
|
@@ -179,5 +76,10 @@ export declare function diagnosticDetails(view: DiagnosticView): {
|
|
|
179
76
|
diagnostic: DiagnosticView;
|
|
180
77
|
}[];
|
|
181
78
|
//#endregion
|
|
182
|
-
|
|
79
|
+
//#region src/core/parsers.d.ts
|
|
80
|
+
export declare function json(): Parser;
|
|
81
|
+
export declare function jsonc(): Parser;
|
|
82
|
+
export declare function defaultParser(file: string): Parser;
|
|
83
|
+
//#endregion
|
|
84
|
+
export { Association, CONFIG_NAME, CorrectlyError, DEFAULT_EXCLUDES, Diagnostic, type DiagnosticView, ExtensionRequirement, Failure, FileResult, JsonSchemaEditorSupport, Mode, ParsedDocument, ParsedJsonDocument, Parser, Position, PreparedValidator, Project, ProjectConfig, Range, ReadText, RemoteOptions, Report, SourceSpan, ValidationContext, ValidationInput, Validator, associationFor, contains, defineConfig, diagnostic, discoverConfig, exclusions, failure, isCorrectlyError, isIncluded, loadProject, locate, modeFor, parseDocument, pointer, positionAt, readText, schemaUri, validateConfig };
|
|
183
85
|
//# sourceMappingURL=core.d.mts.map
|
package/dist/core.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.mts","names":[],"sources":["../src/core/
|
|
1
|
+
{"version":3,"file":"core.d.mts","names":["_$__adapters_ts0.JsonSchemaEditorSupport"],"sources":["../src/core/schemas.ts","../src/core/engine.ts","../src/core/diagnostics.ts","../src/core/parsers.ts"],"mappings":";;;YAUY;qBACC;WACZ;WACA;;YAkCW;EACX;EACA,QAAQ;EACR,SAAS;EACT;;YAQW;EACX;EACA,OAAO;EACP,eAAe;EACf,SAAS;;qBAGG;mBACK;WACR,WAAS,YAAA;mBACD;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;UACT;EACR,YACC,SAAS,KAAK;IACb,QAAQ,KAAK;KAEd,UAAS;EAgBJ,KACL,eACA,YAAW,UACT,QAAQ;UAeG;UA2DN;UAOA;UA+DM;;wBA8GC,gBAAgB;;;YCzVpB,gBAAgB;EAC3B,gBAAgB;;qBAEJ;WACH,SAAS;WACT,SAAS;mBACD;UACT;EACR,YAAY,SAAS,SAAS,UAAS;UAoB/B;UAMA;EAiBF,WAAW;EAaX,OAAO,eAAY;aAbRA;;;;EA8BX,SAAS,cAAc,eAAe,QAAQ;EAiD9C,WAAW;;;;KCzIN,iBAAiB;EAC5B;IAAY;IAAe,aAAa;;;wBAiEzB,gBACf,sBAAsB,eACpB;wBA8Ba,kBACf,MAAM;EACF;EAAe,YAAY;;;;wBCpGhB,QAAQ;wBAQR,SAAS;wBAQT,cAAc,eAAe"}
|
package/dist/core.mjs
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import { C as pointer, S as parseDocument, _ as
|
|
2
|
-
|
|
1
|
+
import { C as pointer, S as parseDocument, _ as defaultParser, a as defineConfig, b as diagnostic, c as isIncluded, d as readText, f as schemaUri, g as isCorrectlyError, h as failure, i as contains, l as loadProject, m as CorrectlyError, n as DEFAULT_EXCLUDES, o as discoverConfig, p as validateConfig, r as associationFor, s as exclusions, t as CONFIG_NAME, u as modeFor, v as json, w as positionAt, x as locate, y as jsonc } from "./config-Cb6o4YnJ.mjs";
|
|
2
|
+
import { n as diagnosticViews, t as diagnosticDetails } from "./diagnostics-BqD1WOy4.mjs";
|
|
3
|
+
import { n as SchemaStore, r as localSchemaPath, t as DIALECTS } from "./schemas-UxCtIdo2.mjs";
|
|
4
|
+
import { t as Engine } from "./engine-VST0hoSk.mjs";
|
|
5
|
+
export { CONFIG_NAME, CorrectlyError, DEFAULT_EXCLUDES, DIALECTS, Engine, SchemaStore, associationFor, contains, defaultParser, defineConfig, diagnostic, diagnosticDetails, diagnosticViews, discoverConfig, exclusions, failure, isCorrectlyError, isIncluded, json, jsonc, loadProject, localSchemaPath, locate, modeFor, parseDocument, pointer, positionAt, readText, schemaUri, validateConfig };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/core/diagnostics.ts
|
|
2
|
+
function validationContexts(errors, diagnostics) {
|
|
3
|
+
const summaries = errors.flatMap((error, index) => {
|
|
4
|
+
if (error.keyword === "anyOf" || error.keyword === "oneOf") return [{
|
|
5
|
+
index,
|
|
6
|
+
error,
|
|
7
|
+
prefix: `${error.schemaPath}/`,
|
|
8
|
+
alternative: true
|
|
9
|
+
}];
|
|
10
|
+
if (error.keyword === "if" && ["then", "else"].includes(error.params.failingKeyword)) return [{
|
|
11
|
+
index,
|
|
12
|
+
error,
|
|
13
|
+
prefix: `${error.schemaPath.slice(0, -3)}/${error.params.failingKeyword}`,
|
|
14
|
+
alternative: false
|
|
15
|
+
}];
|
|
16
|
+
return [];
|
|
17
|
+
});
|
|
18
|
+
return diagnostics.map((diagnostic, index) => {
|
|
19
|
+
const error = errors[index];
|
|
20
|
+
const parent = summaries.filter((parent) => parent.index > index && (error.instancePath === parent.error.instancePath || error.instancePath.startsWith(`${parent.error.instancePath}/`)) && (parent.error.propertyName === void 0 || error.propertyName === parent.error.propertyName) && (parent.alternative ? error.schemaPath.startsWith(parent.prefix) : error.schemaPath === parent.prefix || error.schemaPath.startsWith(`${parent.prefix}/`))).toSorted((a, b) => b.prefix.length - a.prefix.length || a.index - b.index)[0];
|
|
21
|
+
if (!parent) return diagnostic;
|
|
22
|
+
const branch = parent.alternative ? error.schemaPath.slice(parent.prefix.length).split("/")[0] : parent.error.params.failingKeyword;
|
|
23
|
+
if (parent.alternative && !/^\d+$/.test(branch)) return diagnostic;
|
|
24
|
+
return {
|
|
25
|
+
...diagnostic,
|
|
26
|
+
context: {
|
|
27
|
+
parent: parent.index,
|
|
28
|
+
label: parent.alternative ? `Alternative ${Number(branch) + 1}` : branch === "then" ? "Then branch" : "Else branch"
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function diagnosticViews(diagnostics) {
|
|
34
|
+
const views = diagnostics.map((diagnostic) => ({
|
|
35
|
+
...diagnostic,
|
|
36
|
+
branches: []
|
|
37
|
+
}));
|
|
38
|
+
const roots = [];
|
|
39
|
+
for (const [index, view] of views.entries()) {
|
|
40
|
+
const context = view.context;
|
|
41
|
+
const parent = context && Number.isInteger(context.parent) && context.parent > index ? views[context.parent] : void 0;
|
|
42
|
+
if (!parent) {
|
|
43
|
+
roots.push(view);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
let branch = parent.branches.find((branch) => branch.label === context.label);
|
|
47
|
+
if (!branch) {
|
|
48
|
+
branch = {
|
|
49
|
+
label: context.label,
|
|
50
|
+
diagnostics: []
|
|
51
|
+
};
|
|
52
|
+
parent.branches.push(branch);
|
|
53
|
+
}
|
|
54
|
+
branch.diagnostics.push(view);
|
|
55
|
+
}
|
|
56
|
+
return roots;
|
|
57
|
+
}
|
|
58
|
+
function diagnosticDetails(view) {
|
|
59
|
+
return view.branches.flatMap((branch) => branch.diagnostics.flatMap((child) => [{
|
|
60
|
+
label: branch.label,
|
|
61
|
+
diagnostic: child
|
|
62
|
+
}, ...diagnosticDetails(child).map((detail) => ({
|
|
63
|
+
...detail,
|
|
64
|
+
label: `${branch.label} / ${detail.label}`
|
|
65
|
+
}))]));
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { diagnosticViews as n, validationContexts as r, diagnosticDetails as t };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=diagnostics-BqD1WOy4.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics-BqD1WOy4.mjs","names":[],"sources":["../src/core/diagnostics.ts"],"sourcesContent":["import type { ErrorObject } from \"ajv\"\nimport type { Diagnostic } from \"./types.ts\"\n\nexport type DiagnosticView = Diagnostic & {\n\tbranches: { label: string; diagnostics: DiagnosticView[] }[]\n}\n\n// Ajv emits branch failures before the applicator's summary. Keep the complete\n// flat report and annotate only relationships established by schema paths.\n// Reference paths can lose their caller; leave those errors standalone.\nexport function validationContexts(\n\terrors: readonly ErrorObject[],\n\tdiagnostics: Diagnostic[],\n): Diagnostic[] {\n\tconst summaries = errors.flatMap((error, index) => {\n\t\tif (error.keyword === \"anyOf\" || error.keyword === \"oneOf\")\n\t\t\treturn [\n\t\t\t\t{ index, error, prefix: `${error.schemaPath}/`, alternative: true },\n\t\t\t]\n\t\tif (\n\t\t\terror.keyword === \"if\" &&\n\t\t\t[\"then\", \"else\"].includes(error.params.failingKeyword as string)\n\t\t)\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tindex,\n\t\t\t\t\terror,\n\t\t\t\t\tprefix: `${error.schemaPath.slice(0, -3)}/${error.params.failingKeyword}`,\n\t\t\t\t\talternative: false,\n\t\t\t\t},\n\t\t\t]\n\t\treturn []\n\t})\n\treturn diagnostics.map((diagnostic, index) => {\n\t\tconst error = errors[index]!\n\t\tconst candidates = summaries.filter(\n\t\t\t(parent) =>\n\t\t\t\tparent.index > index &&\n\t\t\t\t(error.instancePath === parent.error.instancePath ||\n\t\t\t\t\terror.instancePath.startsWith(`${parent.error.instancePath}/`)) &&\n\t\t\t\t(parent.error.propertyName === undefined ||\n\t\t\t\t\terror.propertyName === parent.error.propertyName) &&\n\t\t\t\t(parent.alternative\n\t\t\t\t\t? error.schemaPath.startsWith(parent.prefix)\n\t\t\t\t\t: error.schemaPath === parent.prefix ||\n\t\t\t\t\t\terror.schemaPath.startsWith(`${parent.prefix}/`)),\n\t\t)\n\t\tconst parent = candidates.toSorted(\n\t\t\t(a, b) => b.prefix.length - a.prefix.length || a.index - b.index,\n\t\t)[0]\n\t\tif (!parent) return diagnostic\n\t\tconst branch = parent.alternative\n\t\t\t? error.schemaPath.slice(parent.prefix.length).split(\"/\")[0]!\n\t\t\t: (parent.error.params.failingKeyword as string)\n\t\tif (parent.alternative && !/^\\d+$/.test(branch)) return diagnostic\n\t\treturn {\n\t\t\t...diagnostic,\n\t\t\tcontext: {\n\t\t\t\tparent: parent.index,\n\t\t\t\tlabel: parent.alternative\n\t\t\t\t\t? `Alternative ${Number(branch) + 1}`\n\t\t\t\t\t: branch === \"then\"\n\t\t\t\t\t\t? \"Then branch\"\n\t\t\t\t\t\t: \"Else branch\",\n\t\t\t},\n\t\t}\n\t})\n}\n\nexport function diagnosticViews(\n\tdiagnostics: readonly Diagnostic[],\n): DiagnosticView[] {\n\tconst views = diagnostics.map((diagnostic): DiagnosticView => ({\n\t\t...diagnostic,\n\t\tbranches: [],\n\t}))\n\tconst roots: DiagnosticView[] = []\n\tfor (const [index, view] of views.entries()) {\n\t\tconst context = view.context\n\t\t// Parents must follow their children, so malformed metadata cannot create\n\t\t// cycles or make a diagnostic disappear from the displayed report.\n\t\tconst parent =\n\t\t\tcontext && Number.isInteger(context.parent) && context.parent > index\n\t\t\t\t? views[context.parent]\n\t\t\t\t: undefined\n\t\tif (!parent) {\n\t\t\troots.push(view)\n\t\t\tcontinue\n\t\t}\n\t\tlet branch = parent.branches.find(\n\t\t\t(branch) => branch.label === context!.label,\n\t\t)\n\t\tif (!branch) {\n\t\t\tbranch = { label: context!.label, diagnostics: [] }\n\t\t\tparent.branches.push(branch)\n\t\t}\n\t\tbranch.diagnostics.push(view)\n\t}\n\treturn roots\n}\n\nexport function diagnosticDetails(\n\tview: DiagnosticView,\n): { label: string; diagnostic: DiagnosticView }[] {\n\treturn view.branches.flatMap((branch) =>\n\t\tbranch.diagnostics.flatMap((child) => [\n\t\t\t{ label: branch.label, diagnostic: child },\n\t\t\t...diagnosticDetails(child).map((detail) => ({\n\t\t\t\t...detail,\n\t\t\t\tlabel: `${branch.label} / ${detail.label}`,\n\t\t\t})),\n\t\t]),\n\t)\n}\n"],"mappings":";AAUA,SAAgB,mBACf,QACA,aACe;CACf,MAAM,YAAY,OAAO,SAAS,OAAO,UAAU;EAClD,IAAI,MAAM,YAAY,WAAW,MAAM,YAAY,SAClD,OAAO,CACN;GAAE;GAAO;GAAO,QAAQ,GAAG,MAAM,WAAW;GAAI,aAAa;EAAK,CACnE;EACD,IACC,MAAM,YAAY,QAClB,CAAC,QAAQ,MAAM,CAAC,CAAC,SAAS,MAAM,OAAO,cAAwB,GAE/D,OAAO,CACN;GACC;GACA;GACA,QAAQ,GAAG,MAAM,WAAW,MAAM,GAAG,EAAE,EAAE,GAAG,MAAM,OAAO;GACzD,aAAa;EACd,CACD;EACD,OAAO,CAAC;CACT,CAAC;CACD,OAAO,YAAY,KAAK,YAAY,UAAU;EAC7C,MAAM,QAAQ,OAAO;EAarB,MAAM,SAZa,UAAU,QAC3B,WACA,OAAO,QAAQ,UACd,MAAM,iBAAiB,OAAO,MAAM,gBACpC,MAAM,aAAa,WAAW,GAAG,OAAO,MAAM,aAAa,EAAE,OAC7D,OAAO,MAAM,iBAAiB,KAAA,KAC9B,MAAM,iBAAiB,OAAO,MAAM,kBACpC,OAAO,cACL,MAAM,WAAW,WAAW,OAAO,MAAM,IACzC,MAAM,eAAe,OAAO,UAC7B,MAAM,WAAW,WAAW,GAAG,OAAO,OAAO,EAAE,EAE3B,CAAC,CAAC,UACxB,GAAG,MAAM,EAAE,OAAO,SAAS,EAAE,OAAO,UAAU,EAAE,QAAQ,EAAE,KAC5D,CAAC,CAAC;EACF,IAAI,CAAC,QAAQ,OAAO;EACpB,MAAM,SAAS,OAAO,cACnB,MAAM,WAAW,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KACvD,OAAO,MAAM,OAAO;EACxB,IAAI,OAAO,eAAe,CAAC,QAAQ,KAAK,MAAM,GAAG,OAAO;EACxD,OAAO;GACN,GAAG;GACH,SAAS;IACR,QAAQ,OAAO;IACf,OAAO,OAAO,cACX,eAAe,OAAO,MAAM,IAAI,MAChC,WAAW,SACV,gBACA;GACL;EACD;CACD,CAAC;AACF;AAEA,SAAgB,gBACf,aACmB;CACnB,MAAM,QAAQ,YAAY,KAAK,gBAAgC;EAC9D,GAAG;EACH,UAAU,CAAC;CACZ,EAAE;CACF,MAAM,QAA0B,CAAC;CACjC,KAAK,MAAM,CAAC,OAAO,SAAS,MAAM,QAAQ,GAAG;EAC5C,MAAM,UAAU,KAAK;EAGrB,MAAM,SACL,WAAW,OAAO,UAAU,QAAQ,MAAM,KAAK,QAAQ,SAAS,QAC7D,MAAM,QAAQ,UACd,KAAA;EACJ,IAAI,CAAC,QAAQ;GACZ,MAAM,KAAK,IAAI;GACf;EACD;EACA,IAAI,SAAS,OAAO,SAAS,MAC3B,WAAW,OAAO,UAAU,QAAS,KACvC;EACA,IAAI,CAAC,QAAQ;GACZ,SAAS;IAAE,OAAO,QAAS;IAAO,aAAa,CAAC;GAAE;GAClD,OAAO,SAAS,KAAK,MAAM;EAC5B;EACA,OAAO,YAAY,KAAK,IAAI;CAC7B;CACA,OAAO;AACR;AAEA,SAAgB,kBACf,MACkD;CAClD,OAAO,KAAK,SAAS,SAAS,WAC7B,OAAO,YAAY,SAAS,UAAU,CACrC;EAAE,OAAO,OAAO;EAAO,YAAY;CAAM,GACzC,GAAG,kBAAkB,KAAK,CAAC,CAAC,KAAK,YAAY;EAC5C,GAAG;EACH,OAAO,GAAG,OAAO,MAAM,KAAK,OAAO;CACpC,EAAE,CACH,CAAC,CACF;AACD"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { _ as defaultParser, c as isIncluded, d as readText, h as failure, m as CorrectlyError, r as associationFor } from "./config-Cb6o4YnJ.mjs";
|
|
2
|
+
//#region src/core/engine.ts
|
|
3
|
+
var Engine = class {
|
|
4
|
+
project;
|
|
5
|
+
context;
|
|
6
|
+
prepared = /* @__PURE__ */ new Map();
|
|
7
|
+
registration;
|
|
8
|
+
constructor(project, options = {}) {
|
|
9
|
+
this.project = project;
|
|
10
|
+
const watch = (uri) => options.onDependency?.(uri);
|
|
11
|
+
this.context = {
|
|
12
|
+
root: project.root,
|
|
13
|
+
configPath: project.configPath,
|
|
14
|
+
remote: {
|
|
15
|
+
...project.config.remote,
|
|
16
|
+
...options.offline === void 0 ? {} : { offline: options.offline }
|
|
17
|
+
},
|
|
18
|
+
read: async (uri) => {
|
|
19
|
+
watch(uri);
|
|
20
|
+
return (options.read ?? readText)(uri);
|
|
21
|
+
},
|
|
22
|
+
...options.fetch ? { fetch: options.fetch } : {},
|
|
23
|
+
...options.signal ? { signal: options.signal } : {},
|
|
24
|
+
watch,
|
|
25
|
+
services: /* @__PURE__ */ new Map()
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
register() {
|
|
29
|
+
return this.registration ??= (async () => {
|
|
30
|
+
for (const rule of this.project.config.associations) await rule.validate?.register?.(this.context);
|
|
31
|
+
})();
|
|
32
|
+
}
|
|
33
|
+
validator(validator) {
|
|
34
|
+
let prepared = this.prepared.get(validator);
|
|
35
|
+
if (!prepared) {
|
|
36
|
+
prepared = (async () => {
|
|
37
|
+
await this.register();
|
|
38
|
+
const result = await validator.prepare(this.context);
|
|
39
|
+
if (!result || typeof result.validate !== "function") throw new CorrectlyError("validator", `Validator ${validator.id} did not prepare a validate function`);
|
|
40
|
+
return result;
|
|
41
|
+
})();
|
|
42
|
+
this.prepared.set(validator, prepared);
|
|
43
|
+
}
|
|
44
|
+
return prepared;
|
|
45
|
+
}
|
|
46
|
+
async prepare() {
|
|
47
|
+
await this.register();
|
|
48
|
+
for (const rule of this.project.config.associations) if (rule.validate) {
|
|
49
|
+
if (!rule.validate.accepts.includes(rule.parse?.valueModel ?? "json")) throw new CorrectlyError("adapter-incompatible", `Parser ${rule.parse?.id ?? "json"} produces ${rule.parse?.valueModel ?? "json"}; validator ${rule.validate.id} accepts ${rule.validate.accepts.join(", ")}`);
|
|
50
|
+
await this.validator(rule.validate);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async editor(file) {
|
|
54
|
+
if (!isIncluded(this.project, file)) return void 0;
|
|
55
|
+
const association = associationFor(this.project, file);
|
|
56
|
+
if (!association) return void 0;
|
|
57
|
+
const rule = this.project.config.associations[association.index];
|
|
58
|
+
const parser = rule.parse ?? defaultParser(file);
|
|
59
|
+
if (!rule.validate || !parser.editorLanguage) return void 0;
|
|
60
|
+
if (!rule.validate.accepts.includes(parser.valueModel)) return void 0;
|
|
61
|
+
const prepared = await this.validator(rule.validate);
|
|
62
|
+
return prepared.editor ? {
|
|
63
|
+
support: prepared.editor,
|
|
64
|
+
language: parser.editorLanguage,
|
|
65
|
+
association: association.index
|
|
66
|
+
} : void 0;
|
|
67
|
+
}
|
|
68
|
+
async validate(file, text) {
|
|
69
|
+
const association = associationFor(this.project, file);
|
|
70
|
+
const rule = association ? this.project.config.associations[association.index] : void 0;
|
|
71
|
+
const parser = rule?.parse ?? defaultParser(file);
|
|
72
|
+
const result = {
|
|
73
|
+
file,
|
|
74
|
+
mode: parser.id,
|
|
75
|
+
association,
|
|
76
|
+
coverage: "excluded",
|
|
77
|
+
diagnostics: [],
|
|
78
|
+
failures: []
|
|
79
|
+
};
|
|
80
|
+
if (!isIncluded(this.project, file)) return result;
|
|
81
|
+
result.coverage = rule?.validate ? association?.schema ? "schema" : "validated" : "syntax-only";
|
|
82
|
+
try {
|
|
83
|
+
this.context.signal?.throwIfAborted();
|
|
84
|
+
const parsed = await parser.parse(text, {
|
|
85
|
+
file,
|
|
86
|
+
...this.context.signal ? { signal: this.context.signal } : {}
|
|
87
|
+
});
|
|
88
|
+
result.diagnostics.push(...parsed.diagnostics);
|
|
89
|
+
if (rule?.validate) {
|
|
90
|
+
if (!rule.validate.accepts.includes(parser.valueModel)) throw new CorrectlyError("adapter-incompatible", `Parser ${parser.id} produces ${parser.valueModel}; validator ${rule.validate.id} accepts ${rule.validate.accepts.join(", ")}`);
|
|
91
|
+
const validator = await this.validator(rule.validate);
|
|
92
|
+
if (!parsed.diagnostics.length) result.diagnostics.push(...await validator.validate({
|
|
93
|
+
file,
|
|
94
|
+
text,
|
|
95
|
+
parsed,
|
|
96
|
+
...this.context.signal ? { signal: this.context.signal } : {}
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
result.failures.push(failure(error, file));
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
async dispose() {
|
|
105
|
+
for (const prepared of this.prepared.values()) await (await prepared.catch(() => void 0))?.dispose?.();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
//#endregion
|
|
109
|
+
export { Engine as t };
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=engine-VST0hoSk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-VST0hoSk.mjs","names":[],"sources":["../src/core/engine.ts"],"sourcesContent":["import { associationFor, isIncluded, readText, type Project } from \"./config.ts\"\nimport { defaultParser } from \"./parsers.ts\"\nimport { CorrectlyError, failure, type FileResult } from \"./types.ts\"\nimport type { StoreOptions } from \"./schemas.ts\"\nimport type {\n\tPreparedValidator,\n\tValidationContext,\n\tValidator,\n} from \"./adapters.ts\"\n\nexport type EngineOptions = StoreOptions & {\n\tonDependency?: (uri: string) => void\n}\nexport class Engine {\n\treadonly project: Project\n\treadonly context: ValidationContext\n\tprivate readonly prepared = new Map<Validator, Promise<PreparedValidator>>()\n\tprivate registration: Promise<void> | undefined\n\tconstructor(project: Project, options: EngineOptions = {}) {\n\t\tthis.project = project\n\t\tconst watch = (uri: string) => options.onDependency?.(uri)\n\t\tthis.context = {\n\t\t\troot: project.root,\n\t\t\tconfigPath: project.configPath,\n\t\t\tremote: {\n\t\t\t\t...project.config.remote,\n\t\t\t\t...(options.offline === undefined ? {} : { offline: options.offline }),\n\t\t\t},\n\t\t\tread: async (uri) => {\n\t\t\t\twatch(uri)\n\t\t\t\treturn (options.read ?? readText)(uri)\n\t\t\t},\n\t\t\t...(options.fetch ? { fetch: options.fetch } : {}),\n\t\t\t...(options.signal ? { signal: options.signal } : {}),\n\t\t\twatch,\n\t\t\tservices: new Map(),\n\t\t}\n\t}\n\tprivate register(): Promise<void> {\n\t\treturn (this.registration ??= (async () => {\n\t\t\tfor (const rule of this.project.config.associations)\n\t\t\t\tawait rule.validate?.register?.(this.context)\n\t\t})())\n\t}\n\tprivate validator(validator: Validator): Promise<PreparedValidator> {\n\t\tlet prepared = this.prepared.get(validator)\n\t\tif (!prepared) {\n\t\t\tprepared = (async () => {\n\t\t\t\tawait this.register()\n\t\t\t\tconst result = await validator.prepare(this.context)\n\t\t\t\tif (!result || typeof result.validate !== \"function\")\n\t\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\t\"validator\",\n\t\t\t\t\t\t`Validator ${validator.id} did not prepare a validate function`,\n\t\t\t\t\t)\n\t\t\t\treturn result\n\t\t\t})()\n\t\t\tthis.prepared.set(validator, prepared)\n\t\t}\n\t\treturn prepared\n\t}\n\tasync prepare(): Promise<void> {\n\t\tawait this.register()\n\t\tfor (const rule of this.project.config.associations) {\n\t\t\tif (rule.validate) {\n\t\t\t\tif (!rule.validate.accepts.includes(rule.parse?.valueModel ?? \"json\"))\n\t\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\t\"adapter-incompatible\",\n\t\t\t\t\t\t`Parser ${rule.parse?.id ?? \"json\"} produces ${rule.parse?.valueModel ?? \"json\"}; validator ${rule.validate.id} accepts ${rule.validate.accepts.join(\", \")}`,\n\t\t\t\t\t)\n\t\t\t\tawait this.validator(rule.validate)\n\t\t\t}\n\t\t}\n\t}\n\tasync editor(file: string) {\n\t\tif (!isIncluded(this.project, file)) return undefined\n\t\tconst association = associationFor(this.project, file)\n\t\tif (!association) return undefined\n\t\tconst rule = this.project.config.associations[association.index]!\n\t\tconst parser = rule.parse ?? defaultParser(file)\n\t\tif (!rule.validate || !parser.editorLanguage) return undefined\n\t\tif (!rule.validate.accepts.includes(parser.valueModel)) return undefined\n\t\tconst prepared = await this.validator(rule.validate)\n\t\treturn prepared.editor\n\t\t\t? {\n\t\t\t\t\tsupport: prepared.editor,\n\t\t\t\t\tlanguage: parser.editorLanguage,\n\t\t\t\t\tassociation: association.index,\n\t\t\t\t}\n\t\t\t: undefined\n\t}\n\tasync validate(file: string, text: string): Promise<FileResult> {\n\t\tconst association = associationFor(this.project, file)\n\t\tconst rule = association\n\t\t\t? this.project.config.associations[association.index]\n\t\t\t: undefined\n\t\tconst parser = rule?.parse ?? defaultParser(file)\n\t\tconst result: FileResult = {\n\t\t\tfile,\n\t\t\tmode: parser.id,\n\t\t\tassociation,\n\t\t\tcoverage: \"excluded\",\n\t\t\tdiagnostics: [],\n\t\t\tfailures: [],\n\t\t}\n\t\tif (!isIncluded(this.project, file)) return result\n\t\tresult.coverage = rule?.validate\n\t\t\t? association?.schema\n\t\t\t\t? \"schema\"\n\t\t\t\t: \"validated\"\n\t\t\t: \"syntax-only\"\n\t\ttry {\n\t\t\tthis.context.signal?.throwIfAborted()\n\t\t\tconst parsed = await parser.parse(text, {\n\t\t\t\tfile,\n\t\t\t\t...(this.context.signal ? { signal: this.context.signal } : {}),\n\t\t\t})\n\t\t\tresult.diagnostics.push(...parsed.diagnostics)\n\t\t\tif (rule?.validate) {\n\t\t\t\tif (!rule.validate.accepts.includes(parser.valueModel))\n\t\t\t\t\tthrow new CorrectlyError(\n\t\t\t\t\t\t\"adapter-incompatible\",\n\t\t\t\t\t\t`Parser ${parser.id} produces ${parser.valueModel}; validator ${rule.validate.id} accepts ${rule.validate.accepts.join(\", \")}`,\n\t\t\t\t\t)\n\t\t\t\tconst validator = await this.validator(rule.validate)\n\t\t\t\tif (!parsed.diagnostics.length)\n\t\t\t\t\tresult.diagnostics.push(\n\t\t\t\t\t\t...(await validator.validate({\n\t\t\t\t\t\t\tfile,\n\t\t\t\t\t\t\ttext,\n\t\t\t\t\t\t\tparsed,\n\t\t\t\t\t\t\t...(this.context.signal ? { signal: this.context.signal } : {}),\n\t\t\t\t\t\t})),\n\t\t\t\t\t)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tresult.failures.push(failure(error, file))\n\t\t}\n\t\treturn result\n\t}\n\tasync dispose(): Promise<void> {\n\t\tfor (const prepared of this.prepared.values()) {\n\t\t\tconst result = await prepared.catch(() => undefined)\n\t\t\tawait result?.dispose?.()\n\t\t}\n\t}\n}\n"],"mappings":";;AAaA,IAAa,SAAb,MAAoB;CACnB;CACA;CACA,2BAA4B,IAAI,IAA2C;CAC3E;CACA,YAAY,SAAkB,UAAyB,CAAC,GAAG;EAC1D,KAAK,UAAU;EACf,MAAM,SAAS,QAAgB,QAAQ,eAAe,GAAG;EACzD,KAAK,UAAU;GACd,MAAM,QAAQ;GACd,YAAY,QAAQ;GACpB,QAAQ;IACP,GAAG,QAAQ,OAAO;IAClB,GAAI,QAAQ,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;GACrE;GACA,MAAM,OAAO,QAAQ;IACpB,MAAM,GAAG;IACT,QAAQ,QAAQ,QAAQ,SAAA,CAAU,GAAG;GACtC;GACA,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;GAChD,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;GACnD;GACA,0BAAU,IAAI,IAAI;EACnB;CACD;CACA,WAAkC;EACjC,OAAQ,KAAK,kBAAkB,YAAY;GAC1C,KAAK,MAAM,QAAQ,KAAK,QAAQ,OAAO,cACtC,MAAM,KAAK,UAAU,WAAW,KAAK,OAAO;EAC9C,EAAA,CAAG;CACJ;CACA,UAAkB,WAAkD;EACnE,IAAI,WAAW,KAAK,SAAS,IAAI,SAAS;EAC1C,IAAI,CAAC,UAAU;GACd,YAAY,YAAY;IACvB,MAAM,KAAK,SAAS;IACpB,MAAM,SAAS,MAAM,UAAU,QAAQ,KAAK,OAAO;IACnD,IAAI,CAAC,UAAU,OAAO,OAAO,aAAa,YACzC,MAAM,IAAI,eACT,aACA,aAAa,UAAU,GAAG,qCAC3B;IACD,OAAO;GACR,EAAA,CAAG;GACH,KAAK,SAAS,IAAI,WAAW,QAAQ;EACtC;EACA,OAAO;CACR;CACA,MAAM,UAAyB;EAC9B,MAAM,KAAK,SAAS;EACpB,KAAK,MAAM,QAAQ,KAAK,QAAQ,OAAO,cACtC,IAAI,KAAK,UAAU;GAClB,IAAI,CAAC,KAAK,SAAS,QAAQ,SAAS,KAAK,OAAO,cAAc,MAAM,GACnE,MAAM,IAAI,eACT,wBACA,UAAU,KAAK,OAAO,MAAM,OAAO,YAAY,KAAK,OAAO,cAAc,OAAO,cAAc,KAAK,SAAS,GAAG,WAAW,KAAK,SAAS,QAAQ,KAAK,IAAI,GAC1J;GACD,MAAM,KAAK,UAAU,KAAK,QAAQ;EACnC;CAEF;CACA,MAAM,OAAO,MAAc;EAC1B,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,GAAG,OAAO,KAAA;EAC5C,MAAM,cAAc,eAAe,KAAK,SAAS,IAAI;EACrD,IAAI,CAAC,aAAa,OAAO,KAAA;EACzB,MAAM,OAAO,KAAK,QAAQ,OAAO,aAAa,YAAY;EAC1D,MAAM,SAAS,KAAK,SAAS,cAAc,IAAI;EAC/C,IAAI,CAAC,KAAK,YAAY,CAAC,OAAO,gBAAgB,OAAO,KAAA;EACrD,IAAI,CAAC,KAAK,SAAS,QAAQ,SAAS,OAAO,UAAU,GAAG,OAAO,KAAA;EAC/D,MAAM,WAAW,MAAM,KAAK,UAAU,KAAK,QAAQ;EACnD,OAAO,SAAS,SACb;GACA,SAAS,SAAS;GAClB,UAAU,OAAO;GACjB,aAAa,YAAY;EAC1B,IACC,KAAA;CACJ;CACA,MAAM,SAAS,MAAc,MAAmC;EAC/D,MAAM,cAAc,eAAe,KAAK,SAAS,IAAI;EACrD,MAAM,OAAO,cACV,KAAK,QAAQ,OAAO,aAAa,YAAY,SAC7C,KAAA;EACH,MAAM,SAAS,MAAM,SAAS,cAAc,IAAI;EAChD,MAAM,SAAqB;GAC1B;GACA,MAAM,OAAO;GACb;GACA,UAAU;GACV,aAAa,CAAC;GACd,UAAU,CAAC;EACZ;EACA,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,GAAG,OAAO;EAC5C,OAAO,WAAW,MAAM,WACrB,aAAa,SACZ,WACA,cACD;EACH,IAAI;GACH,KAAK,QAAQ,QAAQ,eAAe;GACpC,MAAM,SAAS,MAAM,OAAO,MAAM,MAAM;IACvC;IACA,GAAI,KAAK,QAAQ,SAAS,EAAE,QAAQ,KAAK,QAAQ,OAAO,IAAI,CAAC;GAC9D,CAAC;GACD,OAAO,YAAY,KAAK,GAAG,OAAO,WAAW;GAC7C,IAAI,MAAM,UAAU;IACnB,IAAI,CAAC,KAAK,SAAS,QAAQ,SAAS,OAAO,UAAU,GACpD,MAAM,IAAI,eACT,wBACA,UAAU,OAAO,GAAG,YAAY,OAAO,WAAW,cAAc,KAAK,SAAS,GAAG,WAAW,KAAK,SAAS,QAAQ,KAAK,IAAI,GAC5H;IACD,MAAM,YAAY,MAAM,KAAK,UAAU,KAAK,QAAQ;IACpD,IAAI,CAAC,OAAO,YAAY,QACvB,OAAO,YAAY,KAClB,GAAI,MAAM,UAAU,SAAS;KAC5B;KACA;KACA;KACA,GAAI,KAAK,QAAQ,SAAS,EAAE,QAAQ,KAAK,QAAQ,OAAO,IAAI,CAAC;IAC9D,CAAC,CACF;GACF;EACD,SAAS,OAAO;GACf,OAAO,SAAS,KAAK,QAAQ,OAAO,IAAI,CAAC;EAC1C;EACA,OAAO;CACR;CACA,MAAM,UAAyB;EAC9B,KAAK,MAAM,YAAY,KAAK,SAAS,OAAO,GAE3C,OAAM,MADe,SAAS,YAAY,KAAA,CAAS,EAAA,EACrC,UAAU;CAE1B;AACD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Ajv, FormatDefinition } from "ajv";
|
|
2
|
+
//#region src/core/extensions.d.ts
|
|
3
|
+
/** Synchronous assertions and annotation-only keywords. Registration is explicit. */
|
|
4
|
+
type AjvExtension = {
|
|
5
|
+
id: string;
|
|
6
|
+
formats?: Readonly<Record<string, FormatDefinition<string> | FormatDefinition<number>>>;
|
|
7
|
+
annotations?: readonly string[];
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { AjvExtension as t };
|
|
11
|
+
//# sourceMappingURL=extensions-ClclWslY.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensions-ClclWslY.d.mts","names":[],"sources":["../src/core/extensions.ts"],"mappings":";;;KAKY;EACX;EACA,UAAU,SACT,eAAe,2BAA2B;EAE3C"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { getLanguageService } from "vscode-json-languageservice";
|
|
3
|
+
//#region src/lsp/hints.ts
|
|
4
|
+
function externalSelection(document) {
|
|
5
|
+
return new Proxy(document, { get(target, key) {
|
|
6
|
+
if (key === "root") return void 0;
|
|
7
|
+
const value = Reflect.get(target, key);
|
|
8
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
9
|
+
} });
|
|
10
|
+
}
|
|
11
|
+
var Hints = class {
|
|
12
|
+
services = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
async service(engine, document) {
|
|
14
|
+
const file = fileURLToPath(document.uri);
|
|
15
|
+
const editor = await engine.editor(file);
|
|
16
|
+
if (!editor) return void 0;
|
|
17
|
+
const key = String(editor.association);
|
|
18
|
+
let services = this.services.get(engine);
|
|
19
|
+
if (!services) {
|
|
20
|
+
services = /* @__PURE__ */ new Map();
|
|
21
|
+
this.services.set(engine, services);
|
|
22
|
+
}
|
|
23
|
+
let service = services.get(key);
|
|
24
|
+
if (!service) {
|
|
25
|
+
service = getLanguageService({
|
|
26
|
+
schemaRequestService: (uri) => editor.support.readSchema(uri),
|
|
27
|
+
workspaceContext: { resolveRelativePath: (relative, resource) => new URL(relative, resource).href }
|
|
28
|
+
});
|
|
29
|
+
service.configure({
|
|
30
|
+
validate: false,
|
|
31
|
+
schemas: [{
|
|
32
|
+
uri: editor.support.uri,
|
|
33
|
+
fileMatch: ["*"]
|
|
34
|
+
}]
|
|
35
|
+
});
|
|
36
|
+
services.set(key, service);
|
|
37
|
+
}
|
|
38
|
+
return service;
|
|
39
|
+
}
|
|
40
|
+
async complete(engine, document, position) {
|
|
41
|
+
if (!("editor" in engine)) return engine.complete(document, position);
|
|
42
|
+
const service = await this.service(engine, document);
|
|
43
|
+
return service ? await service.doComplete(document, position, externalSelection(service.parseJSONDocument(document))) : {
|
|
44
|
+
isIncomplete: false,
|
|
45
|
+
items: []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async hover(engine, document, position) {
|
|
49
|
+
if (!("editor" in engine)) return engine.hover(document, position);
|
|
50
|
+
const service = await this.service(engine, document);
|
|
51
|
+
return service ? await service.doHover(document, position, externalSelection(service.parseJSONDocument(document))) : null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
export { Hints as t };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=hints-HvSIhuMM.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hints-HvSIhuMM.mjs","names":[],"sources":["../src/lsp/hints.ts"],"sourcesContent":["import {\n\tgetLanguageService,\n\ttype JSONDocument,\n\ttype LanguageService,\n\ttype Position,\n} from \"vscode-json-languageservice\"\nimport type { TextDocument } from \"vscode-languageserver-textdocument\"\nimport { fileURLToPath } from \"node:url\"\n\nimport type { ProjectSession } from \"../runtime/session.ts\"\nimport type { Engine } from \"../core/engine.ts\"\n\n// Only the schema-selection accessor is hidden. The original AST (including\n// $schema as ordinary data) is retained by every bound traversal method.\nexport function externalSelection(document: JSONDocument): JSONDocument {\n\treturn new Proxy(document, {\n\t\tget(target, key) {\n\t\t\tif (key === \"root\") return undefined\n\t\t\tconst value: unknown = Reflect.get(target, key)\n\t\t\treturn typeof value === \"function\" ? value.bind(target) : value\n\t\t},\n\t})\n}\n\nexport class Hints {\n\tprivate readonly services = new WeakMap<\n\t\tEngine,\n\t\tMap<string, LanguageService>\n\t>()\n\tprivate async service(\n\t\tengine: Engine,\n\t\tdocument: TextDocument,\n\t): Promise<LanguageService | undefined> {\n\t\tconst file = fileURLToPath(document.uri)\n\t\tconst editor = await engine.editor(file)\n\t\tif (!editor) return undefined\n\t\tconst key = String(editor.association)\n\n\t\tlet services = this.services.get(engine)\n\t\tif (!services) {\n\t\t\tservices = new Map()\n\t\t\tthis.services.set(engine, services)\n\t\t}\n\t\tlet service = services.get(key)\n\t\tif (!service) {\n\t\t\tservice = getLanguageService({\n\t\t\t\tschemaRequestService: (uri) => editor.support.readSchema(uri),\n\t\t\t\tworkspaceContext: {\n\t\t\t\t\tresolveRelativePath: (relative, resource) =>\n\t\t\t\t\t\tnew URL(relative, resource).href,\n\t\t\t\t},\n\t\t\t})\n\t\t\t// A per-association service prevents overlapping rules being combined.\n\t\t\tservice.configure({\n\t\t\t\tvalidate: false,\n\t\t\t\tschemas: [{ uri: editor.support.uri, fileMatch: [\"*\"] }],\n\t\t\t})\n\t\t\tservices.set(key, service)\n\t\t}\n\t\treturn service\n\t}\n\tasync complete(\n\t\tengine: Engine | ProjectSession,\n\t\tdocument: TextDocument,\n\t\tposition: Position,\n\t) {\n\t\tif (!(\"editor\" in engine)) return engine.complete(document, position)\n\t\tconst service = await this.service(engine, document)\n\t\treturn service\n\t\t\t? await service.doComplete(\n\t\t\t\t\tdocument,\n\t\t\t\t\tposition,\n\t\t\t\t\texternalSelection(service.parseJSONDocument(document)),\n\t\t\t\t)\n\t\t\t: { isIncomplete: false, items: [] }\n\t}\n\tasync hover(\n\t\tengine: Engine | ProjectSession,\n\t\tdocument: TextDocument,\n\t\tposition: Position,\n\t) {\n\t\tif (!(\"editor\" in engine)) return engine.hover(document, position)\n\t\tconst service = await this.service(engine, document)\n\t\treturn service\n\t\t\t? await service.doHover(\n\t\t\t\t\tdocument,\n\t\t\t\t\tposition,\n\t\t\t\t\texternalSelection(service.parseJSONDocument(document)),\n\t\t\t\t)\n\t\t\t: null\n\t}\n}\n"],"mappings":";;;AAcA,SAAgB,kBAAkB,UAAsC;CACvE,OAAO,IAAI,MAAM,UAAU,EAC1B,IAAI,QAAQ,KAAK;EAChB,IAAI,QAAQ,QAAQ,OAAO,KAAA;EAC3B,MAAM,QAAiB,QAAQ,IAAI,QAAQ,GAAG;EAC9C,OAAO,OAAO,UAAU,aAAa,MAAM,KAAK,MAAM,IAAI;CAC3D,EACD,CAAC;AACF;AAEA,IAAa,QAAb,MAAmB;CAClB,2BAA4B,IAAI,QAG9B;CACF,MAAc,QACb,QACA,UACuC;EACvC,MAAM,OAAO,cAAc,SAAS,GAAG;EACvC,MAAM,SAAS,MAAM,OAAO,OAAO,IAAI;EACvC,IAAI,CAAC,QAAQ,OAAO,KAAA;EACpB,MAAM,MAAM,OAAO,OAAO,WAAW;EAErC,IAAI,WAAW,KAAK,SAAS,IAAI,MAAM;EACvC,IAAI,CAAC,UAAU;GACd,2BAAW,IAAI,IAAI;GACnB,KAAK,SAAS,IAAI,QAAQ,QAAQ;EACnC;EACA,IAAI,UAAU,SAAS,IAAI,GAAG;EAC9B,IAAI,CAAC,SAAS;GACb,UAAU,mBAAmB;IAC5B,uBAAuB,QAAQ,OAAO,QAAQ,WAAW,GAAG;IAC5D,kBAAkB,EACjB,sBAAsB,UAAU,aAC/B,IAAI,IAAI,UAAU,QAAQ,CAAC,CAAC,KAC9B;GACD,CAAC;GAED,QAAQ,UAAU;IACjB,UAAU;IACV,SAAS,CAAC;KAAE,KAAK,OAAO,QAAQ;KAAK,WAAW,CAAC,GAAG;IAAE,CAAC;GACxD,CAAC;GACD,SAAS,IAAI,KAAK,OAAO;EAC1B;EACA,OAAO;CACR;CACA,MAAM,SACL,QACA,UACA,UACC;EACD,IAAI,EAAE,YAAY,SAAS,OAAO,OAAO,SAAS,UAAU,QAAQ;EACpE,MAAM,UAAU,MAAM,KAAK,QAAQ,QAAQ,QAAQ;EACnD,OAAO,UACJ,MAAM,QAAQ,WACd,UACA,UACA,kBAAkB,QAAQ,kBAAkB,QAAQ,CAAC,CACtD,IACC;GAAE,cAAc;GAAO,OAAO,CAAC;EAAE;CACrC;CACA,MAAM,MACL,QACA,UACA,UACC;EACD,IAAI,EAAE,YAAY,SAAS,OAAO,OAAO,MAAM,UAAU,QAAQ;EACjE,MAAM,UAAU,MAAM,KAAK,QAAQ,QAAQ,QAAQ;EACnD,OAAO,UACJ,MAAM,QAAQ,QACd,UACA,UACA,kBAAkB,QAAQ,kBAAkB,QAAQ,CAAC,CACtD,IACC;CACJ;AACD"}
|