@eriknaslund/skiss 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/cli.js +533 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +43 -4
- package/dist/index.js +509 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/parse.ts","../src/resolve.ts","../src/generators/linkml.ts","../src/generators/mermaid.ts","../src/serialize.ts","../src/compile.ts","../src/diagnostics.ts","../src/index.ts"],"sourcesContent":["// The `skiss` command. Node-only, and the only file in the package that\n// touches files or `process` (ADR 0003). A thin layer: read, call the\n// library, write. Anything that looks like logic belongs in the library.\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { basename, extname } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport { compile, formatDiagnostic, VERSION } from './index.ts';\n\nconst HELP = `Usage: skiss <command> [options]\n\nCommands:\n diagram <file> Write a Mermaid class diagram for a .skiss file.\n compile <file> Write a LinkML schema for a .skiss file.\n <file> may be - to read standard input.\n\nOptions:\n -o, --output <path> Write the output to <path> instead of standard output\n --notes diagram: emit \\`? text\\` doubts as Mermaid notes\n --json compile: write the schema as JSON instead of YAML\n --name <name> compile: the schema name. Defaults to the file's\n basename without its extension, or \\`sketch\\` for\n standard input.\n --strict Exit 1 when the input has any diagnostic\n -h, --help Show this help and exit\n --version Print the version and exit\n\nDiagnostics go to standard error, one per line:\n <file>:<line>:<col>: <severity> <CODE> <message>\n\nExit codes:\n 0 the output was produced\n 1 --strict and the input has diagnostics (the output is still written)\n 2 usage error, missing file or unreadable input\n 70 internal error, a bug in skiss\n`;\n\n/** Issue #6, AC4 and AC5. 70 is `EX_SOFTWARE` from `sysexits.h`. */\nconst EXIT_OK = 0;\nconst EXIT_STRICT = 1;\nconst EXIT_USAGE = 2;\nconst EXIT_INTERNAL = 70;\n\n/**\n * Which options each command takes. `--help` and `--version` are answered\n * before a command is read and are not listed. An option that belongs to the\n * other command is a usage error rather than something silently ignored.\n */\nconst COMMANDS = {\n diagram: ['output', 'notes', 'strict'],\n compile: ['output', 'json', 'name', 'strict'],\n} as const;\n\ntype Command = keyof typeof COMMANDS;\n\nconst isCommand = (text: string): text is Command => Object.hasOwn(COMMANDS, text);\n\n/** Thrown for anything that ends the run with exit code 2. */\nclass UsageError extends Error {}\n\n/**\n * Our own `UsageError`, or a `parseArgs` rejection (unknown option, `-o`\n * with no path), whose `code` is one of the `ERR_PARSE_ARGS_*` family.\n */\nfunction isUsageError(error: unknown): boolean {\n if (error instanceof UsageError) return true;\n if (typeof error !== 'object' || error === null || !('code' in error)) return false;\n return typeof error.code === 'string' && error.code.startsWith('ERR_PARSE_ARGS');\n}\n\nasync function main(argv: string[]): Promise<number> {\n if (argv.length === 0) {\n process.stderr.write(HELP);\n return EXIT_USAGE;\n }\n\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n output: { type: 'string', short: 'o' },\n notes: { type: 'boolean' },\n json: { type: 'boolean' },\n name: { type: 'string' },\n strict: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean' },\n },\n allowPositionals: true,\n strict: true,\n });\n\n if (values.help === true) {\n process.stdout.write(HELP);\n return EXIT_OK;\n }\n if (values.version === true) {\n process.stdout.write(`${VERSION}\\n`);\n return EXIT_OK;\n }\n\n const [command, file, ...extra] = positionals;\n if (command === undefined) throw new UsageError('missing command');\n if (!isCommand(command)) throw new UsageError(`unknown command \\`${command}\\``);\n if (file === undefined)\n throw new UsageError(`${command} needs a <file>, or - for standard input`);\n if (extra.length > 0) throw new UsageError(`unexpected argument \\`${extra[0]}\\``);\n\n // `parseArgs` leaves an option out of `values` when it was not given, so\n // the keys here are exactly what was typed.\n const accepted: readonly string[] = COMMANDS[command];\n for (const option of Object.keys(values)) {\n if (!accepted.includes(option)) {\n throw new UsageError(`\\`${command}\\` does not take \\`--${option}\\``);\n }\n }\n\n const source = file === '-' ? await readStdin() : await readSource(file);\n const { output, diagnostics } =\n command === 'compile'\n ? compile(source, {\n target: 'linkml',\n schemaName: values.name ?? defaultSchemaName(file),\n format: values.json === true ? 'json' : 'yaml',\n })\n : compile(source, { target: 'mermaid', notes: values.notes });\n\n const label = file === '-' ? '<stdin>' : file;\n for (const d of diagnostics) process.stderr.write(`${formatDiagnostic(d, label)}\\n`);\n\n if (values.output === undefined) process.stdout.write(output);\n else await writeOutput(values.output, output);\n\n return values.strict === true && diagnostics.length > 0 ? EXIT_STRICT : EXIT_OK;\n}\n\n/**\n * Issue #24, AC2. `toLinkML` normalises this to a valid LinkML name\n * (SPEC §5.2), so a basename with a dot or a dash in it needs nothing here.\n */\nconst defaultSchemaName = (file: string): string =>\n file === '-' ? 'sketch' : basename(file, extname(file));\n\nasync function readSource(file: string): Promise<string> {\n try {\n return await readFile(file, 'utf8');\n } catch (error) {\n throw new UsageError(`cannot read \\`${file}\\`: ${reason(error)}`);\n }\n}\n\nasync function readStdin(): Promise<string> {\n try {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n } catch (error) {\n throw new UsageError(`cannot read standard input: ${reason(error)}`);\n }\n}\n\n/** D1: the path is written verbatim; no extension is inferred from the target. */\nasync function writeOutput(path: string, text: string): Promise<void> {\n try {\n await writeFile(path, text, 'utf8');\n } catch (error) {\n throw new UsageError(`cannot write \\`${path}\\`: ${reason(error)}`);\n }\n}\n\n/** The OS error code when there is one (`ENOENT`), else the message. */\nfunction reason(error: unknown): string {\n if (error instanceof Error) {\n const code = (error as NodeJS.ErrnoException).code;\n return code ?? error.message;\n }\n return String(error);\n}\n\n// `process.exitCode` rather than `process.exit()`, so a piped stdout is\n// flushed before the process ends.\nmain(process.argv.slice(2)).then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n if (isUsageError(error)) {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`skiss: ${message}\\nTry 'skiss --help' for more information.\\n`);\n process.exitCode = EXIT_USAGE;\n return;\n }\n // Anything else is a bug (`compile` never throws by contract), so the\n // stack is the useful output and the `--help` hint would mislead.\n const detail =\n error instanceof Error && error.stack !== undefined ? error.stack : String(error);\n process.stderr.write(`skiss: internal error: ${detail}\\n`);\n process.exitCode = EXIT_INTERNAL;\n },\n);\n","// The per-line parser: SPEC §3, §4 and §7, ADR 0004.\n//\n// Each line is read on its own. The one piece of state carried from line to\n// line is which class is current, so a field can attach to it and a field\n// with no current class can be reported as E_FIELD_WITHOUT_CLASS. No line\n// changes how another line is *read*; a line that fails to parse is skipped.\n// A failed class line clears the current class (ARCHITECTURE.md, diagnostics\n// table), so the fields under it are reported rather than silently attached\n// to the previous class.\n//\n// Nothing here throws. A line that does not match the grammar produces exactly\n// one diagnostic with severity `error` and is skipped.\n\nimport type {\n ClassNode,\n Diagnostic,\n DiagnosticCode,\n Document,\n FieldNode,\n Name,\n Primitive,\n TypeRef,\n} from './ast.ts';\n\n// SPEC §4: WS is spaces or tabs. Used for indentation, trailer delimiting and\n// working default D5 (trailing whitespace is ignored).\nconst isWs = (c: string | undefined): boolean => c === ' ' || c === '\\t';\nconst trimWs = (s: string): string => s.replace(/^[ \\t]+/, '').replace(/[ \\t]+$/, '');\n\nconst CLASS_NAME = /^[A-Z][A-Za-z0-9]*$/;\nconst FIELD_NAME = /^[a-z][A-Za-z0-9]*$/;\nconst SYSTEM_OR_VALUE = /^[A-Za-z][A-Za-z0-9_-]*$/;\n\n/**\n * SPEC §3.2: the primitives and the aliases that name them. The one table;\n * `resolve` reads it for its type suggestions rather than keeping a second.\n */\nexport const PRIMITIVES: Record<string, Primitive> = {\n string: 'string',\n int: 'int',\n float: 'float',\n bool: 'bool',\n date: 'date',\n datetime: 'datetime',\n uri: 'uri',\n text: 'string',\n integer: 'int',\n boolean: 'bool',\n};\n\n/**\n * The primitive a type word names, or `undefined` for any other word.\n *\n * `Object.hasOwn` and not a plain `PRIMITIVES[word]`: the table is a plain\n * object, so `constructor`, `toString` and the other `Object.prototype` keys\n * would find an inherited property and read as a primitive (issue #42).\n */\nfunction primitiveFor(word: string): Primitive | undefined {\n return Object.hasOwn(PRIMITIVES, word) ? PRIMITIVES[word] : undefined;\n}\n\nconst FIELD_ORDER = 'name, `*`, `: type`, `@System`, `= Class.field`, then `#` and `?`';\nconst CLASS_ORDER = 'name, `@System`, `~ Class`, then `#` and `?`';\n\nexport function parse(source: string): Document {\n const classes: ClassNode[] = [];\n const diagnostics: Diagnostic[] = [];\n let current: ClassNode | undefined;\n\n // A single leading U+FEFF is an editor's byte order mark, not content.\n // Stripping it keeps line 1 a class line and columns equal to what the\n // editor shows, since editors hide the BOM.\n const text0 = source.startsWith('\\ufeff') ? source.slice(1) : source;\n const lines = text0.split(/\\r\\n|\\n|\\r/);\n for (let i = 0; i < lines.length; i++) {\n const line = i + 1;\n const text = (lines[i] ?? '').replace(/[ \\t]+$/, '');\n const first = text[0];\n if (first === undefined || first === '#') continue; // blank or comment, SPEC §3.1\n\n if (isWs(first)) {\n const start = text.search(/[^ \\t]/);\n if (current === undefined) {\n diagnostics.push({\n severity: 'error',\n code: 'E_FIELD_WITHOUT_CLASS',\n message: 'An indented line is a field, but there is no valid class line above it',\n line,\n col: start,\n end: text.length,\n });\n continue;\n }\n const result = parseFieldLine(text, line);\n if (result.ok) current.fields.push(result.value);\n else diagnostics.push(result.diagnostic);\n continue;\n }\n\n if (/\\p{L}/u.test(first)) {\n const result = parseClassLine(text, line);\n if (result.ok) {\n classes.push(result.value);\n current = result.value;\n } else {\n // A failed class line clears the current class: the indented lines\n // under it report E_FIELD_WITHOUT_CLASS until the next class line\n // parses, instead of attaching to the previous class.\n diagnostics.push(result.diagnostic);\n current = undefined;\n }\n continue;\n }\n\n diagnostics.push({\n severity: 'error',\n code: 'E_UNPARSABLE',\n message: 'A line at column 0 must start with a class name or `#` for a comment',\n line,\n col: 0,\n end: text.length,\n });\n }\n\n return { classes, diagnostics };\n}\n\n// ---------------------------------------------------------------------------\n// Trailer: SPEC §3.9, Delimiting.\n\ninterface Trailer {\n head: string;\n description?: string;\n note?: string;\n}\n\n/** True when the `?` at `i` stands alone: whitespace before, whitespace or end after. */\nfunction isDoubtMarker(text: string, i: number): boolean {\n return text[i] === '?' && isWs(text[i - 1]) && (i + 1 === text.length || isWs(text[i + 1]));\n}\n\nfunction splitTrailer(text: string): Trailer {\n let start = -1;\n for (let i = 1; i < text.length; i++) {\n if (!isWs(text[i - 1])) continue;\n if (text[i] === '#' || isDoubtMarker(text, i)) {\n start = i;\n break;\n }\n }\n if (start < 0) return { head: text };\n\n const trailer: Trailer = { head: text.slice(0, start).replace(/[ \\t]+$/, '') };\n if (text[start] === '?') {\n // The doubt runs to the end of the line; a later `#` is text.\n const note = trimWs(text.slice(start + 1));\n if (note !== '') trailer.note = note;\n return trailer;\n }\n // The description comes first and the first standalone `?` ends it.\n let doubt = -1;\n for (let i = start + 1; i < text.length; i++) {\n if (isDoubtMarker(text, i)) {\n doubt = i;\n break;\n }\n }\n const description = trimWs(text.slice(start + 1, doubt < 0 ? text.length : doubt));\n if (description !== '') trailer.description = description;\n if (doubt >= 0) {\n const note = trimWs(text.slice(doubt + 1));\n if (note !== '') trailer.note = note;\n }\n return trailer;\n}\n\n// ---------------------------------------------------------------------------\n// Tokens. Whitespace between tokens is not significant; `[]` is one token.\n\ntype TokenKind = 'word' | '*' | ':' | '@' | '~' | '=' | '.' | '|' | '[]' | '[' | 'other';\n\ninterface Token {\n kind: TokenKind;\n text: string;\n col: number;\n end: number;\n}\n\nconst WORD = /[\\p{L}\\p{N}_-]+/uy;\nconst OPERATORS: readonly TokenKind[] = ['*', ':', '@', '~', '=', '.', '|', '['];\n\nfunction tokenize(head: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n while (i < head.length) {\n const c = head[i] ?? '';\n if (isWs(c)) {\n i++;\n continue;\n }\n WORD.lastIndex = i;\n const word = WORD.exec(head);\n if (word !== null) {\n tokens.push({ kind: 'word', text: word[0], col: i, end: i + word[0].length });\n i += word[0].length;\n continue;\n }\n if (c === '[' && head[i + 1] === ']') {\n tokens.push({ kind: '[]', text: '[]', col: i, end: i + 2 });\n i += 2;\n continue;\n }\n // Any other character is one token. Whole code points, so a message can\n // show an astral character rather than half of it.\n const ch = String.fromCodePoint(head.codePointAt(i) ?? 0);\n const kind = OPERATORS.find((op) => op === ch) ?? 'other';\n tokens.push({ kind, text: ch, col: i, end: i + ch.length });\n i += ch.length;\n }\n return tokens;\n}\n\ninterface Cursor {\n tokens: Token[];\n pos: number;\n line: number;\n}\n\nconst peek = (c: Cursor): Token | undefined => c.tokens[c.pos];\n\nfunction take(c: Cursor): Token | undefined {\n const t = c.tokens[c.pos];\n if (t !== undefined) c.pos++;\n return t;\n}\n\nconst name = (t: Token, line: number): Name => ({ text: t.text, line, col: t.col, end: t.end });\n\n// ---------------------------------------------------------------------------\n// Results. Errors are values, never exceptions.\n\ntype Result<T> = { ok: true; value: T } | { ok: false; diagnostic: Diagnostic };\n\nfunction fail<T>(\n code: DiagnosticCode,\n message: string,\n line: number,\n span: { col: number; end: number },\n): Result<T> {\n return {\n ok: false,\n diagnostic: { severity: 'error', code, message, line, col: span.col, end: span.end },\n };\n}\n\n/** The span just after `after`, for \"expected something after X\" errors. */\nconst afterSpan = (after: Token) => ({ col: after.end, end: after.end });\n\n// ---------------------------------------------------------------------------\n// Class line: ClassName [ \"@\" System ] [ \"~\" ClassName ] [ trailer ]\n\nfunction parseClassLine(text: string, line: number): Result<ClassNode> {\n const trailer = splitTrailer(text);\n const c: Cursor = { tokens: tokenize(trailer.head), pos: 0, line };\n\n const head = take(c);\n if (head === undefined || head.kind !== 'word') {\n return fail('E_UNPARSABLE', 'A class line must start with a class name', line, {\n col: 0,\n end: Math.max(1, trailer.head.length),\n });\n }\n if (!CLASS_NAME.test(head.text)) {\n return fail(\n 'E_BAD_NAME',\n `Class names are UpperCamelCase (letters and digits, uppercase first): \\`${head.text}\\``,\n line,\n head,\n );\n }\n const node: Omit<ClassNode, 'fields'> = { name: name(head, line), line };\n\n const at = peek(c);\n if (at?.kind === '@') {\n take(c);\n const system = parseSystem(c, at);\n if (!system.ok) return system;\n node.system = system.value;\n }\n\n const tilde = peek(c);\n if (tilde?.kind === '~') {\n take(c);\n const target = take(c);\n if (target === undefined || target.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n 'Expected a class name after `~`, e.g. `CharacterPage @Community ~ Character`',\n line,\n target ?? afterSpan(tilde),\n );\n }\n if (!CLASS_NAME.test(target.text)) {\n return fail(\n 'E_BAD_NAME',\n `The class after \\`~\\` must be UpperCamelCase: \\`${target.text}\\``,\n line,\n target,\n );\n }\n node.similarTo = name(target, line);\n }\n\n const rest = peek(c);\n if (rest !== undefined) return unexpected(rest, line, 'class', CLASS_ORDER);\n\n if (trailer.description !== undefined) node.description = trailer.description;\n if (trailer.note !== undefined) node.note = trailer.note;\n return { ok: true, value: { ...node, fields: [] } };\n}\n\n// ---------------------------------------------------------------------------\n// Field line: WS field-name [ \"*\" ] [ \":\" type ] [ \"@\" System ]\n// [ \"=\" ClassName \".\" field-name ] [ trailer ]\n\nfunction parseFieldLine(text: string, line: number): Result<FieldNode> {\n const trailer = splitTrailer(text);\n const c: Cursor = { tokens: tokenize(trailer.head), pos: 0, line };\n\n const head = take(c);\n if (head === undefined) {\n // Nothing before the trailer. SPEC §3.1 defines comments at column 0\n // only, so an indented `#` line is a field line without a name.\n const col = text.search(/[^ \\t]/);\n const message =\n text[col] === '#'\n ? 'A `#` comment must start at column 0; an indented line is a field and needs a name'\n : 'A field line needs a field name before its trailer';\n return fail('E_UNPARSABLE', message, line, { col, end: Math.max(col + 1, text.length) });\n }\n if (head.kind !== 'word') return unexpected(head, line, 'field', FIELD_ORDER);\n if (!FIELD_NAME.test(head.text)) {\n return fail(\n 'E_BAD_NAME',\n `Field names are lowerCamelCase (letters and digits, lowercase first): \\`${head.text}\\``,\n line,\n head,\n );\n }\n const node: FieldNode = { name: name(head, line), line, identifier: false };\n\n const star = peek(c);\n if (star?.kind === '*') {\n take(c);\n node.identifier = true;\n node.identifierAt = name(star, line);\n }\n\n const colon = peek(c);\n if (colon?.kind === ':') {\n take(c);\n const type = parseType(c, colon);\n if (!type.ok) return type;\n node.type = type.value;\n }\n\n const at = peek(c);\n if (at?.kind === '@') {\n take(c);\n const system = parseSystem(c, at);\n if (!system.ok) return system;\n node.system = system.value;\n }\n\n const equals = peek(c);\n if (equals?.kind === '=') {\n take(c);\n const example = 'e.g. `characterId = Character.id`';\n const className = take(c);\n if (className === undefined || className.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n `Expected \\`Class.field\\` after \\`=\\`, ${example}`,\n line,\n className ?? afterSpan(equals),\n );\n }\n if (!CLASS_NAME.test(className.text)) {\n return fail(\n 'E_BAD_NAME',\n `The class after \\`=\\` must be UpperCamelCase: \\`${className.text}\\``,\n line,\n className,\n );\n }\n const dot = take(c);\n if (dot === undefined || dot.kind !== '.') {\n return fail(\n 'E_UNPARSABLE',\n `Expected \\`.\\` and a field name after \\`= ${className.text}\\`, ${example}`,\n line,\n dot ?? afterSpan(className),\n );\n }\n const fieldName = take(c);\n if (fieldName === undefined || fieldName.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n `Expected a field name after \\`= ${className.text}.\\`, ${example}`,\n line,\n fieldName ?? afterSpan(dot),\n );\n }\n if (!FIELD_NAME.test(fieldName.text)) {\n return fail(\n 'E_BAD_NAME',\n `The field after \\`= ${className.text}.\\` must be lowerCamelCase: \\`${fieldName.text}\\``,\n line,\n fieldName,\n );\n }\n node.joinsTo = { className: name(className, line), fieldName: name(fieldName, line) };\n }\n\n const rest = peek(c);\n if (rest !== undefined) return unexpected(rest, line, 'field', FIELD_ORDER);\n\n if (trailer.description !== undefined) node.description = trailer.description;\n if (trailer.note !== undefined) node.note = trailer.note;\n return { ok: true, value: node };\n}\n\n// \"@\" System, shared by class and field lines. SPEC §3.5. `at` is already consumed.\nfunction parseSystem(c: Cursor, at: Token): Result<Name> {\n const system = take(c);\n if (system === undefined || system.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n 'Expected a system name after `@`, e.g. `@Catalog`',\n c.line,\n system ?? afterSpan(at),\n );\n }\n if (!SYSTEM_OR_VALUE.test(system.text)) {\n return fail(\n 'E_UNPARSABLE',\n `A system name is letters, digits, \\`-\\` and \\`_\\`, starting with a letter: \\`${system.text}\\``,\n c.line,\n system,\n );\n }\n return { ok: true, value: name(system, c.line) };\n}\n\n// type = ( primitive | ClassName | enum ) [ \"[]\" ]. SPEC §3.2 to §3.4. `colon` is already consumed.\nfunction parseType(c: Cursor, colon: Token): Result<TypeRef> {\n const first = peek(c);\n // Working default D3: nothing type-like after the colon.\n if (first === undefined || first.kind === '*' || first.kind === '@' || first.kind === '=') {\n return fail(\n 'E_MISSING_TYPE',\n 'A colon needs a type after it, e.g. `crewSize: int`',\n c.line,\n colon,\n );\n }\n if (first.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n `Expected a type after \\`:\\`, found \\`${first.text}\\``,\n c.line,\n first,\n );\n }\n take(c);\n\n const words: Token[] = [first];\n for (let pipe = peek(c); pipe?.kind === '|'; pipe = peek(c)) {\n take(c);\n const value = take(c);\n if (value === undefined || value.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n 'Expected an enum value after `|`, e.g. `climate: arid|temperate|frozen`',\n c.line,\n value ?? afterSpan(pipe),\n );\n }\n words.push(value);\n }\n\n let many = false;\n const bracket = peek(c);\n if (bracket?.kind === '[]') {\n take(c);\n many = true;\n } else if (bracket?.kind === '[') {\n return fail(\n 'E_UNCLOSED_MANY',\n '`[` must be closed: `[]` marks a many-valued field',\n c.line,\n bracket,\n );\n }\n\n if (words.length > 1) {\n for (const w of words) {\n if (!SYSTEM_OR_VALUE.test(w.text)) {\n return fail(\n 'E_UNPARSABLE',\n `An enum value is letters, digits, \\`-\\` and \\`_\\`, starting with a letter: \\`${w.text}\\``,\n c.line,\n w,\n );\n }\n }\n return { ok: true, value: { kind: 'enum', values: words.map((w) => name(w, c.line)), many } };\n }\n\n const word = first.text;\n const primitive = primitiveFor(word);\n if (primitive !== undefined) {\n return {\n ok: true,\n value: { kind: 'primitive', name: primitive, written: name(first, c.line), many },\n };\n }\n if (/^[A-Z]/.test(word)) {\n if (!CLASS_NAME.test(word)) {\n return fail(\n 'E_BAD_NAME',\n `A referenced class must be UpperCamelCase: \\`${word}\\``,\n c.line,\n first,\n );\n }\n return { ok: true, value: { kind: 'class', name: name(first, c.line), many } };\n }\n if (/^[a-z]/.test(word)) {\n // SPEC §3.2: any other lowercase word is an unknown type; `resolve` warns.\n return { ok: true, value: { kind: 'unknown', name: name(first, c.line), many } };\n }\n return fail(\n 'E_UNPARSABLE',\n `A type is a primitive, a class name or an enum, not \\`${word}\\``,\n c.line,\n first,\n );\n}\n\n// A token left over once the fixed modifier sequence has been consumed.\nfunction unexpected<T>(\n token: Token,\n line: number,\n kind: 'class' | 'field',\n order: string,\n): Result<T> {\n const modifiers: TokenKind[] = kind === 'field' ? ['*', ':', '@', '='] : ['@', '~'];\n if (modifiers.includes(token.kind)) {\n return fail(\n 'E_UNPARSABLE',\n `\\`${token.text}\\` is out of order; a ${kind} line reads: ${order}`,\n line,\n token,\n );\n }\n if (token.text === '<') {\n return fail(\n 'E_UNPARSABLE',\n '`<` is reserved for inheritance and not yet part of the language',\n line,\n token,\n );\n }\n if (token.text === '?') {\n return fail(\n 'E_UNPARSABLE',\n '`?` attached to a word is not a marker; a doubt needs whitespace before `?` and after it',\n line,\n token,\n );\n }\n if (token.text === '#') {\n return fail('E_UNPARSABLE', 'A description needs whitespace before `#`', line, token);\n }\n return fail('E_UNPARSABLE', `Unexpected \\`${token.text}\\` on a ${kind} line`, line, token);\n}\n","// The cross-line pass: SPEC §3.2, §3.8 and §7, ADR 0004.\n//\n// `parse` reads every line on its own, so anything that needs two lines to\n// know is established here: whether a referenced class or field exists,\n// whether a name is duplicated, whether a class has more than one `*`. It\n// produces warnings only, never removes a node or a diagnostic, never throws,\n// and never touches its input.\n\nimport type {\n ClassNode,\n Diagnostic,\n DiagnosticCode,\n Document,\n FieldNode,\n JoinRef,\n Name,\n TypeRef,\n} from './ast.ts';\nimport { PRIMITIVES } from './parse.ts';\n\n/** What `resolve` returns: a `Document` whose `undeclared` list is always present. */\nexport interface ResolvedDocument extends Document {\n undeclared: Name[];\n}\n\nexport function resolve(doc: Document): ResolvedDocument {\n // A deep copy, so nothing in the output is shared with the input and the\n // identifier flags below can be cleared without mutating it (AC1).\n const out: ResolvedDocument = {\n ...doc,\n classes: doc.classes.map(copyClass),\n diagnostics: doc.diagnostics.map((d) => ({ ...d })),\n undeclared: [],\n };\n const classes = out.classes;\n\n const declared = new Set(classes.map((c) => c.name.text));\n const warnings: Diagnostic[] = [];\n const undeclared = new Map<string, Name>();\n\n const warn = (code: DiagnosticCode, message: string, at: Name): void => {\n warnings.push({ severity: 'warning', code, message, line: at.line, col: at.col, end: at.end });\n };\n\n // `: X`, `~ X` or `= X.f` with X not declared (SPEC §3.2). The reference is\n // kept; the name goes on the list a generator draws placeholders from.\n const reference = (name: Name): boolean => {\n if (declared.has(name.text)) return true;\n if (!undeclared.has(name.text)) undeclared.set(name.text, name);\n // A capitalised primitive (`players: Int`) is read as a class by SPEC\n // §3.2, so the warning names the primitive the reader meant. The\n // reference itself is untouched: the fallback is still a placeholder.\n // `Object.hasOwn` and not a plain lookup: `Constructor` would otherwise\n // find `Object.prototype.constructor` and be hinted.\n const lower = name.text.toLowerCase();\n const hint = Object.hasOwn(PRIMITIVES, lower) ? `. Did you mean \\`${lower}\\`?` : '';\n warn('W_UNDECLARED_CLASS', `class \\`${name.text}\\` is not declared${hint}`, name);\n return false;\n };\n\n // One walk in document order keeps the warnings in line order, and on one\n // line in the order the tokens are written.\n const firstClass = new Map<string, ClassNode>();\n for (const cls of classes) {\n const earlier = firstClass.get(cls.name.text);\n if (earlier === undefined) firstClass.set(cls.name.text, cls);\n else {\n // Working default D1: both are kept, the later one carries the warning.\n warn(\n 'W_DUPLICATE_CLASS',\n `class \\`${cls.name.text}\\` is already declared on line ${earlier.line}`,\n cls.name,\n );\n }\n\n // Working default D3: `~` to the class itself is not a warning in 0.1.0.\n if (cls.similarTo !== undefined) reference(cls.similarTo);\n\n const firstField = new Map<string, FieldNode>();\n let identifier: FieldNode | undefined;\n for (const field of cls.fields) {\n const earlierField = firstField.get(field.name.text);\n if (earlierField === undefined) firstField.set(field.name.text, field);\n else {\n warn(\n 'W_DUPLICATE_FIELD',\n `field \\`${field.name.text}\\` is already declared on line ${earlierField.line} in class \\`${cls.name.text}\\``,\n field.name,\n );\n }\n\n // SPEC §3.8: at most one identifier per class, the first wins. The\n // range is the `*` the warning is about (issue #16); a field carrying\n // `identifier` without a recorded position falls back to its name.\n if (field.identifier) {\n if (identifier === undefined) identifier = field;\n else {\n warn(\n 'W_MULTIPLE_IDENTIFIERS',\n `\\`*\\` on \\`${field.name.text}\\` is ignored: class \\`${cls.name.text}\\` already has the identifier \\`${identifier.name.text}\\` on line ${identifier.line}`,\n field.identifierAt ?? field.name,\n );\n field.identifier = false;\n }\n }\n\n if (field.type?.kind === 'unknown') {\n // SPEC §3.2: any other lowercase word is an unknown type; generators\n // treat it as `string`. The node stays as written.\n const word = field.type.name.text;\n const suggestion = closestTypeWord(word);\n warn(\n 'W_UNKNOWN_TYPE',\n suggestion === undefined\n ? `unknown type \\`${word}\\`, treated as \\`string\\``\n : `unknown type \\`${word}\\`, did you mean \\`${suggestion}\\`?`,\n field.type.name,\n );\n } else if (field.type?.kind === 'class') {\n reference(field.type.name);\n }\n\n if (field.joinsTo !== undefined) {\n const { className, fieldName } = field.joinsTo;\n // Working default D2: an undeclared class is one warning, not two.\n // Any declaration of a duplicated class may carry the field.\n const hasField = (c: ClassNode): boolean =>\n c.name.text === className.text && c.fields.some((f) => f.name.text === fieldName.text);\n if (reference(className) && !classes.some(hasField)) {\n warn(\n 'W_UNDECLARED_FIELD',\n `class \\`${className.text}\\` has no field \\`${fieldName.text}\\``,\n fieldName,\n );\n }\n }\n }\n }\n\n // Idempotence (AC1): a warning the document already carries is not added\n // again, so resolving a resolved document changes nothing.\n const present = new Set(out.diagnostics.map(key));\n for (const w of warnings) {\n if (!present.has(key(w))) out.diagnostics.push(w);\n }\n // Errors are in line order from `parse`; a stable sort slots the warnings\n // in and keeps errors before warnings on the same line.\n out.diagnostics.sort((a, b) => a.line - b.line);\n\n out.undeclared = [...undeclared.values()].map((n) => ({ ...n }));\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// The copy is written out for the known AST shape rather than done with\n// `structuredClone`: that throws on a document an editor has wrapped in a\n// Proxy (a reactive store) or on a node carrying a function, and `resolve`\n// must never throw. Spreads read through a Proxy's traps and off a frozen\n// object alike.\n\nconst copyName = (n: Name): Name => ({ ...n });\n\nfunction copyType(t: TypeRef): TypeRef {\n switch (t.kind) {\n case 'primitive':\n return { ...t, written: copyName(t.written) };\n case 'class':\n case 'unknown':\n return { ...t, name: copyName(t.name) };\n case 'enum':\n return { ...t, values: t.values.map(copyName) };\n }\n}\n\nconst copyJoin = (j: JoinRef): JoinRef => ({\n className: copyName(j.className),\n fieldName: copyName(j.fieldName),\n});\n\nfunction copyField(f: FieldNode): FieldNode {\n const out: FieldNode = { ...f, name: copyName(f.name) };\n if (f.identifierAt !== undefined) out.identifierAt = copyName(f.identifierAt);\n if (f.type !== undefined) out.type = copyType(f.type);\n if (f.joinsTo !== undefined) out.joinsTo = copyJoin(f.joinsTo);\n return out;\n}\n\nfunction copyClass(c: ClassNode): ClassNode {\n const out: ClassNode = { ...c, name: copyName(c.name), fields: c.fields.map(copyField) };\n if (c.system !== undefined) out.system = copyName(c.system);\n if (c.similarTo !== undefined) out.similarTo = copyName(c.similarTo);\n return out;\n}\n\nconst key = (d: Diagnostic): string =>\n [d.severity, d.code, d.line, d.col, d.end, d.message].join(' ');\n\n// ---------------------------------------------------------------------------\n// Suggestions for unknown types (AC3): the closest accepted type word within\n// Levenshtein distance 2. On equal distance the candidate sharing the longest\n// prefix with the typed word wins (`flt` is `float`, not `int`); sharing the\n// first letter is the prefix rule at length one, so it needs no extra step.\n// Primitives come before the aliases in the parser's table so a tie that\n// survives goes to the canonical name. Working default D4: inline, no\n// dependency.\n\nconst TYPE_WORDS = Object.keys(PRIMITIVES);\n\nconst MAX_DISTANCE = 2;\n\nfunction closestTypeWord(word: string): string | undefined {\n let best: string | undefined;\n let bestDistance = MAX_DISTANCE + 1;\n let bestPrefix = -1;\n for (const candidate of TYPE_WORDS) {\n const distance = levenshtein(word, candidate);\n if (distance > MAX_DISTANCE || distance > bestDistance) continue;\n const prefix = commonPrefixLength(word, candidate);\n if (distance < bestDistance || prefix > bestPrefix) {\n best = candidate;\n bestDistance = distance;\n bestPrefix = prefix;\n }\n }\n return best;\n}\n\nfunction commonPrefixLength(a: string, b: string): number {\n let i = 0;\n while (i < a.length && i < b.length && a[i] === b[i]) i++;\n return i;\n}\n\n/** Edit distance with unit insert, delete and substitute costs. */\nfunction levenshtein(a: string, b: string): number {\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n let previous = Array.from({ length: b.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n const current = [i];\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n current[j] = Math.min(\n (previous[j] ?? 0) + 1,\n (current[j - 1] ?? 0) + 1,\n (previous[j - 1] ?? 0) + cost,\n );\n }\n previous = current;\n }\n return previous[b.length] ?? 0;\n}\n","// Document -> LinkML schema as a plain object. SPEC §5 is the contract and\n// the `.linkml.yaml` fixtures are its reference output, checked by the real\n// LinkML toolchain.\n//\n// No YAML here: the schema object is the generator's output and `serialize`\n// turns it into text (ADR 0006). Fields become class-local `attributes` and\n// never top-level `slots` (ADR 0005). Never throws.\n\nimport type { ClassNode, Document, FieldNode, Primitive } from '../ast.ts';\nimport { resolve } from '../resolve.ts';\n\n/** A LinkML `annotations` block in the compact `tag: value` form (SPEC §5.3). */\nexport interface LinkMLAnnotations {\n [tag: string]: string | boolean;\n}\n\n/** One entry under a class's `attributes`. Key order is SPEC §5.3. */\nexport interface LinkMLAttribute {\n description?: string;\n range?: string;\n multivalued?: boolean;\n identifier?: boolean;\n annotations?: LinkMLAnnotations;\n}\n\n/** One entry under `classes`. Key order is SPEC §5.3. */\nexport interface LinkMLClass {\n description?: string;\n annotations?: LinkMLAnnotations;\n close_mappings?: string[];\n attributes?: Record<string, LinkMLAttribute>;\n}\n\n/** One entry under `enums`. A permissible value carries no body, hence `null`. */\nexport interface LinkMLEnum {\n permissible_values: Record<string, null>;\n}\n\n/** The whole schema. Plain data: every value here survives `JSON.stringify`. */\nexport interface LinkMLSchema {\n id: string;\n name: string;\n default_prefix: string;\n default_range: string;\n prefixes: Record<string, string>;\n imports: string[];\n classes?: Record<string, LinkMLClass>;\n enums?: Record<string, LinkMLEnum>;\n}\n\nexport interface LinkMLOptions {\n /** Normally the file name. Normalised to a valid LinkML name (SPEC §5.2). */\n schemaName: string;\n}\n\n/** SPEC §5.2: the base URI is a placeholder. */\nconst BASE_URI = 'https://example.org';\n\n/** SPEC §3.2 primitives to the LinkML built-in types `linkml:types` defines. */\nconst RANGE: Record<Primitive, string> = {\n string: 'string',\n int: 'integer',\n float: 'float',\n bool: 'boolean',\n date: 'date',\n datetime: 'datetime',\n uri: 'uri',\n};\n\nexport function toLinkML(doc: Document, opts: LinkMLOptions): LinkMLSchema {\n // A document that has not been through `resolve` has no `undeclared` list\n // and may still carry a second `*`. Resolving is idempotent, so a resolved\n // document comes out unchanged and the output is the same either way.\n const resolved = resolve(doc);\n const schemaName = linkmlName(opts.schemaName);\n\n const classes = emittedClasses(resolved.classes);\n // LinkML keeps classes and enums in one namespace, so the enum names have to\n // avoid every class this schema emits, the undeclared stubs included.\n const classNames = new Set(classes.map((cls) => cls.node.name.text));\n for (const name of resolved.undeclared) classNames.add(name.text);\n const enums = nameEnums(classes, classNames);\n\n // SPEC §5.2. `linkml` and the schema's own prefix come first; a system\n // prefix that would collide with either is not allowed to overwrite it.\n // `Object.hasOwn`, not `in`: `prefixes` is a plain object, so `in` is true\n // for `constructor` and the other `Object.prototype` keys and a real prefix\n // would be dropped.\n const prefixes: Record<string, string> = { linkml: 'https://w3id.org/linkml/' };\n if (!Object.hasOwn(prefixes, schemaName)) prefixes[schemaName] = `${BASE_URI}/${schemaName}/`;\n\n // One prefix per distinct `@System`, in the order the systems are written:\n // a class line before its own fields.\n const systemPrefix = new Map<string, string>();\n const addSystem = (system: string): void => {\n const prefix = linkmlName(system);\n if (!systemPrefix.has(system)) systemPrefix.set(system, prefix);\n if (!Object.hasOwn(prefixes, prefix)) prefixes[prefix] = `${BASE_URI}/system/${prefix}/`;\n };\n for (const { node, fields } of classes) {\n if (node.system !== undefined) addSystem(node.system.text);\n for (const field of fields) {\n if (field.system !== undefined) addSystem(field.system.text);\n }\n }\n\n // SPEC §5.1, mapping prefix: `~ Other` uses the prefix of Other's system\n // when Other is declared with an `@`, otherwise the schema's own prefix.\n const declaredSystem = new Map<string, string | undefined>();\n for (const { node } of classes) {\n if (!declaredSystem.has(node.name.text)) declaredSystem.set(node.name.text, node.system?.text);\n }\n const mappingPrefix = (target: string): string => {\n const system = declaredSystem.get(target);\n if (system === undefined) return schemaName;\n return systemPrefix.get(system) ?? schemaName;\n };\n\n const schema: LinkMLSchema = {\n id: `${BASE_URI}/${schemaName}`,\n name: schemaName,\n default_prefix: schemaName,\n default_range: 'string',\n prefixes,\n imports: ['linkml:types'],\n };\n\n const out: Record<string, LinkMLClass> = {};\n for (const cls of classes) {\n out[cls.node.name.text] = buildClass(cls, mappingPrefix, enums);\n }\n // SPEC §5.1: a reference to an undeclared class becomes a stub, after the\n // classes that are declared.\n for (const name of resolved.undeclared) {\n if (!(name.text in out)) out[name.text] = { annotations: { undeclared: true } };\n }\n if (Object.keys(out).length > 0) schema.classes = out;\n\n const enumBlock = buildEnums(classes, enums);\n if (Object.keys(enumBlock).length > 0) schema.enums = enumBlock;\n\n return schema;\n}\n\n// ---------------------------------------------------------------------------\n// Which nodes are emitted at all.\n\ninterface EmittedClass {\n node: ClassNode;\n /** The class's fields with duplicate names dropped, first declaration first. */\n fields: FieldNode[];\n}\n\n/**\n * Issue #17: `resolve` keeps both nodes of a duplicated class, which is what a\n * live preview should show, but LinkML classes are keyed by name and two nodes\n * with `*` would give one class two identifiers. The first declaration wins and\n * the later ones are not emitted; the `W_DUPLICATE_CLASS` warning already says\n * so. The same applies to a duplicate field inside one class.\n */\nfunction emittedClasses(classes: ClassNode[]): EmittedClass[] {\n const out: EmittedClass[] = [];\n const seen = new Set<string>();\n for (const node of classes) {\n if (seen.has(node.name.text)) continue;\n seen.add(node.name.text);\n const fields: FieldNode[] = [];\n const seenField = new Set<string>();\n for (const field of node.fields) {\n if (seenField.has(field.name.text)) continue;\n seenField.add(field.name.text);\n fields.push(field);\n }\n out.push({ node, fields });\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Enum naming, SPEC §5.1.\n\n/** The key an enum's name is looked up by: one attribute of one class. */\nconst useKey = (className: string, fieldName: string): string => `${className}\\u0000${fieldName}`;\n\n/**\n * An inline enum on field `climate` becomes `ClimateEnum`. Fields with the same\n * name and identical value sets share one enum; fields with the same name and\n * different value sets are each class-qualified (`PlanetClimateEnum`).\n *\n * Working default: \"identical\" is the values in the order written, and one\n * differing value set qualifies every field of that name, including the ones\n * that agree with each other.\n */\nfunction nameEnums(classes: EmittedClass[], classNames: ReadonlySet<string>): Map<string, string> {\n const uses: { className: string; fieldName: string; values: string }[] = [];\n for (const { node, fields } of classes) {\n for (const field of fields) {\n if (field.type?.kind !== 'enum') continue;\n uses.push({\n className: node.name.text,\n fieldName: field.name.text,\n values: field.type.values.map((v) => v.text).join('|'),\n });\n }\n }\n\n const valueSets = new Map<string, Set<string>>();\n for (const use of uses) {\n const seen = valueSets.get(use.fieldName) ?? new Set<string>();\n seen.add(use.values);\n valueSets.set(use.fieldName, seen);\n }\n\n // Working default: two value sets that still collide after qualification\n // (field `bookStatus` against `status` on class `Book`) keep separate enums,\n // the later one numbered. SPEC §5.1 does not cover the case. A name a class\n // already holds is numbered the same way: `gen-python` refuses a schema with\n // overlapping enum and class names.\n const taken = new Map<string, string>();\n const names = new Map<string, string>();\n for (const use of uses) {\n const shared = (valueSets.get(use.fieldName)?.size ?? 0) <= 1;\n const base = shared\n ? `${capitalise(use.fieldName)}Enum`\n : `${capitalise(use.className)}${capitalise(use.fieldName)}Enum`;\n let name = base;\n for (\n let n = 2;\n classNames.has(name) || (taken.has(name) && taken.get(name) !== use.values);\n n++\n ) {\n name = `${base}${n}`;\n }\n taken.set(name, use.values);\n names.set(useKey(use.className, use.fieldName), name);\n }\n return names;\n}\n\n/** The `enums` block, each enum at its first use and its values as written. */\nfunction buildEnums(\n classes: EmittedClass[],\n enums: Map<string, string>,\n): Record<string, LinkMLEnum> {\n const out: Record<string, LinkMLEnum> = {};\n for (const { node, fields } of classes) {\n for (const field of fields) {\n if (field.type?.kind !== 'enum') continue;\n const name = enums.get(useKey(node.name.text, field.name.text));\n if (name === undefined || name in out) continue;\n const values: Record<string, null> = {};\n for (const value of field.type.values) values[value.text] = null;\n out[name] = { permissible_values: values };\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Classes and attributes. Key order is working default D1 of issue #23,\n// matching SPEC §5.3.\n\nfunction buildClass(\n cls: EmittedClass,\n mappingPrefix: (target: string) => string,\n enums: Map<string, string>,\n): LinkMLClass {\n const { node, fields } = cls;\n const out: LinkMLClass = {};\n\n if (node.description !== undefined) out.description = node.description;\n\n const annotations: LinkMLAnnotations = {};\n if (node.system !== undefined) annotations.system = node.system.text;\n if (node.note !== undefined) annotations.note = node.note;\n if (Object.keys(annotations).length > 0) out.annotations = annotations;\n\n if (node.similarTo !== undefined) {\n const target = node.similarTo.text;\n out.close_mappings = [`${mappingPrefix(target)}:${target}`];\n }\n\n const attributes: Record<string, LinkMLAttribute> = {};\n for (const field of fields) {\n attributes[field.name.text] = buildAttribute(field, node.name.text, enums);\n }\n if (Object.keys(attributes).length > 0) out.attributes = attributes;\n\n return out;\n}\n\nfunction buildAttribute(\n field: FieldNode,\n className: string,\n enums: Map<string, string>,\n): LinkMLAttribute {\n const out: LinkMLAttribute = {};\n\n if (field.description !== undefined) out.description = field.description;\n\n const range = rangeOf(field, className, enums);\n if (range !== undefined) out.range = range;\n if (field.type?.many === true) out.multivalued = true;\n if (field.identifier) out.identifier = true;\n\n // Annotation order is the order the markers are written on the line\n // (SPEC §4): `@System`, then `= Class.field`, then `?`.\n const annotations: LinkMLAnnotations = {};\n if (field.system !== undefined) annotations.system = field.system.text;\n if (field.joinsTo !== undefined) {\n annotations.joins_to = `${field.joinsTo.className.text}.${field.joinsTo.fieldName.text}`;\n }\n if (field.note !== undefined) annotations.note = field.note;\n if (Object.keys(annotations).length > 0) out.annotations = annotations;\n\n return out;\n}\n\n/**\n * SPEC §5.1. A field with no colon has no `range` at all and takes `string`\n * from `default_range`; an unknown type is a warning at resolve time and\n * compiles to `string` here (SPEC §3.2).\n */\nfunction rangeOf(\n field: FieldNode,\n className: string,\n enums: Map<string, string>,\n): string | undefined {\n const type = field.type;\n if (type === undefined) return undefined;\n switch (type.kind) {\n case 'primitive':\n return RANGE[type.name];\n case 'class':\n return type.name.text;\n case 'unknown':\n return 'string';\n case 'enum':\n return enums.get(useKey(className, field.name.text));\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * The prefixes `linkml:types` binds. Every schema imports it, and LinkML\n * refuses a schema that binds one of these to another URI (`gen-python`:\n * \"Prefix: schema mismatch between schema and types\"). A schema or system\n * name that lands on one takes a trailing underscore instead.\n */\nconst RESERVED_PREFIXES = new Set(['linkml', 'xsd', 'shex', 'schema']);\n\n/**\n * SPEC §5.2: lowercase, every non-alphanumeric an underscore. A LinkML name\n * must match `^[a-zA-Z_][\\w.-]*$`, and the schema name is also its prefix,\n * which RDF forbids to be the bare `_` (blank nodes). So a name with no\n * letters or digits at all becomes `sketch`, one that starts with a digit\n * (`2024-inventory.skiss`) takes a leading underscore, and one that is a\n * prefix `linkml:types` already binds (`schema.skiss`) takes a trailing one.\n */\nconst linkmlName = (text: string): string => {\n const name = text.toLowerCase().replace(/[^a-z0-9]/g, '_');\n if (!/[a-z0-9]/.test(name)) return 'sketch';\n if (RESERVED_PREFIXES.has(name)) return `${name}_`;\n return /^[0-9]/.test(name) ? `_${name}` : name;\n};\n\nconst capitalise = (text: string): string => text.charAt(0).toUpperCase() + text.slice(1);\n","// Document -> Mermaid classDiagram text. The mapping table in\n// docs/ARCHITECTURE.md (Mermaid mapping) is the contract; the `.mmd`\n// fixtures are its reference output.\n//\n// A string builder and nothing more: Mermaid is a validation aid, not a\n// rendering layer, so no abstraction is built on top of it. Never throws.\n\nimport type { Document, FieldNode, TypeRef } from '../ast.ts';\nimport { resolve } from '../resolve.ts';\n\nexport interface MermaidOptions {\n /** Emit `? text` doubts as `note for` lines. Off by default. */\n notes?: boolean;\n}\n\nexport function toMermaid(doc: Document, opts?: MermaidOptions): string {\n // A document that has not been through `resolve` has no `undeclared`\n // list and may still carry a second `*`. Resolving is idempotent, so a\n // resolved document comes out unchanged and the output is the same either way.\n const resolved = resolve(doc);\n const notes = opts?.notes === true;\n\n // Output order per the table: classes, undeclared placeholders, notes,\n // relations. Notes must precede every relation line; Mermaid fails to\n // parse a note that follows a `..>` relation.\n const lines: string[] = ['classDiagram'];\n\n for (const cls of resolved.classes) {\n lines.push(` class ${cls.name.text} {`);\n if (cls.system !== undefined) lines.push(` <<${cls.system.text}>>`);\n for (const field of cls.fields) lines.push(` ${member(field)}`);\n lines.push(' }');\n }\n\n for (const name of resolved.undeclared) {\n lines.push(` class ${name.text} {`, ' <<undeclared>>', ' }');\n }\n\n if (notes) {\n for (const cls of resolved.classes) {\n if (cls.note !== undefined) lines.push(` note for ${cls.name.text} ${quote(cls.note)}`);\n for (const field of cls.fields) {\n if (field.note !== undefined) {\n lines.push(` note for ${cls.name.text} ${quote(`${field.name.text}: ${field.note}`)}`);\n }\n }\n }\n }\n\n for (const cls of resolved.classes) {\n const from = cls.name.text;\n // `~` is Mermaid's generic-type delimiter and vanishes from labels, so\n // the label is the word `similar`.\n if (cls.similarTo !== undefined) lines.push(` ${from} ..> ${cls.similarTo.text} : similar`);\n for (const field of cls.fields) {\n const type = field.type;\n if (type?.kind === 'class') {\n lines.push(\n type.many\n ? ` ${from} \"1\" --> \"*\" ${type.name.text} : ${field.name.text}`\n : ` ${from} --> ${type.name.text} : ${field.name.text}`,\n );\n }\n if (field.joinsTo !== undefined) {\n const { className, fieldName } = field.joinsTo;\n lines.push(` ${from} ..> ${className.text} : ${field.name.text} = ${fieldName.text}`);\n }\n }\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n// `*` replaces the `+` visibility marker for an identifier; a trailing `*`\n// would be Mermaid's abstract-member marker and disappear.\nfunction member(field: FieldNode): string {\n const marker = field.identifier ? '*' : '+';\n const type = field.type === undefined ? '' : `${typeText(field.type)} `;\n const system = field.system === undefined ? '' : ` @${field.system.text}`;\n return `${marker}${type}${field.name.text}${system}`;\n}\n\n// The Skiss type text verbatim: an alias such as `integer` and an unknown\n// type such as `itn` are written as typed, enum values joined with `|`,\n// `[]` appended for many.\nfunction typeText(type: TypeRef): string {\n let text: string;\n switch (type.kind) {\n case 'primitive':\n text = type.written.text;\n break;\n case 'class':\n case 'unknown':\n text = type.name.text;\n break;\n case 'enum':\n text = type.values.map((v) => v.text).join('|');\n break;\n }\n return type.many ? `${text}[]` : text;\n}\n\n// A note is a double-quoted Mermaid string, so a double quote inside the\n// doubt becomes a single quote (issue #5, AC4).\nconst quote = (text: string): string => `\"${text.replaceAll('\"', \"'\")}\"`;\n","// LinkML schema object -> text (ADR 0006). The generator returns data; this\n// is the only place that knows about YAML, and `yaml` is the library's only\n// runtime dependency.\n//\n// The YAML is held to SPEC §5.3 byte for byte, which means two-space\n// indentation, block style, no document markers, and a blank line before\n// `classes:`, before `enums:` and before every class.\n\nimport { isMap, isScalar, Scalar, visit, Document as YAMLDocument } from 'yaml';\nimport type { LinkMLSchema } from './generators/linkml.ts';\n\nexport type SerializeFormat = 'yaml' | 'json';\n\nexport function serialize(schema: LinkMLSchema, format: SerializeFormat): string {\n if (format === 'json') return `${JSON.stringify(schema, null, 2)}\\n`;\n\n // LinkML reads the file with PyYAML, which is YAML 1.1: there `yes`, `no`,\n // `on`, `off`, `y`, `n` and `12:30` are not strings. Building the document\n // in 1.1 makes the writer quote them, so a description stays the text the\n // sketch wrote.\n const doc = new YAMLDocument(schema, { version: '1.1' });\n const root = doc.contents;\n if (isMap(root)) {\n for (const pair of root.items) {\n const key = pair.key;\n if (!isScalar(key)) continue;\n if (key.value !== 'classes' && key.value !== 'enums') continue;\n key.spaceBefore = true;\n // A blank line before every class, the first one included, so the\n // section reads as separated blocks rather than one wall of keys.\n if (key.value === 'classes' && isMap(pair.value)) {\n for (const entry of pair.value.items) {\n if (isScalar(entry.key)) entry.key.spaceBefore = true;\n }\n }\n }\n }\n\n // A tab or another control character in a plain scalar is either illegal\n // YAML (PyYAML stops at a tab that starts a token) or lost; double quoting\n // escapes it. Tabs reach here because SPEC §4 counts them as whitespace, so\n // they survive into trailer text.\n visit(doc, {\n Scalar(_, node) {\n if (typeof node.value === 'string' && hasControlCharacter(node.value)) {\n node.type = Scalar.QUOTE_DOUBLE;\n }\n },\n });\n\n const text = doc.toString({\n directives: false,\n indent: 2,\n lineWidth: 0,\n // A permissible value carries no body: `arid:`, not `arid: null`.\n nullStr: '',\n });\n // A blank line before the first entry of a nested map is written at the\n // map's own indentation, so the `spaceBefore` separators above are the only\n // whitespace-only lines here: `lineWidth: 0` never folds a scalar, and a\n // scalar holding a newline is double-quoted by the pass above and stays on\n // one line. Emptying them cannot reach a value.\n return text.replace(/^[ \\t]+$/gm, '');\n}\n\n/** C0 controls and DEL. Written as codepoints: Biome bans them in a regex. */\nfunction hasControlCharacter(text: string): boolean {\n for (const character of text) {\n const code = character.codePointAt(0) ?? 0;\n if (code < 0x20 || code === 0x7f) return true;\n }\n return false;\n}\n","// The whole path in one call, for callers that want one (ADR 0006): parse,\n// resolve, generate. Never throws, because nothing it calls does; bad input\n// produces diagnostics and the output of the partial document.\n\nimport type { Diagnostic } from './ast.ts';\nimport { toLinkML } from './generators/linkml.ts';\nimport { type MermaidOptions, toMermaid } from './generators/mermaid.ts';\nimport { parse } from './parse.ts';\nimport { resolve } from './resolve.ts';\nimport { type SerializeFormat, serialize } from './serialize.ts';\n\n/** `toMermaid` text from the source. */\nexport interface MermaidCompileOptions extends MermaidOptions {\n target: 'mermaid';\n}\n\n/** `toLinkML` put through `serialize` (ADR 0006). */\nexport interface LinkMLCompileOptions {\n target: 'linkml';\n /** Normally the file name. Normalised to a valid LinkML name (SPEC §5.2). */\n schemaName: string;\n /** Defaults to `yaml`, the form LinkML itself reads. */\n format?: SerializeFormat;\n}\n\n/**\n * A union rather than one shape with optional keys, so `schemaName` is\n * required exactly when it is used and a `mermaid` call cannot carry a\n * `format` that would be ignored.\n */\nexport type CompileOptions = MermaidCompileOptions | LinkMLCompileOptions;\n\nexport interface CompileResult {\n /** The generated text, `\\n`-terminated, whatever the platform. */\n output: string;\n /** Errors from `parse` and warnings from `resolve`, in line order. */\n diagnostics: Diagnostic[];\n}\n\nexport function compile(source: string, opts: CompileOptions): CompileResult {\n const doc = resolve(parse(source));\n const output =\n opts.target === 'linkml'\n ? serialize(toLinkML(doc, { schemaName: opts.schemaName }), opts.format ?? 'yaml')\n : toMermaid(doc, { notes: opts.notes });\n return { output, diagnostics: doc.diagnostics };\n}\n","// One diagnostic as one line of text, in the `file:line:col: severity CODE\n// message` shape compilers print and editors and terminals know how to\n// jump to. Shared by the CLI and any editor that wants the same text\n// (issue #6, working default D4).\n\nimport type { Diagnostic } from './ast.ts';\n\n/**\n * `<file>:<line>:<col>: <severity> <CODE> <message>`, without a trailing\n * newline. The `<file>:` prefix is omitted when `file` is not given, and\n * `<col>` when the diagnostic has no column. Columns are printed 1-based, as\n * the `file:line:col` convention expects, while `Diagnostic.col` stays\n * 0-based for editors.\n */\nexport function formatDiagnostic(d: Diagnostic, file?: string): string {\n const where = [file, d.line, d.col === undefined ? undefined : d.col + 1]\n .filter((part) => part !== undefined)\n .join(':');\n return `${where}: ${d.severity} ${d.code} ${d.message}`;\n}\n","export type {\n ClassNode,\n Diagnostic,\n DiagnosticCode,\n Document,\n FieldNode,\n JoinRef,\n Name,\n Primitive,\n Severity,\n TypeRef,\n} from './ast.ts';\nexport {\n type CompileOptions,\n type CompileResult,\n compile,\n type LinkMLCompileOptions,\n type MermaidCompileOptions,\n} from './compile.ts';\nexport { formatDiagnostic } from './diagnostics.ts';\nexport {\n type LinkMLAnnotations,\n type LinkMLAttribute,\n type LinkMLClass,\n type LinkMLEnum,\n type LinkMLOptions,\n type LinkMLSchema,\n toLinkML,\n} from './generators/linkml.ts';\nexport { type MermaidOptions, toMermaid } from './generators/mermaid.ts';\nexport { parse } from './parse.ts';\nexport { type ResolvedDocument, resolve } from './resolve.ts';\nexport { type SerializeFormat, serialize } from './serialize.ts';\n\nexport const VERSION = '0.2.1';\n"],"mappings":"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","names":["name","name","name","key"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/parse.ts","../src/resolve.ts","../src/generators/linkml.ts","../src/generators/mermaid.ts","../src/serialize.ts","../src/compile.ts","../src/diagnostics.ts","../src/generators/skiss.ts","../src/generators/from-linkml.ts","../src/import.ts","../src/index.ts"],"sourcesContent":["// The `skiss` command. Node-only, and the only file in the package that\n// touches files or `process` (ADR 0003). A thin layer: read, call the\n// library, write. Anything that looks like logic belongs in the library.\n\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { basename, extname } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport type { Diagnostic, Dropped } from './index.ts';\nimport { compile, formatDiagnostic, formatDropped, importLinkML, VERSION } from './index.ts';\n\nconst HELP = `Usage: skiss <command> [options]\n\nCommands:\n diagram <file> Write a Mermaid class diagram for a .skiss file.\n compile <file> Write a LinkML schema for a .skiss file.\n import <file> Write Skiss for a LinkML schema file, YAML or JSON.\n <file> may be - to read standard input.\n\nOptions:\n -o, --output <path> Write the output to <path> instead of standard output\n --notes diagram: emit \\`? text\\` doubts as Mermaid notes\n --json compile: write the schema as JSON instead of YAML\n --name <name> compile: the schema name. Defaults to the file's\n basename without its extension, or \\`sketch\\` for\n standard input.\n --strict Exit 1 when the input has any diagnostic; for import,\n also when the projection dropped anything\n -h, --help Show this help and exit\n --version Print the version and exit\n\nDiagnostics go to standard error, one per line:\n <file>:<line>:<col>: <severity> <CODE> <message>\n\nimport writes what the projection could not carry to standard error too, as\none line before the diagnostics. Its diagnostics are the ones the sketch it\nwrote has, so their line numbers are lines of that sketch.\n\nExit codes:\n 0 the output was produced\n 1 --strict and the input has diagnostics (the output is still written)\n 2 usage error, missing file or unreadable input\n 70 internal error, a bug in skiss\n`;\n\n/** Issue #6, AC4 and AC5. 70 is `EX_SOFTWARE` from `sysexits.h`. */\nconst EXIT_OK = 0;\nconst EXIT_STRICT = 1;\nconst EXIT_USAGE = 2;\nconst EXIT_INTERNAL = 70;\n\n/**\n * Which options each command takes. `--help` and `--version` are answered\n * before a command is read and are not listed. An option that belongs to the\n * other command is a usage error rather than something silently ignored.\n */\nconst COMMANDS = {\n diagram: ['output', 'notes', 'strict'],\n compile: ['output', 'json', 'name', 'strict'],\n import: ['output', 'strict'],\n} as const;\n\ntype Command = keyof typeof COMMANDS;\n\nconst isCommand = (text: string): text is Command => Object.hasOwn(COMMANDS, text);\n\n/** Thrown for anything that ends the run with exit code 2. */\nclass UsageError extends Error {}\n\n/**\n * Our own `UsageError`, or a `parseArgs` rejection (unknown option, `-o`\n * with no path), whose `code` is one of the `ERR_PARSE_ARGS_*` family.\n */\nfunction isUsageError(error: unknown): boolean {\n if (error instanceof UsageError) return true;\n if (typeof error !== 'object' || error === null || !('code' in error)) return false;\n return typeof error.code === 'string' && error.code.startsWith('ERR_PARSE_ARGS');\n}\n\nasync function main(argv: string[]): Promise<number> {\n if (argv.length === 0) {\n process.stderr.write(HELP);\n return EXIT_USAGE;\n }\n\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n output: { type: 'string', short: 'o' },\n notes: { type: 'boolean' },\n json: { type: 'boolean' },\n name: { type: 'string' },\n strict: { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean' },\n },\n allowPositionals: true,\n strict: true,\n });\n\n if (values.help === true) {\n process.stdout.write(HELP);\n return EXIT_OK;\n }\n if (values.version === true) {\n process.stdout.write(`${VERSION}\\n`);\n return EXIT_OK;\n }\n\n const [command, file, ...extra] = positionals;\n if (command === undefined) throw new UsageError('missing command');\n if (!isCommand(command)) throw new UsageError(`unknown command \\`${command}\\``);\n if (file === undefined)\n throw new UsageError(`${command} needs a <file>, or - for standard input`);\n if (extra.length > 0) throw new UsageError(`unexpected argument \\`${extra[0]}\\``);\n\n // `parseArgs` leaves an option out of `values` when it was not given, so\n // the keys here are exactly what was typed.\n const accepted: readonly string[] = COMMANDS[command];\n for (const option of Object.keys(values)) {\n if (!accepted.includes(option)) {\n throw new UsageError(`\\`${command}\\` does not take \\`--${option}\\``);\n }\n }\n\n const source = file === '-' ? await readStdin() : await readSource(file);\n // `import` reads LinkML rather than Skiss, and is the one command whose\n // result carries a SPEC §8 report of what the projection could not carry.\n const { output, diagnostics, dropped } = runCommand(command, source, file, values);\n\n const label = file === '-' ? '<stdin>' : file;\n // Issue #47, D2: the report is information and not an error, so it is\n // written whether or not `--strict` was given, and before the diagnostics.\n const report = formatDropped(dropped);\n if (report !== '') process.stderr.write(`${report}\\n`);\n for (const d of diagnostics) process.stderr.write(`${formatDiagnostic(d, label)}\\n`);\n\n if (values.output === undefined) process.stdout.write(output);\n else await writeOutput(values.output, output);\n\n const strict = values.strict === true && (diagnostics.length > 0 || dropped.length > 0);\n return strict ? EXIT_STRICT : EXIT_OK;\n}\n\n/** What every command produces. `dropped` is empty for all but `import`. */\ninterface CommandResult {\n output: string;\n diagnostics: Diagnostic[];\n dropped: Dropped[];\n}\n\nfunction runCommand(\n command: Command,\n source: string,\n file: string,\n values: { name?: string; json?: boolean; notes?: boolean },\n): CommandResult {\n if (command === 'import') return importLinkML(source);\n if (command === 'compile') {\n return {\n ...compile(source, {\n target: 'linkml',\n schemaName: values.name ?? defaultSchemaName(file),\n format: values.json === true ? 'json' : 'yaml',\n }),\n dropped: [],\n };\n }\n return { ...compile(source, { target: 'mermaid', notes: values.notes }), dropped: [] };\n}\n\n/**\n * Issue #24, AC2. `toLinkML` normalises this to a valid LinkML name\n * (SPEC §5.2), so a basename with a dot or a dash in it needs nothing here.\n */\nconst defaultSchemaName = (file: string): string =>\n file === '-' ? 'sketch' : basename(file, extname(file));\n\nasync function readSource(file: string): Promise<string> {\n try {\n return await readFile(file, 'utf8');\n } catch (error) {\n throw new UsageError(`cannot read \\`${file}\\`: ${reason(error)}`);\n }\n}\n\nasync function readStdin(): Promise<string> {\n try {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n } catch (error) {\n throw new UsageError(`cannot read standard input: ${reason(error)}`);\n }\n}\n\n/** D1: the path is written verbatim; no extension is inferred from the target. */\nasync function writeOutput(path: string, text: string): Promise<void> {\n try {\n await writeFile(path, text, 'utf8');\n } catch (error) {\n throw new UsageError(`cannot write \\`${path}\\`: ${reason(error)}`);\n }\n}\n\n/** The OS error code when there is one (`ENOENT`), else the message. */\nfunction reason(error: unknown): string {\n if (error instanceof Error) {\n const code = (error as NodeJS.ErrnoException).code;\n return code ?? error.message;\n }\n return String(error);\n}\n\n// `process.exitCode` rather than `process.exit()`, so a piped stdout is\n// flushed before the process ends.\nmain(process.argv.slice(2)).then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n if (isUsageError(error)) {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`skiss: ${message}\\nTry 'skiss --help' for more information.\\n`);\n process.exitCode = EXIT_USAGE;\n return;\n }\n // Anything else is a bug (`compile` never throws by contract), so the\n // stack is the useful output and the `--help` hint would mislead.\n const detail =\n error instanceof Error && error.stack !== undefined ? error.stack : String(error);\n process.stderr.write(`skiss: internal error: ${detail}\\n`);\n process.exitCode = EXIT_INTERNAL;\n },\n);\n","// The per-line parser: SPEC §3, §4 and §7, ADR 0004.\n//\n// Each line is read on its own. The one piece of state carried from line to\n// line is which class is current, so a field can attach to it and a field\n// with no current class can be reported as E_FIELD_WITHOUT_CLASS. No line\n// changes how another line is *read*; a line that fails to parse is skipped.\n// A failed class line clears the current class (ARCHITECTURE.md, diagnostics\n// table), so the fields under it are reported rather than silently attached\n// to the previous class.\n//\n// Nothing here throws. A line that does not match the grammar produces exactly\n// one diagnostic with severity `error` and is skipped.\n\nimport type {\n ClassNode,\n Diagnostic,\n DiagnosticCode,\n Document,\n FieldNode,\n Name,\n Primitive,\n TypeRef,\n} from './ast.ts';\n\n// SPEC §4: WS is spaces or tabs. Used for indentation, trailer delimiting and\n// working default D5 (trailing whitespace is ignored).\nconst isWs = (c: string | undefined): boolean => c === ' ' || c === '\\t';\nconst trimWs = (s: string): string => s.replace(/^[ \\t]+/, '').replace(/[ \\t]+$/, '');\n\n// SPEC §4: the name productions. Exported because a projection from LinkML\n// has to know what it may write (SPEC §8, Names), and one grammar in one\n// place is the point of the parser owning them.\nexport const CLASS_NAME = /^[A-Z][A-Za-z0-9]*$/;\nexport const FIELD_NAME = /^[a-z][A-Za-z0-9]*$/;\nexport const SYSTEM_OR_VALUE = /^[A-Za-z][A-Za-z0-9_-]*$/;\n\n/**\n * SPEC §3.2: the primitives and the aliases that name them. The one table;\n * `resolve` reads it for its type suggestions rather than keeping a second.\n */\nexport const PRIMITIVES: Record<string, Primitive> = {\n string: 'string',\n int: 'int',\n float: 'float',\n bool: 'bool',\n date: 'date',\n datetime: 'datetime',\n uri: 'uri',\n text: 'string',\n integer: 'int',\n boolean: 'bool',\n};\n\n/**\n * The primitive a type word names, or `undefined` for any other word.\n *\n * `Object.hasOwn` and not a plain `PRIMITIVES[word]`: the table is a plain\n * object, so `constructor`, `toString` and the other `Object.prototype` keys\n * would find an inherited property and read as a primitive (issue #42).\n */\nfunction primitiveFor(word: string): Primitive | undefined {\n return Object.hasOwn(PRIMITIVES, word) ? PRIMITIVES[word] : undefined;\n}\n\nconst FIELD_ORDER = 'name, `*`, `: type`, `@System`, `= Class.field`, then `#` and `?`';\nconst CLASS_ORDER = 'name, `@System`, `~ Class`, then `#` and `?`';\n\nexport function parse(source: string): Document {\n const classes: ClassNode[] = [];\n const diagnostics: Diagnostic[] = [];\n let current: ClassNode | undefined;\n\n // A single leading U+FEFF is an editor's byte order mark, not content.\n // Stripping it keeps line 1 a class line and columns equal to what the\n // editor shows, since editors hide the BOM.\n const text0 = source.startsWith('\\ufeff') ? source.slice(1) : source;\n const lines = text0.split(/\\r\\n|\\n|\\r/);\n for (let i = 0; i < lines.length; i++) {\n const line = i + 1;\n const text = (lines[i] ?? '').replace(/[ \\t]+$/, '');\n const first = text[0];\n if (first === undefined || first === '#') continue; // blank or comment, SPEC §3.1\n\n if (isWs(first)) {\n const start = text.search(/[^ \\t]/);\n if (current === undefined) {\n diagnostics.push({\n severity: 'error',\n code: 'E_FIELD_WITHOUT_CLASS',\n message: 'An indented line is a field, but there is no valid class line above it',\n line,\n col: start,\n end: text.length,\n });\n continue;\n }\n const result = parseFieldLine(text, line);\n if (result.ok) current.fields.push(result.value);\n else diagnostics.push(result.diagnostic);\n continue;\n }\n\n if (/\\p{L}/u.test(first)) {\n const result = parseClassLine(text, line);\n if (result.ok) {\n classes.push(result.value);\n current = result.value;\n } else {\n // A failed class line clears the current class: the indented lines\n // under it report E_FIELD_WITHOUT_CLASS until the next class line\n // parses, instead of attaching to the previous class.\n diagnostics.push(result.diagnostic);\n current = undefined;\n }\n continue;\n }\n\n diagnostics.push({\n severity: 'error',\n code: 'E_UNPARSABLE',\n message: 'A line at column 0 must start with a class name or `#` for a comment',\n line,\n col: 0,\n end: text.length,\n });\n }\n\n return { classes, diagnostics };\n}\n\n// ---------------------------------------------------------------------------\n// Trailer: SPEC §3.9, Delimiting.\n\ninterface Trailer {\n head: string;\n description?: string;\n note?: string;\n}\n\n/** True when the `?` at `i` stands alone: whitespace before, whitespace or end after. */\nfunction isDoubtMarker(text: string, i: number): boolean {\n return text[i] === '?' && isWs(text[i - 1]) && (i + 1 === text.length || isWs(text[i + 1]));\n}\n\nfunction splitTrailer(text: string): Trailer {\n let start = -1;\n for (let i = 1; i < text.length; i++) {\n if (!isWs(text[i - 1])) continue;\n if (text[i] === '#' || isDoubtMarker(text, i)) {\n start = i;\n break;\n }\n }\n if (start < 0) return { head: text };\n\n const trailer: Trailer = { head: text.slice(0, start).replace(/[ \\t]+$/, '') };\n if (text[start] === '?') {\n // The doubt runs to the end of the line; a later `#` is text.\n const note = trimWs(text.slice(start + 1));\n if (note !== '') trailer.note = note;\n return trailer;\n }\n // The description comes first and the first standalone `?` ends it.\n let doubt = -1;\n for (let i = start + 1; i < text.length; i++) {\n if (isDoubtMarker(text, i)) {\n doubt = i;\n break;\n }\n }\n const description = trimWs(text.slice(start + 1, doubt < 0 ? text.length : doubt));\n if (description !== '') trailer.description = description;\n if (doubt >= 0) {\n const note = trimWs(text.slice(doubt + 1));\n if (note !== '') trailer.note = note;\n }\n return trailer;\n}\n\n// ---------------------------------------------------------------------------\n// Tokens. Whitespace between tokens is not significant; `[]` is one token.\n\ntype TokenKind = 'word' | '*' | ':' | '@' | '~' | '=' | '.' | '|' | '[]' | '[' | 'other';\n\ninterface Token {\n kind: TokenKind;\n text: string;\n col: number;\n end: number;\n}\n\nconst WORD = /[\\p{L}\\p{N}_-]+/uy;\nconst OPERATORS: readonly TokenKind[] = ['*', ':', '@', '~', '=', '.', '|', '['];\n\nfunction tokenize(head: string): Token[] {\n const tokens: Token[] = [];\n let i = 0;\n while (i < head.length) {\n const c = head[i] ?? '';\n if (isWs(c)) {\n i++;\n continue;\n }\n WORD.lastIndex = i;\n const word = WORD.exec(head);\n if (word !== null) {\n tokens.push({ kind: 'word', text: word[0], col: i, end: i + word[0].length });\n i += word[0].length;\n continue;\n }\n if (c === '[' && head[i + 1] === ']') {\n tokens.push({ kind: '[]', text: '[]', col: i, end: i + 2 });\n i += 2;\n continue;\n }\n // Any other character is one token. Whole code points, so a message can\n // show an astral character rather than half of it.\n const ch = String.fromCodePoint(head.codePointAt(i) ?? 0);\n const kind = OPERATORS.find((op) => op === ch) ?? 'other';\n tokens.push({ kind, text: ch, col: i, end: i + ch.length });\n i += ch.length;\n }\n return tokens;\n}\n\ninterface Cursor {\n tokens: Token[];\n pos: number;\n line: number;\n}\n\nconst peek = (c: Cursor): Token | undefined => c.tokens[c.pos];\n\nfunction take(c: Cursor): Token | undefined {\n const t = c.tokens[c.pos];\n if (t !== undefined) c.pos++;\n return t;\n}\n\nconst name = (t: Token, line: number): Name => ({ text: t.text, line, col: t.col, end: t.end });\n\n// ---------------------------------------------------------------------------\n// Results. Errors are values, never exceptions.\n\ntype Result<T> = { ok: true; value: T } | { ok: false; diagnostic: Diagnostic };\n\nfunction fail<T>(\n code: DiagnosticCode,\n message: string,\n line: number,\n span: { col: number; end: number },\n): Result<T> {\n return {\n ok: false,\n diagnostic: { severity: 'error', code, message, line, col: span.col, end: span.end },\n };\n}\n\n/** The span just after `after`, for \"expected something after X\" errors. */\nconst afterSpan = (after: Token) => ({ col: after.end, end: after.end });\n\n// ---------------------------------------------------------------------------\n// Class line: ClassName [ \"@\" System ] [ \"~\" ClassName ] [ trailer ]\n\nfunction parseClassLine(text: string, line: number): Result<ClassNode> {\n const trailer = splitTrailer(text);\n const c: Cursor = { tokens: tokenize(trailer.head), pos: 0, line };\n\n const head = take(c);\n if (head === undefined || head.kind !== 'word') {\n return fail('E_UNPARSABLE', 'A class line must start with a class name', line, {\n col: 0,\n end: Math.max(1, trailer.head.length),\n });\n }\n if (!CLASS_NAME.test(head.text)) {\n return fail(\n 'E_BAD_NAME',\n `Class names are UpperCamelCase (letters and digits, uppercase first): \\`${head.text}\\``,\n line,\n head,\n );\n }\n const node: Omit<ClassNode, 'fields'> = { name: name(head, line), line };\n\n const at = peek(c);\n if (at?.kind === '@') {\n take(c);\n const system = parseSystem(c, at);\n if (!system.ok) return system;\n node.system = system.value;\n }\n\n const tilde = peek(c);\n if (tilde?.kind === '~') {\n take(c);\n const target = take(c);\n if (target === undefined || target.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n 'Expected a class name after `~`, e.g. `CharacterPage @Community ~ Character`',\n line,\n target ?? afterSpan(tilde),\n );\n }\n if (!CLASS_NAME.test(target.text)) {\n return fail(\n 'E_BAD_NAME',\n `The class after \\`~\\` must be UpperCamelCase: \\`${target.text}\\``,\n line,\n target,\n );\n }\n node.similarTo = name(target, line);\n }\n\n const rest = peek(c);\n if (rest !== undefined) return unexpected(rest, line, 'class', CLASS_ORDER);\n\n if (trailer.description !== undefined) node.description = trailer.description;\n if (trailer.note !== undefined) node.note = trailer.note;\n return { ok: true, value: { ...node, fields: [] } };\n}\n\n// ---------------------------------------------------------------------------\n// Field line: WS field-name [ \"*\" ] [ \":\" type ] [ \"@\" System ]\n// [ \"=\" ClassName \".\" field-name ] [ trailer ]\n\nfunction parseFieldLine(text: string, line: number): Result<FieldNode> {\n const trailer = splitTrailer(text);\n const c: Cursor = { tokens: tokenize(trailer.head), pos: 0, line };\n\n const head = take(c);\n if (head === undefined) {\n // Nothing before the trailer. SPEC §3.1 defines comments at column 0\n // only, so an indented `#` line is a field line without a name.\n const col = text.search(/[^ \\t]/);\n const message =\n text[col] === '#'\n ? 'A `#` comment must start at column 0; an indented line is a field and needs a name'\n : 'A field line needs a field name before its trailer';\n return fail('E_UNPARSABLE', message, line, { col, end: Math.max(col + 1, text.length) });\n }\n if (head.kind !== 'word') return unexpected(head, line, 'field', FIELD_ORDER);\n if (!FIELD_NAME.test(head.text)) {\n return fail(\n 'E_BAD_NAME',\n `Field names are lowerCamelCase (letters and digits, lowercase first): \\`${head.text}\\``,\n line,\n head,\n );\n }\n const node: FieldNode = { name: name(head, line), line, identifier: false };\n\n const star = peek(c);\n if (star?.kind === '*') {\n take(c);\n node.identifier = true;\n node.identifierAt = name(star, line);\n }\n\n const colon = peek(c);\n if (colon?.kind === ':') {\n take(c);\n const type = parseType(c, colon);\n if (!type.ok) return type;\n node.type = type.value;\n }\n\n const at = peek(c);\n if (at?.kind === '@') {\n take(c);\n const system = parseSystem(c, at);\n if (!system.ok) return system;\n node.system = system.value;\n }\n\n const equals = peek(c);\n if (equals?.kind === '=') {\n take(c);\n const example = 'e.g. `characterId = Character.id`';\n const className = take(c);\n if (className === undefined || className.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n `Expected \\`Class.field\\` after \\`=\\`, ${example}`,\n line,\n className ?? afterSpan(equals),\n );\n }\n if (!CLASS_NAME.test(className.text)) {\n return fail(\n 'E_BAD_NAME',\n `The class after \\`=\\` must be UpperCamelCase: \\`${className.text}\\``,\n line,\n className,\n );\n }\n const dot = take(c);\n if (dot === undefined || dot.kind !== '.') {\n return fail(\n 'E_UNPARSABLE',\n `Expected \\`.\\` and a field name after \\`= ${className.text}\\`, ${example}`,\n line,\n dot ?? afterSpan(className),\n );\n }\n const fieldName = take(c);\n if (fieldName === undefined || fieldName.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n `Expected a field name after \\`= ${className.text}.\\`, ${example}`,\n line,\n fieldName ?? afterSpan(dot),\n );\n }\n if (!FIELD_NAME.test(fieldName.text)) {\n return fail(\n 'E_BAD_NAME',\n `The field after \\`= ${className.text}.\\` must be lowerCamelCase: \\`${fieldName.text}\\``,\n line,\n fieldName,\n );\n }\n node.joinsTo = { className: name(className, line), fieldName: name(fieldName, line) };\n }\n\n const rest = peek(c);\n if (rest !== undefined) return unexpected(rest, line, 'field', FIELD_ORDER);\n\n if (trailer.description !== undefined) node.description = trailer.description;\n if (trailer.note !== undefined) node.note = trailer.note;\n return { ok: true, value: node };\n}\n\n// \"@\" System, shared by class and field lines. SPEC §3.5. `at` is already consumed.\nfunction parseSystem(c: Cursor, at: Token): Result<Name> {\n const system = take(c);\n if (system === undefined || system.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n 'Expected a system name after `@`, e.g. `@Catalog`',\n c.line,\n system ?? afterSpan(at),\n );\n }\n if (!SYSTEM_OR_VALUE.test(system.text)) {\n return fail(\n 'E_UNPARSABLE',\n `A system name is letters, digits, \\`-\\` and \\`_\\`, starting with a letter: \\`${system.text}\\``,\n c.line,\n system,\n );\n }\n return { ok: true, value: name(system, c.line) };\n}\n\n// type = ( primitive | ClassName | enum ) [ \"[]\" ]. SPEC §3.2 to §3.4. `colon` is already consumed.\nfunction parseType(c: Cursor, colon: Token): Result<TypeRef> {\n const first = peek(c);\n // Working default D3: nothing type-like after the colon.\n if (first === undefined || first.kind === '*' || first.kind === '@' || first.kind === '=') {\n return fail(\n 'E_MISSING_TYPE',\n 'A colon needs a type after it, e.g. `crewSize: int`',\n c.line,\n colon,\n );\n }\n if (first.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n `Expected a type after \\`:\\`, found \\`${first.text}\\``,\n c.line,\n first,\n );\n }\n take(c);\n\n const words: Token[] = [first];\n for (let pipe = peek(c); pipe?.kind === '|'; pipe = peek(c)) {\n take(c);\n const value = take(c);\n if (value === undefined || value.kind !== 'word') {\n return fail(\n 'E_UNPARSABLE',\n 'Expected an enum value after `|`, e.g. `climate: arid|temperate|frozen`',\n c.line,\n value ?? afterSpan(pipe),\n );\n }\n words.push(value);\n }\n\n let many = false;\n const bracket = peek(c);\n if (bracket?.kind === '[]') {\n take(c);\n many = true;\n } else if (bracket?.kind === '[') {\n return fail(\n 'E_UNCLOSED_MANY',\n '`[` must be closed: `[]` marks a many-valued field',\n c.line,\n bracket,\n );\n }\n\n if (words.length > 1) {\n for (const w of words) {\n if (!SYSTEM_OR_VALUE.test(w.text)) {\n return fail(\n 'E_UNPARSABLE',\n `An enum value is letters, digits, \\`-\\` and \\`_\\`, starting with a letter: \\`${w.text}\\``,\n c.line,\n w,\n );\n }\n }\n return { ok: true, value: { kind: 'enum', values: words.map((w) => name(w, c.line)), many } };\n }\n\n const word = first.text;\n const primitive = primitiveFor(word);\n if (primitive !== undefined) {\n return {\n ok: true,\n value: { kind: 'primitive', name: primitive, written: name(first, c.line), many },\n };\n }\n if (/^[A-Z]/.test(word)) {\n if (!CLASS_NAME.test(word)) {\n return fail(\n 'E_BAD_NAME',\n `A referenced class must be UpperCamelCase: \\`${word}\\``,\n c.line,\n first,\n );\n }\n return { ok: true, value: { kind: 'class', name: name(first, c.line), many } };\n }\n if (/^[a-z]/.test(word)) {\n // SPEC §3.2: any other lowercase word is an unknown type; `resolve` warns.\n return { ok: true, value: { kind: 'unknown', name: name(first, c.line), many } };\n }\n return fail(\n 'E_UNPARSABLE',\n `A type is a primitive, a class name or an enum, not \\`${word}\\``,\n c.line,\n first,\n );\n}\n\n// A token left over once the fixed modifier sequence has been consumed.\nfunction unexpected<T>(\n token: Token,\n line: number,\n kind: 'class' | 'field',\n order: string,\n): Result<T> {\n const modifiers: TokenKind[] = kind === 'field' ? ['*', ':', '@', '='] : ['@', '~'];\n if (modifiers.includes(token.kind)) {\n return fail(\n 'E_UNPARSABLE',\n `\\`${token.text}\\` is out of order; a ${kind} line reads: ${order}`,\n line,\n token,\n );\n }\n if (token.text === '<') {\n return fail(\n 'E_UNPARSABLE',\n '`<` is reserved for inheritance and not yet part of the language',\n line,\n token,\n );\n }\n if (token.text === '?') {\n return fail(\n 'E_UNPARSABLE',\n '`?` attached to a word is not a marker; a doubt needs whitespace before `?` and after it',\n line,\n token,\n );\n }\n if (token.text === '#') {\n return fail('E_UNPARSABLE', 'A description needs whitespace before `#`', line, token);\n }\n return fail('E_UNPARSABLE', `Unexpected \\`${token.text}\\` on a ${kind} line`, line, token);\n}\n","// The cross-line pass: SPEC §3.2, §3.8 and §7, ADR 0004.\n//\n// `parse` reads every line on its own, so anything that needs two lines to\n// know is established here: whether a referenced class or field exists,\n// whether a name is duplicated, whether a class has more than one `*`. It\n// produces warnings only, never removes a node or a diagnostic, never throws,\n// and never touches its input.\n\nimport type {\n ClassNode,\n Diagnostic,\n DiagnosticCode,\n Document,\n FieldNode,\n JoinRef,\n Name,\n TypeRef,\n} from './ast.ts';\nimport { PRIMITIVES } from './parse.ts';\n\n/** What `resolve` returns: a `Document` whose `undeclared` list is always present. */\nexport interface ResolvedDocument extends Document {\n undeclared: Name[];\n}\n\nexport function resolve(doc: Document): ResolvedDocument {\n // A deep copy, so nothing in the output is shared with the input and the\n // identifier flags below can be cleared without mutating it (AC1).\n const out: ResolvedDocument = {\n ...doc,\n classes: doc.classes.map(copyClass),\n diagnostics: doc.diagnostics.map((d) => ({ ...d })),\n undeclared: [],\n };\n const classes = out.classes;\n\n const declared = new Set(classes.map((c) => c.name.text));\n const warnings: Diagnostic[] = [];\n const undeclared = new Map<string, Name>();\n\n const warn = (code: DiagnosticCode, message: string, at: Name): void => {\n warnings.push({ severity: 'warning', code, message, line: at.line, col: at.col, end: at.end });\n };\n\n // `: X`, `~ X` or `= X.f` with X not declared (SPEC §3.2). The reference is\n // kept; the name goes on the list a generator draws placeholders from.\n const reference = (name: Name): boolean => {\n if (declared.has(name.text)) return true;\n if (!undeclared.has(name.text)) undeclared.set(name.text, name);\n // A capitalised primitive (`players: Int`) is read as a class by SPEC\n // §3.2, so the warning names the primitive the reader meant. The\n // reference itself is untouched: the fallback is still a placeholder.\n // `Object.hasOwn` and not a plain lookup: `Constructor` would otherwise\n // find `Object.prototype.constructor` and be hinted.\n const lower = name.text.toLowerCase();\n const hint = Object.hasOwn(PRIMITIVES, lower) ? `. Did you mean \\`${lower}\\`?` : '';\n warn('W_UNDECLARED_CLASS', `class \\`${name.text}\\` is not declared${hint}`, name);\n return false;\n };\n\n // One walk in document order keeps the warnings in line order, and on one\n // line in the order the tokens are written.\n const firstClass = new Map<string, ClassNode>();\n for (const cls of classes) {\n const earlier = firstClass.get(cls.name.text);\n if (earlier === undefined) firstClass.set(cls.name.text, cls);\n else {\n // Working default D1: both are kept, the later one carries the warning.\n warn(\n 'W_DUPLICATE_CLASS',\n `class \\`${cls.name.text}\\` is already declared on line ${earlier.line}`,\n cls.name,\n );\n }\n\n // Working default D3: `~` to the class itself is not a warning in 0.1.0.\n if (cls.similarTo !== undefined) reference(cls.similarTo);\n\n const firstField = new Map<string, FieldNode>();\n let identifier: FieldNode | undefined;\n for (const field of cls.fields) {\n const earlierField = firstField.get(field.name.text);\n if (earlierField === undefined) firstField.set(field.name.text, field);\n else {\n warn(\n 'W_DUPLICATE_FIELD',\n `field \\`${field.name.text}\\` is already declared on line ${earlierField.line} in class \\`${cls.name.text}\\``,\n field.name,\n );\n }\n\n // SPEC §3.8: at most one identifier per class, the first wins. The\n // range is the `*` the warning is about (issue #16); a field carrying\n // `identifier` without a recorded position falls back to its name.\n if (field.identifier) {\n if (identifier === undefined) identifier = field;\n else {\n warn(\n 'W_MULTIPLE_IDENTIFIERS',\n `\\`*\\` on \\`${field.name.text}\\` is ignored: class \\`${cls.name.text}\\` already has the identifier \\`${identifier.name.text}\\` on line ${identifier.line}`,\n field.identifierAt ?? field.name,\n );\n field.identifier = false;\n }\n }\n\n if (field.type?.kind === 'unknown') {\n // SPEC §3.2: any other lowercase word is an unknown type; generators\n // treat it as `string`. The node stays as written.\n const word = field.type.name.text;\n const suggestion = closestTypeWord(word);\n warn(\n 'W_UNKNOWN_TYPE',\n suggestion === undefined\n ? `unknown type \\`${word}\\`, treated as \\`string\\``\n : `unknown type \\`${word}\\`, did you mean \\`${suggestion}\\`?`,\n field.type.name,\n );\n } else if (field.type?.kind === 'class') {\n reference(field.type.name);\n }\n\n if (field.joinsTo !== undefined) {\n const { className, fieldName } = field.joinsTo;\n // Working default D2: an undeclared class is one warning, not two.\n // Any declaration of a duplicated class may carry the field.\n const hasField = (c: ClassNode): boolean =>\n c.name.text === className.text && c.fields.some((f) => f.name.text === fieldName.text);\n if (reference(className) && !classes.some(hasField)) {\n warn(\n 'W_UNDECLARED_FIELD',\n `class \\`${className.text}\\` has no field \\`${fieldName.text}\\``,\n fieldName,\n );\n }\n }\n }\n }\n\n // Idempotence (AC1): a warning the document already carries is not added\n // again, so resolving a resolved document changes nothing.\n const present = new Set(out.diagnostics.map(key));\n for (const w of warnings) {\n if (!present.has(key(w))) out.diagnostics.push(w);\n }\n // Errors are in line order from `parse`; a stable sort slots the warnings\n // in and keeps errors before warnings on the same line.\n out.diagnostics.sort((a, b) => a.line - b.line);\n\n out.undeclared = [...undeclared.values()].map((n) => ({ ...n }));\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// The copy is written out for the known AST shape rather than done with\n// `structuredClone`: that throws on a document an editor has wrapped in a\n// Proxy (a reactive store) or on a node carrying a function, and `resolve`\n// must never throw. Spreads read through a Proxy's traps and off a frozen\n// object alike.\n\nconst copyName = (n: Name): Name => ({ ...n });\n\nfunction copyType(t: TypeRef): TypeRef {\n switch (t.kind) {\n case 'primitive':\n return { ...t, written: copyName(t.written) };\n case 'class':\n case 'unknown':\n return { ...t, name: copyName(t.name) };\n case 'enum':\n return { ...t, values: t.values.map(copyName) };\n }\n}\n\nconst copyJoin = (j: JoinRef): JoinRef => ({\n className: copyName(j.className),\n fieldName: copyName(j.fieldName),\n});\n\nfunction copyField(f: FieldNode): FieldNode {\n const out: FieldNode = { ...f, name: copyName(f.name) };\n if (f.identifierAt !== undefined) out.identifierAt = copyName(f.identifierAt);\n if (f.type !== undefined) out.type = copyType(f.type);\n if (f.joinsTo !== undefined) out.joinsTo = copyJoin(f.joinsTo);\n return out;\n}\n\nfunction copyClass(c: ClassNode): ClassNode {\n const out: ClassNode = { ...c, name: copyName(c.name), fields: c.fields.map(copyField) };\n if (c.system !== undefined) out.system = copyName(c.system);\n if (c.similarTo !== undefined) out.similarTo = copyName(c.similarTo);\n return out;\n}\n\nconst key = (d: Diagnostic): string =>\n [d.severity, d.code, d.line, d.col, d.end, d.message].join(' ');\n\n// ---------------------------------------------------------------------------\n// Suggestions for unknown types (AC3): the closest accepted type word within\n// Levenshtein distance 2. On equal distance the candidate sharing the longest\n// prefix with the typed word wins (`flt` is `float`, not `int`); sharing the\n// first letter is the prefix rule at length one, so it needs no extra step.\n// Primitives come before the aliases in the parser's table so a tie that\n// survives goes to the canonical name. Working default D4: inline, no\n// dependency.\n\nconst TYPE_WORDS = Object.keys(PRIMITIVES);\n\nconst MAX_DISTANCE = 2;\n\nfunction closestTypeWord(word: string): string | undefined {\n let best: string | undefined;\n let bestDistance = MAX_DISTANCE + 1;\n let bestPrefix = -1;\n for (const candidate of TYPE_WORDS) {\n const distance = levenshtein(word, candidate);\n if (distance > MAX_DISTANCE || distance > bestDistance) continue;\n const prefix = commonPrefixLength(word, candidate);\n if (distance < bestDistance || prefix > bestPrefix) {\n best = candidate;\n bestDistance = distance;\n bestPrefix = prefix;\n }\n }\n return best;\n}\n\nfunction commonPrefixLength(a: string, b: string): number {\n let i = 0;\n while (i < a.length && i < b.length && a[i] === b[i]) i++;\n return i;\n}\n\n/** Edit distance with unit insert, delete and substitute costs. */\nfunction levenshtein(a: string, b: string): number {\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n let previous = Array.from({ length: b.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n const current = [i];\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n current[j] = Math.min(\n (previous[j] ?? 0) + 1,\n (current[j - 1] ?? 0) + 1,\n (previous[j - 1] ?? 0) + cost,\n );\n }\n previous = current;\n }\n return previous[b.length] ?? 0;\n}\n","// Document -> LinkML schema as a plain object. SPEC §5 is the contract and\n// the `.linkml.yaml` fixtures are its reference output, checked by the real\n// LinkML toolchain.\n//\n// No YAML here: the schema object is the generator's output and `serialize`\n// turns it into text (ADR 0006). Fields become class-local `attributes` and\n// never top-level `slots` (ADR 0005). Never throws.\n\nimport type { ClassNode, Document, FieldNode, Primitive } from '../ast.ts';\nimport { resolve } from '../resolve.ts';\n\n/** A LinkML `annotations` block in the compact `tag: value` form (SPEC §5.3). */\nexport interface LinkMLAnnotations {\n [tag: string]: string | boolean;\n}\n\n/** One entry under a class's `attributes`. Key order is SPEC §5.3. */\nexport interface LinkMLAttribute {\n description?: string;\n range?: string;\n multivalued?: boolean;\n identifier?: boolean;\n annotations?: LinkMLAnnotations;\n}\n\n/** One entry under `classes`. Key order is SPEC §5.3. */\nexport interface LinkMLClass {\n description?: string;\n annotations?: LinkMLAnnotations;\n close_mappings?: string[];\n attributes?: Record<string, LinkMLAttribute>;\n}\n\n/** One entry under `enums`. A permissible value carries no body, hence `null`. */\nexport interface LinkMLEnum {\n permissible_values: Record<string, null>;\n}\n\n/** The whole schema. Plain data: every value here survives `JSON.stringify`. */\nexport interface LinkMLSchema {\n id: string;\n name: string;\n default_prefix: string;\n default_range: string;\n prefixes: Record<string, string>;\n imports: string[];\n classes?: Record<string, LinkMLClass>;\n enums?: Record<string, LinkMLEnum>;\n}\n\nexport interface LinkMLOptions {\n /** Normally the file name. Normalised to a valid LinkML name (SPEC §5.2). */\n schemaName: string;\n}\n\n/** SPEC §5.2: the base URI is a placeholder. */\nconst BASE_URI = 'https://example.org';\n\n/** SPEC §3.2 primitives to the LinkML built-in types `linkml:types` defines. */\nconst RANGE: Record<Primitive, string> = {\n string: 'string',\n int: 'integer',\n float: 'float',\n bool: 'boolean',\n date: 'date',\n datetime: 'datetime',\n uri: 'uri',\n};\n\nexport function toLinkML(doc: Document, opts: LinkMLOptions): LinkMLSchema {\n // A document that has not been through `resolve` has no `undeclared` list\n // and may still carry a second `*`. Resolving is idempotent, so a resolved\n // document comes out unchanged and the output is the same either way.\n const resolved = resolve(doc);\n const schemaName = linkmlName(opts.schemaName);\n\n const classes = emittedClasses(resolved.classes);\n // LinkML keeps classes and enums in one namespace, so the enum names have to\n // avoid every class this schema emits, the undeclared stubs included.\n const classNames = new Set(classes.map((cls) => cls.node.name.text));\n for (const name of resolved.undeclared) classNames.add(name.text);\n const enums = nameEnums(classes, classNames);\n\n // SPEC §5.2. `linkml` and the schema's own prefix come first; a system\n // prefix that would collide with either is not allowed to overwrite it.\n // `Object.hasOwn`, not `in`: `prefixes` is a plain object, so `in` is true\n // for `constructor` and the other `Object.prototype` keys and a real prefix\n // would be dropped.\n const prefixes: Record<string, string> = { linkml: 'https://w3id.org/linkml/' };\n if (!Object.hasOwn(prefixes, schemaName)) prefixes[schemaName] = `${BASE_URI}/${schemaName}/`;\n\n // One prefix per distinct `@System`, in the order the systems are written:\n // a class line before its own fields.\n const systemPrefix = new Map<string, string>();\n const addSystem = (system: string): void => {\n const prefix = linkmlName(system);\n if (!systemPrefix.has(system)) systemPrefix.set(system, prefix);\n if (!Object.hasOwn(prefixes, prefix)) prefixes[prefix] = `${BASE_URI}/system/${prefix}/`;\n };\n for (const { node, fields } of classes) {\n if (node.system !== undefined) addSystem(node.system.text);\n for (const field of fields) {\n if (field.system !== undefined) addSystem(field.system.text);\n }\n }\n\n // SPEC §5.1, mapping prefix: `~ Other` uses the prefix of Other's system\n // when Other is declared with an `@`, otherwise the schema's own prefix.\n const declaredSystem = new Map<string, string | undefined>();\n for (const { node } of classes) {\n if (!declaredSystem.has(node.name.text)) declaredSystem.set(node.name.text, node.system?.text);\n }\n const mappingPrefix = (target: string): string => {\n const system = declaredSystem.get(target);\n if (system === undefined) return schemaName;\n return systemPrefix.get(system) ?? schemaName;\n };\n\n const schema: LinkMLSchema = {\n id: `${BASE_URI}/${schemaName}`,\n name: schemaName,\n default_prefix: schemaName,\n default_range: 'string',\n prefixes,\n imports: ['linkml:types'],\n };\n\n const out: Record<string, LinkMLClass> = {};\n for (const cls of classes) {\n out[cls.node.name.text] = buildClass(cls, mappingPrefix, enums);\n }\n // SPEC §5.1: a reference to an undeclared class becomes a stub, after the\n // classes that are declared.\n for (const name of resolved.undeclared) {\n if (!(name.text in out)) out[name.text] = { annotations: { undeclared: true } };\n }\n if (Object.keys(out).length > 0) schema.classes = out;\n\n const enumBlock = buildEnums(classes, enums);\n if (Object.keys(enumBlock).length > 0) schema.enums = enumBlock;\n\n return schema;\n}\n\n// ---------------------------------------------------------------------------\n// Which nodes are emitted at all.\n\ninterface EmittedClass {\n node: ClassNode;\n /** The class's fields with duplicate names dropped, first declaration first. */\n fields: FieldNode[];\n}\n\n/**\n * Issue #17: `resolve` keeps both nodes of a duplicated class, which is what a\n * live preview should show, but LinkML classes are keyed by name and two nodes\n * with `*` would give one class two identifiers. The first declaration wins and\n * the later ones are not emitted; the `W_DUPLICATE_CLASS` warning already says\n * so. The same applies to a duplicate field inside one class.\n */\nfunction emittedClasses(classes: ClassNode[]): EmittedClass[] {\n const out: EmittedClass[] = [];\n const seen = new Set<string>();\n for (const node of classes) {\n if (seen.has(node.name.text)) continue;\n seen.add(node.name.text);\n const fields: FieldNode[] = [];\n const seenField = new Set<string>();\n for (const field of node.fields) {\n if (seenField.has(field.name.text)) continue;\n seenField.add(field.name.text);\n fields.push(field);\n }\n out.push({ node, fields });\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Enum naming, SPEC §5.1.\n\n/** The key an enum's name is looked up by: one attribute of one class. */\nconst useKey = (className: string, fieldName: string): string => `${className}\\u0000${fieldName}`;\n\n/**\n * An inline enum on field `climate` becomes `ClimateEnum`. Fields with the same\n * name and identical value sets share one enum; fields with the same name and\n * different value sets are each class-qualified (`PlanetClimateEnum`).\n *\n * Working default: \"identical\" is the values in the order written, and one\n * differing value set qualifies every field of that name, including the ones\n * that agree with each other.\n */\nfunction nameEnums(classes: EmittedClass[], classNames: ReadonlySet<string>): Map<string, string> {\n const uses: { className: string; fieldName: string; values: string }[] = [];\n for (const { node, fields } of classes) {\n for (const field of fields) {\n if (field.type?.kind !== 'enum') continue;\n uses.push({\n className: node.name.text,\n fieldName: field.name.text,\n values: field.type.values.map((v) => v.text).join('|'),\n });\n }\n }\n\n const valueSets = new Map<string, Set<string>>();\n for (const use of uses) {\n const seen = valueSets.get(use.fieldName) ?? new Set<string>();\n seen.add(use.values);\n valueSets.set(use.fieldName, seen);\n }\n\n // Working default: two value sets that still collide after qualification\n // (field `bookStatus` against `status` on class `Book`) keep separate enums,\n // the later one numbered. SPEC §5.1 does not cover the case. A name a class\n // already holds is numbered the same way: `gen-python` refuses a schema with\n // overlapping enum and class names.\n const taken = new Map<string, string>();\n const names = new Map<string, string>();\n for (const use of uses) {\n const shared = (valueSets.get(use.fieldName)?.size ?? 0) <= 1;\n const base = shared\n ? `${capitalise(use.fieldName)}Enum`\n : `${capitalise(use.className)}${capitalise(use.fieldName)}Enum`;\n let name = base;\n for (\n let n = 2;\n classNames.has(name) || (taken.has(name) && taken.get(name) !== use.values);\n n++\n ) {\n name = `${base}${n}`;\n }\n taken.set(name, use.values);\n names.set(useKey(use.className, use.fieldName), name);\n }\n return names;\n}\n\n/** The `enums` block, each enum at its first use and its values as written. */\nfunction buildEnums(\n classes: EmittedClass[],\n enums: Map<string, string>,\n): Record<string, LinkMLEnum> {\n const out: Record<string, LinkMLEnum> = {};\n for (const { node, fields } of classes) {\n for (const field of fields) {\n if (field.type?.kind !== 'enum') continue;\n const name = enums.get(useKey(node.name.text, field.name.text));\n if (name === undefined || name in out) continue;\n const values: Record<string, null> = {};\n for (const value of field.type.values) values[value.text] = null;\n out[name] = { permissible_values: values };\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Classes and attributes. Key order is working default D1 of issue #23,\n// matching SPEC §5.3.\n\nfunction buildClass(\n cls: EmittedClass,\n mappingPrefix: (target: string) => string,\n enums: Map<string, string>,\n): LinkMLClass {\n const { node, fields } = cls;\n const out: LinkMLClass = {};\n\n if (node.description !== undefined) out.description = node.description;\n\n const annotations: LinkMLAnnotations = {};\n if (node.system !== undefined) annotations.system = node.system.text;\n if (node.note !== undefined) annotations.note = node.note;\n if (Object.keys(annotations).length > 0) out.annotations = annotations;\n\n if (node.similarTo !== undefined) {\n const target = node.similarTo.text;\n out.close_mappings = [`${mappingPrefix(target)}:${target}`];\n }\n\n const attributes: Record<string, LinkMLAttribute> = {};\n for (const field of fields) {\n attributes[field.name.text] = buildAttribute(field, node.name.text, enums);\n }\n if (Object.keys(attributes).length > 0) out.attributes = attributes;\n\n return out;\n}\n\nfunction buildAttribute(\n field: FieldNode,\n className: string,\n enums: Map<string, string>,\n): LinkMLAttribute {\n const out: LinkMLAttribute = {};\n\n if (field.description !== undefined) out.description = field.description;\n\n const range = rangeOf(field, className, enums);\n if (range !== undefined) out.range = range;\n if (field.type?.many === true) out.multivalued = true;\n if (field.identifier) out.identifier = true;\n\n // Annotation order is the order the markers are written on the line\n // (SPEC §4): `@System`, then `= Class.field`, then `?`.\n const annotations: LinkMLAnnotations = {};\n if (field.system !== undefined) annotations.system = field.system.text;\n if (field.joinsTo !== undefined) {\n annotations.joins_to = `${field.joinsTo.className.text}.${field.joinsTo.fieldName.text}`;\n }\n if (field.note !== undefined) annotations.note = field.note;\n if (Object.keys(annotations).length > 0) out.annotations = annotations;\n\n return out;\n}\n\n/**\n * SPEC §5.1. A field with no colon has no `range` at all and takes `string`\n * from `default_range`; an unknown type is a warning at resolve time and\n * compiles to `string` here (SPEC §3.2).\n */\nfunction rangeOf(\n field: FieldNode,\n className: string,\n enums: Map<string, string>,\n): string | undefined {\n const type = field.type;\n if (type === undefined) return undefined;\n switch (type.kind) {\n case 'primitive':\n return RANGE[type.name];\n case 'class':\n return type.name.text;\n case 'unknown':\n return 'string';\n case 'enum':\n return enums.get(useKey(className, field.name.text));\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * The prefixes `linkml:types` binds. Every schema imports it, and LinkML\n * refuses a schema that binds one of these to another URI (`gen-python`:\n * \"Prefix: schema mismatch between schema and types\"). A schema or system\n * name that lands on one takes a trailing underscore instead.\n */\nconst RESERVED_PREFIXES = new Set(['linkml', 'xsd', 'shex', 'schema']);\n\n/**\n * SPEC §5.2: lowercase, every non-alphanumeric an underscore. A LinkML name\n * must match `^[a-zA-Z_][\\w.-]*$`, and the schema name is also its prefix,\n * which RDF forbids to be the bare `_` (blank nodes). So a name with no\n * letters or digits at all becomes `sketch`, one that starts with a digit\n * (`2024-inventory.skiss`) takes a leading underscore, and one that is a\n * prefix `linkml:types` already binds (`schema.skiss`) takes a trailing one.\n */\nconst linkmlName = (text: string): string => {\n const name = text.toLowerCase().replace(/[^a-z0-9]/g, '_');\n if (!/[a-z0-9]/.test(name)) return 'sketch';\n if (RESERVED_PREFIXES.has(name)) return `${name}_`;\n return /^[0-9]/.test(name) ? `_${name}` : name;\n};\n\nconst capitalise = (text: string): string => text.charAt(0).toUpperCase() + text.slice(1);\n","// Document -> Mermaid classDiagram text. The mapping table in\n// docs/ARCHITECTURE.md (Mermaid mapping) is the contract; the `.mmd`\n// fixtures are its reference output.\n//\n// A string builder and nothing more: Mermaid is a validation aid, not a\n// rendering layer, so no abstraction is built on top of it. Never throws.\n\nimport type { Document, FieldNode, TypeRef } from '../ast.ts';\nimport { resolve } from '../resolve.ts';\n\nexport interface MermaidOptions {\n /** Emit `? text` doubts as `note for` lines. Off by default. */\n notes?: boolean;\n}\n\nexport function toMermaid(doc: Document, opts?: MermaidOptions): string {\n // A document that has not been through `resolve` has no `undeclared`\n // list and may still carry a second `*`. Resolving is idempotent, so a\n // resolved document comes out unchanged and the output is the same either way.\n const resolved = resolve(doc);\n const notes = opts?.notes === true;\n\n // Output order per the table: classes, undeclared placeholders, notes,\n // relations. Notes must precede every relation line; Mermaid fails to\n // parse a note that follows a `..>` relation.\n const lines: string[] = ['classDiagram'];\n\n for (const cls of resolved.classes) {\n lines.push(` class ${cls.name.text} {`);\n if (cls.system !== undefined) lines.push(` <<${cls.system.text}>>`);\n for (const field of cls.fields) lines.push(` ${member(field)}`);\n lines.push(' }');\n }\n\n for (const name of resolved.undeclared) {\n lines.push(` class ${name.text} {`, ' <<undeclared>>', ' }');\n }\n\n if (notes) {\n for (const cls of resolved.classes) {\n if (cls.note !== undefined) lines.push(` note for ${cls.name.text} ${quote(cls.note)}`);\n for (const field of cls.fields) {\n if (field.note !== undefined) {\n lines.push(` note for ${cls.name.text} ${quote(`${field.name.text}: ${field.note}`)}`);\n }\n }\n }\n }\n\n for (const cls of resolved.classes) {\n const from = cls.name.text;\n // `~` is Mermaid's generic-type delimiter and vanishes from labels, so\n // the label is the word `similar`.\n if (cls.similarTo !== undefined) lines.push(` ${from} ..> ${cls.similarTo.text} : similar`);\n for (const field of cls.fields) {\n const type = field.type;\n if (type?.kind === 'class') {\n lines.push(\n type.many\n ? ` ${from} \"1\" --> \"*\" ${type.name.text} : ${field.name.text}`\n : ` ${from} --> ${type.name.text} : ${field.name.text}`,\n );\n }\n if (field.joinsTo !== undefined) {\n const { className, fieldName } = field.joinsTo;\n lines.push(` ${from} ..> ${className.text} : ${field.name.text} = ${fieldName.text}`);\n }\n }\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n// `*` replaces the `+` visibility marker for an identifier; a trailing `*`\n// would be Mermaid's abstract-member marker and disappear.\nfunction member(field: FieldNode): string {\n const marker = field.identifier ? '*' : '+';\n const type = field.type === undefined ? '' : `${typeText(field.type)} `;\n const system = field.system === undefined ? '' : ` @${field.system.text}`;\n return `${marker}${type}${field.name.text}${system}`;\n}\n\n// The Skiss type text verbatim: an alias such as `integer` and an unknown\n// type such as `itn` are written as typed, enum values joined with `|`,\n// `[]` appended for many.\nfunction typeText(type: TypeRef): string {\n let text: string;\n switch (type.kind) {\n case 'primitive':\n text = type.written.text;\n break;\n case 'class':\n case 'unknown':\n text = type.name.text;\n break;\n case 'enum':\n text = type.values.map((v) => v.text).join('|');\n break;\n }\n return type.many ? `${text}[]` : text;\n}\n\n// A note is a double-quoted Mermaid string, so a double quote inside the\n// doubt becomes a single quote (issue #5, AC4).\nconst quote = (text: string): string => `\"${text.replaceAll('\"', \"'\")}\"`;\n","// LinkML schema object -> text (ADR 0006). The generator returns data; this\n// is the only place that knows about YAML, and `yaml` is the library's only\n// runtime dependency.\n//\n// The YAML is held to SPEC §5.3 byte for byte, which means two-space\n// indentation, block style, no document markers, and a blank line before\n// `classes:`, before `enums:` and before every class.\n\nimport { isMap, isScalar, Scalar, visit, Document as YAMLDocument } from 'yaml';\nimport type { LinkMLSchema } from './generators/linkml.ts';\n\nexport type SerializeFormat = 'yaml' | 'json';\n\nexport function serialize(schema: LinkMLSchema, format: SerializeFormat): string {\n if (format === 'json') return `${JSON.stringify(schema, null, 2)}\\n`;\n\n // LinkML reads the file with PyYAML, which is YAML 1.1: there `yes`, `no`,\n // `on`, `off`, `y`, `n` and `12:30` are not strings. Building the document\n // in 1.1 makes the writer quote them, so a description stays the text the\n // sketch wrote.\n const doc = new YAMLDocument(schema, { version: '1.1' });\n const root = doc.contents;\n if (isMap(root)) {\n for (const pair of root.items) {\n const key = pair.key;\n if (!isScalar(key)) continue;\n if (key.value !== 'classes' && key.value !== 'enums') continue;\n key.spaceBefore = true;\n // A blank line before every class, the first one included, so the\n // section reads as separated blocks rather than one wall of keys.\n if (key.value === 'classes' && isMap(pair.value)) {\n for (const entry of pair.value.items) {\n if (isScalar(entry.key)) entry.key.spaceBefore = true;\n }\n }\n }\n }\n\n // A tab or another control character in a plain scalar is either illegal\n // YAML (PyYAML stops at a tab that starts a token) or lost; double quoting\n // escapes it. Tabs reach here because SPEC §4 counts them as whitespace, so\n // they survive into trailer text.\n visit(doc, {\n Scalar(_, node) {\n if (typeof node.value === 'string' && hasControlCharacter(node.value)) {\n node.type = Scalar.QUOTE_DOUBLE;\n }\n },\n });\n\n const text = doc.toString({\n directives: false,\n indent: 2,\n lineWidth: 0,\n // A permissible value carries no body: `arid:`, not `arid: null`.\n nullStr: '',\n });\n // A blank line before the first entry of a nested map is written at the\n // map's own indentation, so the `spaceBefore` separators above are the only\n // whitespace-only lines here: `lineWidth: 0` never folds a scalar, and a\n // scalar holding a newline is double-quoted by the pass above and stays on\n // one line. Emptying them cannot reach a value.\n return text.replace(/^[ \\t]+$/gm, '');\n}\n\n/** C0 controls and DEL. Written as codepoints: Biome bans them in a regex. */\nfunction hasControlCharacter(text: string): boolean {\n for (const character of text) {\n const code = character.codePointAt(0) ?? 0;\n if (code < 0x20 || code === 0x7f) return true;\n }\n return false;\n}\n","// The whole path in one call, for callers that want one (ADR 0006): parse,\n// resolve, generate. Never throws, because nothing it calls does; bad input\n// produces diagnostics and the output of the partial document.\n\nimport type { Diagnostic } from './ast.ts';\nimport { toLinkML } from './generators/linkml.ts';\nimport { type MermaidOptions, toMermaid } from './generators/mermaid.ts';\nimport { parse } from './parse.ts';\nimport { resolve } from './resolve.ts';\nimport { type SerializeFormat, serialize } from './serialize.ts';\n\n/** `toMermaid` text from the source. */\nexport interface MermaidCompileOptions extends MermaidOptions {\n target: 'mermaid';\n}\n\n/** `toLinkML` put through `serialize` (ADR 0006). */\nexport interface LinkMLCompileOptions {\n target: 'linkml';\n /** Normally the file name. Normalised to a valid LinkML name (SPEC §5.2). */\n schemaName: string;\n /** Defaults to `yaml`, the form LinkML itself reads. */\n format?: SerializeFormat;\n}\n\n/**\n * A union rather than one shape with optional keys, so `schemaName` is\n * required exactly when it is used and a `mermaid` call cannot carry a\n * `format` that would be ignored.\n */\nexport type CompileOptions = MermaidCompileOptions | LinkMLCompileOptions;\n\nexport interface CompileResult {\n /** The generated text, `\\n`-terminated, whatever the platform. */\n output: string;\n /** Errors from `parse` and warnings from `resolve`, in line order. */\n diagnostics: Diagnostic[];\n}\n\nexport function compile(source: string, opts: CompileOptions): CompileResult {\n const doc = resolve(parse(source));\n const output =\n opts.target === 'linkml'\n ? serialize(toLinkML(doc, { schemaName: opts.schemaName }), opts.format ?? 'yaml')\n : toMermaid(doc, { notes: opts.notes });\n return { output, diagnostics: doc.diagnostics };\n}\n","// One diagnostic as one line of text, in the `file:line:col: severity CODE\n// message` shape compilers print and editors and terminals know how to\n// jump to. Shared by the CLI and any editor that wants the same text\n// (issue #6, working default D4).\n\nimport type { Diagnostic } from './ast.ts';\n\n/**\n * `<file>:<line>:<col>: <severity> <CODE> <message>`, without a trailing\n * newline. The `<file>:` prefix is omitted when `file` is not given, and\n * `<col>` when the diagnostic has no column. Columns are printed 1-based, as\n * the `file:line:col` convention expects, while `Diagnostic.col` stays\n * 0-based for editors.\n */\nexport function formatDiagnostic(d: Diagnostic, file?: string): string {\n const where = [file, d.line, d.col === undefined ? undefined : d.col + 1]\n .filter((part) => part !== undefined)\n .join(':');\n return `${where}: ${d.severity} ${d.code} ${d.message}`;\n}\n","// Document -> canonical Skiss text (issue #45). The other half of a\n// projection: `toLinkML` writes a schema out, this writes a Document back as\n// the notation itself.\n//\n// Canonical, not faithful: the AST holds what a line means, not how it was\n// typed, so the printer picks one layout for every document. Positions and\n// diagnostics are ignored, which is why the output of a document that came\n// from `parse` is byte-identical to a source file already written this way.\n// Never throws.\n\nimport type { ClassNode, Document, FieldNode, TypeRef } from '../ast.ts';\n\n/**\n * Where a `#` description or `?` doubt starts, 0-based. A constant and not an\n * option (issue #45, working default D1): this is the column `basic.skiss`\n * and `systems.skiss` are written at.\n */\nconst TRAILER_COLUMN = 40;\n\nexport function toSkiss(doc: Document): string {\n // A document with no classes is the empty string, not a blank line: the\n // format has no leading or trailing blank lines, so there is nothing left.\n if (doc.classes.length === 0) return '';\n return `${doc.classes.map(classBlock).join('\\n\\n')}\\n`;\n}\n\n// SPEC §2: the class line, then its fields at a two-space indent.\nfunction classBlock(cls: ClassNode): string {\n const head =\n cls.name.text +\n (cls.system === undefined ? '' : ` @${cls.system.text}`) +\n (cls.similarTo === undefined ? '' : ` ~ ${cls.similarTo.text}`);\n return [withTrailer(head, cls), ...cls.fields.map(fieldLine)].join('\\n');\n}\n\n// SPEC §4: the modifier order is fixed, so the printer has no choices to make.\nfunction fieldLine(field: FieldNode): string {\n const type = typeText(field.type);\n const head =\n ` ${field.name.text}` +\n (field.identifier ? '*' : '') +\n (type === undefined ? '' : `: ${type}`) +\n (field.system === undefined ? '' : ` @${field.system.text}`) +\n (field.joinsTo === undefined\n ? ''\n : ` = ${field.joinsTo.className.text}.${field.joinsTo.fieldName.text}`);\n return withTrailer(head, field);\n}\n\n/**\n * The type as written after the colon, or `undefined` for a field that needs\n * no colon at all: a plain `string` is what a field without one means\n * (SPEC §3.2), so printing it would be noise. `string[]` still needs the\n * colon, because `[]` has nothing to attach to without it.\n *\n * A primitive prints its canonical name, so `integer` comes back as `int`. An\n * unknown type prints the word as written, so it survives a round trip\n * (issue #45, working default D2).\n */\nfunction typeText(type: TypeRef | undefined): string | undefined {\n if (type === undefined) return undefined;\n let text: string;\n switch (type.kind) {\n case 'primitive':\n if (type.name === 'string' && !type.many) return undefined;\n text = type.name;\n break;\n case 'class':\n case 'unknown':\n text = type.name.text;\n break;\n case 'enum':\n text = type.values.map((v) => v.text).join('|');\n break;\n }\n return type.many ? `${text}[]` : text;\n}\n\n/**\n * SPEC §3.9: the description comes first and the doubt ends it. The trailer\n * starts at `TRAILER_COLUMN`, or two spaces after the line when the line is\n * already that long, so there is always whitespace before the marker for\n * `parse` to delimit on.\n */\nfunction withTrailer(head: string, node: { description?: string; note?: string }): string {\n const parts: string[] = [];\n // An empty description or doubt is dropped rather than printed as a bare\n // marker: `parse` never produces one, and a trailing `# ` would not survive\n // a round trip.\n if (node.description !== undefined && node.description !== '')\n parts.push(`# ${node.description}`);\n if (node.note !== undefined && node.note !== '') parts.push(`? ${node.note}`);\n if (parts.length === 0) return head;\n const gap = head.length < TRAILER_COLUMN - 1 ? ' '.repeat(TRAILER_COLUMN - head.length) : ' ';\n return head + gap + parts.join(' ');\n}\n","// LinkML schema object -> Skiss Document (SPEC §8). The other direction of\n// `toLinkML`: every mapping here is the inverse of a §5.1 row, and everything\n// LinkML says that §5.1 has no row for is reported rather than lost quietly.\n//\n// The input is a plain object and not text: the CLI parses the YAML, so the\n// library stays browser-safe (ADR 0003). The document is built with zeroed\n// positions, printed with `toSkiss`, and parsed again, so the document that\n// comes back carries real positions and `source` is the projection itself.\n// Never throws: a schema this cannot read at all projects to an empty sketch\n// and one report saying why.\n\nimport type { ClassNode, Document, FieldNode, Name, Primitive, TypeRef } from '../ast.ts';\nimport { CLASS_NAME, FIELD_NAME, parse, SYSTEM_OR_VALUE } from '../parse.ts';\nimport { toSkiss } from './skiss.ts';\n\n/**\n * One thing the projection could not carry. `kind` is the LinkML key, or one\n * of the projection's own kinds: `renamed`, `narrowed`, `inlined`,\n * `enum_detail`, `annotation`, `schema`. `element` names what carried it as\n * the sketch names it — `Class`, `Class.field` — or, for an enum, its LinkML\n * name, which the sketch does not keep.\n */\nexport interface Dropped {\n kind: string;\n element: string;\n detail?: string;\n}\n\nexport interface FromLinkMLResult {\n /** The projected sketch, parsed from `source`, so every node has a position. */\n document: Document;\n /** The sketch as canonical Skiss text. */\n source: string;\n /** SPEC §8, in schema order: class by class, then enums, then the schema itself. */\n dropped: Dropped[];\n}\n\n/** SPEC §8: the LinkML types that are Skiss primitives. Everything else narrows. */\nconst PRIMITIVE_RANGE: Record<string, Primitive> = {\n string: 'string',\n integer: 'int',\n float: 'float',\n double: 'float',\n decimal: 'float',\n boolean: 'bool',\n date: 'date',\n datetime: 'datetime',\n uri: 'uri',\n uriorcurie: 'uri',\n};\n\n/** The keys of a class §5.1 writes and this reads back. */\nconst CLASS_KEYS = new Set(['description', 'annotations', 'close_mappings', 'attributes', 'slots']);\n/** The keys of a slot §5.1 writes and this reads back. */\nconst SLOT_KEYS = new Set(['description', 'annotations', 'range', 'multivalued', 'identifier']);\n/** The annotation tags §5.1 gives a meaning. `undeclared` marks a stub. */\nconst CLASS_TAGS = new Set(['system', 'note', 'undeclared']);\nconst SLOT_TAGS = new Set(['system', 'note', 'joins_to']);\n/**\n * Schema-level keys that are never reported: §5.2 boilerplate (issue #46,\n * working default D2) and the three blocks the projection reads.\n */\nconst QUIET_SCHEMA_KEYS = new Set([\n 'id',\n 'name',\n 'prefixes',\n 'imports',\n 'default_prefix',\n 'default_range',\n 'title',\n 'license',\n 'version',\n 'classes',\n 'slots',\n 'enums',\n]);\n\n/** A lowercase word `parse` reads as an unknown type (SPEC §3.2). */\nconst UNKNOWN_TYPE = /^[a-z][a-z0-9_-]*$/;\n\nexport function fromLinkML(schema: unknown): FromLinkMLResult {\n const root = asRecord(schema);\n if (root === undefined) return nothing('schema', 'the schema is not an object');\n const schemaName = schemaElement(root);\n const classBlock = asRecord(get(root, 'classes'));\n if (classBlock === undefined) return nothing(schemaName, 'the schema has no `classes`');\n // Written out with its type: the helpers below are function declarations,\n // and a narrowing does not reach into one.\n const classDefs: Record<string, unknown> = classBlock;\n\n const dropped: Dropped[] = [];\n const report = (kind: string, element: string, detail?: string): void => {\n dropped.push(detail === undefined ? { kind, element } : { kind, element, detail });\n };\n\n const slotDefs = asRecord(get(root, 'slots')) ?? {};\n const enumDefs = asRecord(get(root, 'enums')) ?? {};\n const defaultRange = stringOf(get(root, 'default_range')) ?? 'string';\n\n // Names first, all of them: a reference is written with the name of the\n // element it points at, so no line can be written before every name is\n // known (SPEC §8, Names).\n const classNames = new Map<string, string>();\n const takenClasses = new Set<string>();\n for (const key of Object.keys(classDefs)) {\n classNames.set(key, unique(toClassName(key), takenClasses));\n }\n const fieldNames = new Map<string, Map<string, string>>();\n for (const key of Object.keys(classDefs)) {\n const names = new Map<string, string>();\n const taken = new Set<string>();\n for (const slot of slotKeysOf(asRecord(get(classDefs, key)) ?? {})) {\n names.set(slot, unique(toFieldName(slot), taken));\n }\n fieldNames.set(key, names);\n }\n // SPEC §8, Names: a reference is converted with the name it points at, and\n // every conversion is reported — including a reference out of the schema,\n // which has no declaration here to carry the report. One converted name is\n // reported once per element it appears on.\n const referenced = new Set<string>();\n const reference = (element: string, from: string, to: string): void => {\n if (from === to || referenced.has(`${element}\\u0000${to}`)) return;\n referenced.add(`${element}\\u0000${to}`);\n report('renamed', element, `\\`${to}\\` from \\`${from}\\``);\n };\n\n const classNameOf = (key: string): string => classNames.get(key) ?? toClassName(key);\n const fieldNameOf = (classKey: string, slot: string): string =>\n fieldNames.get(classKey)?.get(slot) ?? toFieldName(slot);\n\n // An enum is inlined at every attribute whose range it is, so its values\n // have to be writable as Skiss values before any of them is read.\n const enumValues = new Map<string, string[]>();\n const unwritable = new Map<string, string>();\n for (const key of Object.keys(enumDefs)) {\n const rawValues = get(asRecord(get(enumDefs, key)) ?? {}, 'permissible_values');\n const values = asRecord(rawValues);\n const keys = Object.keys(values ?? {});\n const bad = keys.find((value) => !SYSTEM_OR_VALUE.test(value));\n if (values === undefined && present(rawValues)) {\n // Say what was found rather than a count of values that were not read.\n unwritable.set(key, `${shown(rawValues)} is not a map of permissible values`);\n } else if (keys.length < 2) {\n // SPEC §3.4: a single value without a pipe is an unknown type, not an enum.\n const count = `${keys.length} permissible value${keys.length === 1 ? '' : 's'}`;\n unwritable.set(key, `${count} cannot be an inline enum (§3.4)`);\n } else if (bad !== undefined) {\n unwritable.set(key, `\\`${bad}\\` is not a value Skiss can write (§4)`);\n } else {\n enumValues.set(key, keys);\n }\n }\n\n /** Where an enum was inlined, for the sharing test below. */\n const enumUses: { enumName: string; field: string; values: string }[] = [];\n\n const classes: ClassNode[] = [];\n for (const key of Object.keys(classDefs)) {\n const raw = get(classDefs, key);\n const body = asRecord(raw);\n const name = classNameOf(key);\n if (body === undefined && raw !== null && raw !== undefined) {\n report('class', name, 'is not a class definition');\n continue;\n }\n const def = body ?? {};\n if (name !== key) report('renamed', name, `from \\`${key}\\``);\n\n const annotations = annotationsOf(def);\n if (annotations.get('undeclared') === true) {\n // SPEC §5.1: the stub a reference to an undeclared class left behind.\n // It is not a class of the sketch; the reference itself is written.\n for (const other of Object.keys(def)) {\n if (other !== 'annotations') report(other, name);\n }\n continue;\n }\n\n const node: ClassNode = { name: at0(name), fields: [], line: 0 };\n const description = oneLine(stringOf(get(def, 'description')));\n if (description !== undefined) node.description = description;\n\n const system = annotations.get('system');\n if (typeof system === 'string' && SYSTEM_OR_VALUE.test(system)) node.system = at0(system);\n else if (system !== undefined) report('annotation', name, '`system` is not a system name');\n\n const note = oneLine(stringOf(annotations.get('note')));\n if (note !== undefined) node.note = note;\n\n const mappings = stringList(get(def, 'close_mappings'));\n const first = mappings[0];\n // SPEC §5.1 writes `<prefix>:Other`, but a foreign schema writes a full\n // IRI just as often; neither the prefix nor the IRI survives into a sketch.\n const target = first === undefined ? '' : localName(first);\n if (target !== '') {\n const similar = Object.hasOwn(classDefs, target) ? classNameOf(target) : toClassName(target);\n node.similarTo = at0(similar);\n reference(name, target, similar);\n }\n\n for (const other of Object.keys(def)) {\n if (CLASS_KEYS.has(other)) {\n if (other === 'annotations') {\n for (const tag of annotations.keys()) {\n if (!CLASS_TAGS.has(tag)) report('annotation', name, `\\`${tag}\\``);\n }\n }\n if (other === 'close_mappings') {\n if (target === '') report('close_mappings', name, 'no mapping this can read');\n else if (mappings.length > 1) {\n report('close_mappings', name, `${mappings.length - 1} beyond the first`);\n }\n }\n // A block the fields are read out of, written as something they\n // cannot be read out of, loses every field in it.\n const block = get(def, other);\n if (other === 'attributes' && present(block) && asRecord(block) === undefined) {\n report('attributes', name, `${shown(block)} is not a map`);\n }\n if (other === 'slots' && present(block) && !Array.isArray(block)) {\n report('slots', name, `${shown(block)} is not a list`);\n }\n continue;\n }\n if (other === 'slot_usage') {\n // One report per slot the usage block changes, not one per class: it\n // is the slot that reads differently here than where it is defined.\n const usage = asRecord(get(def, other));\n if (usage === undefined) {\n report('slot_usage', name);\n continue;\n }\n for (const slot of Object.keys(usage)) {\n // A slot the sketch does not carry is one `is_a` brought in, and\n // `is_a` is dropped: the class is where a reader can find it.\n if (fieldNames.get(key)?.has(slot) === true) {\n report('slot_usage', `${name}.${fieldNameOf(key, slot)}`);\n } else {\n report('slot_usage', name, `\\`${slot}\\` is inherited and not in the sketch`);\n }\n }\n continue;\n }\n report(other, name);\n }\n\n for (const slot of slotKeysOf(def)) {\n const attributes = asRecord(get(def, 'attributes')) ?? {};\n const rawSlot = Object.hasOwn(attributes, slot) ? get(attributes, slot) : get(slotDefs, slot);\n const slotDef = asRecord(rawSlot);\n if (slotDef === undefined && present(rawSlot)) {\n // The same rule as a class whose body is not a class definition.\n report('slot', `${name}.${fieldNameOf(key, slot)}`, 'is not a slot definition');\n continue;\n }\n node.fields.push(buildField(key, name, slot, slotDef ?? {}));\n }\n\n classes.push(node);\n }\n\n // The enums, after the classes that used them (working default D1).\n for (const key of Object.keys(enumDefs)) {\n const def = asRecord(get(enumDefs, key)) ?? {};\n const uses = enumUses.filter((use) => use.enumName === key);\n const why = unwritable.get(key);\n if (why !== undefined) report('enum', key, `${why}; those attributes keep no type`);\n else if (uses.length === 0) report('unused_enum', key, 'no attribute has it as its range');\n else if (uses.length > 1 && sharingLost(uses, enumUses)) {\n report('inlined', key, `inlined at ${uses.length} attributes`);\n }\n\n const detail: string[] = [];\n const values = asRecord(get(def, 'permissible_values')) ?? {};\n const detailed = Object.keys(values).filter((value) => {\n const valueBody = asRecord(get(values, value));\n return valueBody !== undefined && Object.keys(valueBody).length > 0;\n });\n if (detailed.length > 0) {\n const bodies =\n detailed.length === 1 ? 'carries a body of its own' : 'carry bodies of their own';\n detail.push(`${list(detailed)} ${bodies}`);\n }\n const others = Object.keys(def).filter((other) => other !== 'permissible_values');\n if (others.length > 0) detail.push(`the enum carries ${list(others)}`);\n if (detail.length > 0) report('enum_detail', key, detail.join('; '));\n }\n\n // A global slot no class lists is not flattened anywhere, so it is gone.\n for (const slot of Object.keys(slotDefs)) {\n if (!listedSomewhere(slot)) report('slot', slot, 'no class lists it');\n }\n\n // One report per key, so the one-line report counts them (`2 schema keys`).\n for (const key of Object.keys(root)) {\n if (!QUIET_SCHEMA_KEYS.has(key)) report('schema', schemaName, `\\`${key}\\``);\n }\n\n const source = toSkiss({ classes, diagnostics: [] });\n return { document: parse(source), source, dropped };\n\n // -------------------------------------------------------------------------\n\n function buildField(\n classKey: string,\n className: string,\n slot: string,\n def: Record<string, unknown>,\n ): FieldNode {\n const name = fieldNameOf(classKey, slot);\n const element = `${className}.${name}`;\n if (name !== slot) report('renamed', element, `from \\`${slot}\\``);\n\n const identifier = get(def, 'identifier');\n if (present(identifier) && typeof identifier !== 'boolean') {\n // SPEC §8, The report: a key the table carries, with a value the reader\n // cannot use, is reported rather than guessed at. `yes` is a boolean in\n // YAML 1.1 and a string in the YAML 1.2 the CLI parses with.\n report('identifier', element, `${shown(identifier)} is not a boolean`);\n }\n\n const field: FieldNode = {\n name: at0(name),\n identifier: identifier === true,\n line: 0,\n };\n const description = oneLine(stringOf(get(def, 'description')));\n if (description !== undefined) field.description = description;\n\n const type = typeFor(element, name, def);\n if (type !== undefined) field.type = type;\n\n const annotations = annotationsOf(def);\n const system = annotations.get('system');\n if (typeof system === 'string' && SYSTEM_OR_VALUE.test(system)) field.system = at0(system);\n else if (system !== undefined) report('annotation', element, '`system` is not a system name');\n\n const joins = annotations.get('joins_to');\n if (typeof joins === 'string') {\n const dot = joins.indexOf('.');\n const target = joins.slice(0, dot);\n const targetField = joins.slice(dot + 1);\n if (dot > 0 && targetField !== '') {\n const targetClass = classNameOf(target);\n const targetName = fieldNameOf(target, targetField);\n field.joinsTo = { className: at0(targetClass), fieldName: at0(targetName) };\n reference(element, target, targetClass);\n reference(element, targetField, targetName);\n } else report('annotation', element, '`joins_to` is not `Class.field`');\n } else if (joins !== undefined) report('annotation', element, '`joins_to` is not text');\n\n const note = oneLine(stringOf(annotations.get('note')));\n if (note !== undefined) field.note = note;\n\n for (const other of Object.keys(def)) {\n if (!SLOT_KEYS.has(other)) {\n report(other, element);\n continue;\n }\n if (other !== 'annotations') continue;\n for (const tag of annotations.keys()) {\n if (!SLOT_TAGS.has(tag)) report('annotation', element, `\\`${tag}\\``);\n }\n }\n return field;\n }\n\n /** SPEC §8, the `range` rows. The reported narrowing is the last row. */\n function typeFor(\n element: string,\n field: string,\n def: Record<string, unknown>,\n ): TypeRef | undefined {\n const rawMany = get(def, 'multivalued');\n if (present(rawMany) && typeof rawMany !== 'boolean') {\n report('multivalued', element, `${shown(rawMany)} is not a boolean`);\n }\n const many = rawMany === true;\n\n const rawRange = get(def, 'range');\n if (present(rawRange) && typeof rawRange !== 'string') {\n report('range', element, `${shown(rawRange)} is not a string`);\n } else if (rawRange === '') report('range', element, 'the range is empty');\n // No `range` means `default_range`, which SPEC §5.2 writes as `string`.\n const range = stringOf(rawRange) ?? defaultRange;\n\n if (Object.hasOwn(classDefs, range)) {\n const target = classNameOf(range);\n reference(element, range, target);\n return { kind: 'class', name: at0(target), many };\n }\n if (Object.hasOwn(enumDefs, range)) {\n const values = enumValues.get(range);\n // An enum Skiss cannot write leaves the attribute untyped; the enum\n // itself carries the report, once, rather than every use of it.\n if (values === undefined) return many ? stringType(true) : undefined;\n enumUses.push({ enumName: range, field, values: values.join('|') });\n return { kind: 'enum', values: values.map(at0), many };\n }\n if (Object.hasOwn(PRIMITIVE_RANGE, range)) {\n const primitive = PRIMITIVE_RANGE[range] ?? 'string';\n // A plain `string` is what a field without a colon means (SPEC §3.2);\n // `string[]` still needs the colon for `[]` to attach to.\n if (primitive === 'string') return many ? stringType(true) : undefined;\n return { kind: 'primitive', name: primitive, written: at0(primitive), many };\n }\n if (/^[A-Z]/.test(range)) {\n const target = toClassName(range);\n reference(element, range, target);\n return { kind: 'class', name: at0(target), many };\n }\n\n const word = range.toLowerCase();\n if (!UNKNOWN_TYPE.test(word)) {\n report('narrowed', element, `\\`${range}\\` is not a type Skiss can write; it reads as string`);\n return many ? stringType(true) : undefined;\n }\n report('narrowed', element, `\\`${range}\\` is not a Skiss type; it falls back to string`);\n return { kind: 'unknown', name: at0(word), many };\n }\n\n /** True when a class lists this global slot, so it was flattened into one. */\n function listedSomewhere(slot: string): boolean {\n for (const key of Object.keys(classDefs)) {\n const def = asRecord(get(classDefs, key)) ?? {};\n if (stringList(get(def, 'slots')).includes(slot)) return true;\n }\n return false;\n }\n}\n\n/**\n * SPEC §8, Enums: sharing is lost unless §5.1 would rebuild one enum from the\n * inlined copies, which it does for one field name carrying one value set.\n */\nfunction sharingLost(\n uses: { field: string; values: string }[],\n all: { field: string; values: string }[],\n): boolean {\n const first = uses[0];\n if (first === undefined) return false;\n if (uses.some((use) => use.field !== first.field)) return true;\n return all.some((use) => use.field === first.field && use.values !== first.values);\n}\n\n// ---------------------------------------------------------------------------\n// The report as one line, SPEC §8.\n\n/** Kinds that name a countable thing rather than a key on one. */\nconst COUNTED: Record<string, [string, string]> = {\n renamed: ['name', 'names'],\n inlined: ['enum', 'enums'],\n enum: ['unwritable enum', 'unwritable enums'],\n unused_enum: ['unused enum', 'unused enums'],\n class: ['class', 'classes'],\n slot: ['slot', 'slots'],\n schema: ['schema key', 'schema keys'],\n // `mixin: true` marks the class; `mixins: [M]` points at another one.\n mixin: ['mixin class', 'mixin classes'],\n mixins: ['mixin', 'mixins'],\n pattern: ['pattern', 'patterns'],\n unit: ['unit', 'units'],\n};\n\n/** Kinds whose element is an enum. Everything else is a class or a slot. */\nconst ENUM_KINDS = new Set(['enum_detail']);\n\nexport function formatDropped(dropped: Dropped[]): string {\n const groups = new Map<string, Dropped[]>();\n for (const entry of dropped) {\n const group = groups.get(entry.kind);\n if (group === undefined) groups.set(entry.kind, [entry]);\n else group.push(entry);\n }\n\n const drops: string[] = [];\n let renamed = '';\n let inlined = '';\n for (const [kind, entries] of groups) {\n const phrase = phraseFor(kind, entries);\n if (kind === 'renamed') renamed = phrase;\n else if (kind === 'inlined') inlined = phrase;\n else drops.push(phrase);\n }\n\n const sentences: string[] = [];\n if (drops.length > 0) sentences.push(`Dropped: ${drops.join(', ')}.`);\n if (renamed !== '') sentences.push(`Renamed: ${renamed}.`);\n if (inlined !== '') sentences.push(`Inlined: ${inlined}.`);\n return sentences.join(' ');\n}\n\nfunction phraseFor(kind: string, entries: Dropped[]): string {\n const n = entries.length;\n const counted = Object.hasOwn(COUNTED, kind) ? COUNTED[kind] : undefined;\n if (counted !== undefined) return `${n} ${n === 1 ? counted[0] : counted[1]}`;\n return `${kind} on ${n} ${nounFor(kind, entries)}`;\n}\n\nfunction nounFor(kind: string, entries: Dropped[]): string {\n const one = entries.length === 1;\n if (ENUM_KINDS.has(kind)) return one ? 'enum' : 'enums';\n const slots = entries.filter((entry) => entry.element.includes('.')).length;\n if (slots === entries.length) return one ? 'slot' : 'slots';\n if (slots === 0) return one ? 'class' : 'classes';\n return one ? 'element' : 'elements';\n}\n\n// ---------------------------------------------------------------------------\n// Names, SPEC §8.\n\nconst capitalise = (text: string): string => text.charAt(0).toUpperCase() + text.slice(1);\nconst decapitalise = (text: string): string => text.charAt(0).toLowerCase() + text.slice(1);\n\n/** The parts of a LinkML name: anything that is not a letter or a digit separates. */\nconst parts = (text: string): string[] => text.split(/[^A-Za-z0-9]+/).filter((part) => part !== '');\n\n/**\n * `page_count` and `Page-Count` become `PageCount`. A name with nothing to\n * make a class name of is `Class`, and one that would start with a digit\n * takes an `X`: SPEC §4 has no other way to start a class name.\n */\nfunction toClassName(text: string): string {\n if (CLASS_NAME.test(text)) return text;\n const name = parts(text).map(capitalise).join('');\n if (name === '') return 'Class';\n return CLASS_NAME.test(name) ? name : `X${name}`;\n}\n\n/** `page_count` and `Page-Count` become `pageCount`, by the same rule. */\nfunction toFieldName(text: string): string {\n if (FIELD_NAME.test(text)) return text;\n const name = parts(text)\n .map((part, i) => (i === 0 ? decapitalise(part) : capitalise(part)))\n .join('');\n if (name === '') return 'field';\n return FIELD_NAME.test(name) ? name : `x${capitalise(name)}`;\n}\n\n/** Two names that converge take a number: `PageCount`, `PageCount2`. */\nfunction unique(base: string, taken: Set<string>): string {\n let name = base;\n for (let n = 2; taken.has(name); n++) name = `${base}${n}`;\n taken.add(name);\n return name;\n}\n\n// ---------------------------------------------------------------------------\n// Reading a plain object that came from somebody else's YAML.\n\n/**\n * `Object.hasOwn` and never a plain lookup: the input is a plain object, so\n * `constructor` and the other `Object.prototype` keys would otherwise be read\n * as content (issue #42).\n */\nconst get = (record: Record<string, unknown>, key: string): unknown =>\n Object.hasOwn(record, key) ? record[key] : undefined;\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;\n return value as Record<string, unknown>;\n}\n\n/** A key written with no value at all is not a key written with a bad one. */\nconst present = (value: unknown): boolean => value !== undefined && value !== null;\n\n/**\n * A value from somebody else's YAML, short enough to name in a report. A\n * scalar is quoted as it was written; a block is named by its shape.\n */\nfunction shown(value: unknown): string {\n if (Array.isArray(value)) return 'a list';\n if (typeof value === 'object' && value !== null) return 'a map';\n return `\\`${String(value)}\\``;\n}\n\n/**\n * The name at the end of a CURIE or an IRI: `catalog:Book` and\n * `https://schema.org/Book` are both `Book`. Empty when there is no name in it.\n */\nfunction localName(mapping: string): string {\n let cut = -1;\n for (const mark of [':', '/', '#']) cut = Math.max(cut, mapping.lastIndexOf(mark));\n return mapping.slice(cut + 1);\n}\n\nconst stringOf = (value: unknown): string | undefined =>\n typeof value === 'string' && value !== '' ? value : undefined;\n\nconst stringList = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n\n/**\n * The annotations of a class or a slot, compact (`system: Catalog`, what §5.1\n * writes) or in the long form LinkML also accepts (`system: {tag: system,\n * value: Catalog}`).\n */\nfunction annotationsOf(def: Record<string, unknown>): Map<string, string | boolean> {\n const out = new Map<string, string | boolean>();\n const annotations = asRecord(get(def, 'annotations'));\n if (annotations === undefined) return out;\n for (const tag of Object.keys(annotations)) {\n const raw = get(annotations, tag);\n const value = asRecord(raw) === undefined ? raw : get(asRecord(raw) ?? {}, 'value');\n if (typeof value === 'string' || typeof value === 'boolean') out.set(tag, value);\n else out.set(tag, String(value));\n }\n return out;\n}\n\n/** The class's `attributes`, then the schema `slots` it lists, in that order. */\nfunction slotKeysOf(def: Record<string, unknown>): string[] {\n const keys = Object.keys(asRecord(get(def, 'attributes')) ?? {});\n for (const slot of stringList(get(def, 'slots'))) {\n if (!keys.includes(slot)) keys.push(slot);\n }\n return keys;\n}\n\n/** A description is one line in Skiss, so its newlines become spaces. */\nfunction oneLine(text: string | undefined): string | undefined {\n if (text === undefined) return undefined;\n const line = text.replace(/\\s*[\\r\\n]+\\s*/g, ' ').trim();\n return line === '' ? undefined : line;\n}\n\nconst list = (items: string[]): string => items.map((item) => `\\`${item}\\``).join(', ');\n\nconst at0 = (text: string): Name => ({ text, line: 0, col: 0, end: 0 });\n\nconst stringType = (many: boolean): TypeRef => ({\n kind: 'primitive',\n name: 'string',\n written: at0('string'),\n many,\n});\n\nconst schemaElement = (root: Record<string, unknown>): string =>\n stringOf(get(root, 'name')) ?? 'schema';\n\n/** A schema this cannot read at all: an empty sketch and one report saying why. */\nconst nothing = (element: string, detail: string): FromLinkMLResult => ({\n document: parse(''),\n source: '',\n dropped: [{ kind: 'schema', element, detail }],\n});\n","// LinkML text -> Skiss text (SPEC §8), the whole path in one call, as\n// `compile` is the whole path the other way. `fromLinkML` takes a schema\n// object, so this is where the YAML is read; `yaml` is already the library's\n// one runtime dependency, and it needs nothing from Node, so this file stays\n// browser-safe (ADR 0003).\n//\n// Never throws. YAML that cannot be read at all is one `E_NOT_YAML`\n// diagnostic and no output; a schema `fromLinkML` cannot read is an empty\n// sketch and a report saying why (SPEC §8).\n\nimport { parse as parseYAML } from 'yaml';\nimport type { Diagnostic } from './ast.ts';\nimport { type Dropped, fromLinkML } from './generators/from-linkml.ts';\nimport { resolve } from './resolve.ts';\n\nexport interface ImportResult {\n /** The projected sketch as canonical Skiss text, `\\n`-terminated. */\n output: string;\n /** SPEC §8, in schema order: what the projection could not carry. */\n dropped: Dropped[];\n /** The diagnostics of the projected sketch. Their lines are lines of `output`. */\n diagnostics: Diagnostic[];\n}\n\nexport function importLinkML(text: string): ImportResult {\n let schema: unknown;\n try {\n // JSON is YAML, so one parser reads both forms of a LinkML schema.\n schema = parseYAML(text);\n } catch (error) {\n return { output: '', dropped: [], diagnostics: [notYAML(error)] };\n }\n\n const { document, source, dropped } = fromLinkML(schema);\n // `document` is `parse(source)`, so `resolve` adds the warnings the sketch\n // would get if somebody opened the projection and read it.\n return { output: source, dropped, diagnostics: resolve(document).diagnostics };\n}\n\n/**\n * The one diagnostic of a text that is not YAML, on line 1: the reader never\n * got far enough to have a line of its own to point at. A `YAMLParseError`\n * message carries the offending source under its first line, introduced by a\n * colon; a diagnostic is one line, so the first line without that colon is\n * what is kept.\n */\nfunction notYAML(error: unknown): Diagnostic {\n const first = error instanceof Error ? (error.message.split('\\n')[0] ?? '') : String(error);\n const detail = first.replace(/:$/, '');\n return {\n severity: 'error',\n code: 'E_NOT_YAML',\n message: `the input is not YAML: ${detail}`,\n line: 1,\n };\n}\n","export type {\n ClassNode,\n Diagnostic,\n DiagnosticCode,\n Document,\n FieldNode,\n JoinRef,\n Name,\n Primitive,\n Severity,\n TypeRef,\n} from './ast.ts';\nexport {\n type CompileOptions,\n type CompileResult,\n compile,\n type LinkMLCompileOptions,\n type MermaidCompileOptions,\n} from './compile.ts';\nexport { formatDiagnostic } from './diagnostics.ts';\nexport {\n type Dropped,\n type FromLinkMLResult,\n formatDropped,\n fromLinkML,\n} from './generators/from-linkml.ts';\nexport {\n type LinkMLAnnotations,\n type LinkMLAttribute,\n type LinkMLClass,\n type LinkMLEnum,\n type LinkMLOptions,\n type LinkMLSchema,\n toLinkML,\n} from './generators/linkml.ts';\nexport { type MermaidOptions, toMermaid } from './generators/mermaid.ts';\nexport { toSkiss } from './generators/skiss.ts';\nexport { type ImportResult, importLinkML } from './import.ts';\nexport { parse } from './parse.ts';\nexport { type ResolvedDocument, resolve } from './resolve.ts';\nexport { type SerializeFormat, serialize } from './serialize.ts';\n\nexport const VERSION = '0.3.0';\n"],"mappings":"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","names":["name","present","name","name","key","typeText","parts","classBlock","key","name","capitalise"]}
|