@eriknaslund/skiss 0.3.0 → 0.4.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 erik-naslund
3
+ Copyright (c) 2026 Erik Näslund
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -64,7 +64,7 @@ Or without installing: `npx @eriknaslund/skiss diagram model.skiss`.
64
64
 
65
65
  `skiss compile model.skiss` writes a LinkML schema instead, as YAML on standard output. `--json` writes the same schema as JSON, `--name` sets the schema name (it defaults to the file name without its extension, and to `sketch` when reading standard input), and `-o`, `-`, `--strict` and the diagnostics work exactly as they do for `diagram`.
66
66
 
67
- `skiss import schema.linkml.yaml` goes the other way: it reads a LinkML schema, YAML or JSON, and writes Skiss. What the projection could not carry — `is_a`, patterns, `required`, the names it had to convert — is one line on standard error before the diagnostics, because a sketch is a smaller language than LinkML and that line says by how much. `-o`, `-` and the diagnostics work as they do for `compile`; `--strict` exits 1 when the projected sketch has a diagnostic, and also when anything was dropped.
67
+ `skiss import schema.linkml.yaml` goes the other way: it reads a LinkML schema, YAML or JSON, and writes Skiss. What the projection could not carry — `is_a`, patterns, `required`, the names it had to convert — is one line on standard error before the diagnostics, because a sketch is a smaller language than LinkML and that line says by how much. `-o`, `-` and the diagnostics work as they do for `compile`; `--strict` exits 1 when the projected sketch has a diagnostic, and also when anything was dropped. An input that is not a schema at all — not YAML, or YAML no schema can be read out of — produces no sketch, says why on standard error, and exits 2, the code every command uses for unreadable input.
68
68
 
69
69
  `npm install @eriknaslund/skiss` also gives you the library: `compile`, `formatDiagnostic`, `parse`, `resolve`, `toLinkML`, `serialize`, `toMermaid`, `toSkiss`, `fromLinkML`, `formatDropped`, `importLinkML` and `VERSION`, browser-safe.
70
70
 
@@ -79,11 +79,14 @@ Editors that render Skiss live are separate projects built on this package. This
79
79
  | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | How the code is organised. |
80
80
  | [docs/adr/](docs/adr/) | Architecture decision records. |
81
81
  | [docs/ROADMAP.md](docs/ROADMAP.md) | What comes next. |
82
+ | [docs/RELEASING.md](docs/RELEASING.md) | How a version reaches npm. |
82
83
  | [AGENTS.md](AGENTS.md) | How this repository is built. |
83
84
 
84
85
  ## Status
85
86
 
86
- Pre-release. The [specification](docs/SPEC.md) is at 0.1. Nothing is implemented yet.
87
+ 0.4.0, published on npm as [`@eriknaslund/skiss`](https://www.npmjs.com/package/@eriknaslund/skiss). The language parses, resolves and diagnoses; `skiss diagram` draws it, `skiss compile` writes LinkML that the real LinkML toolchain validates in CI, and `skiss import` reads a LinkML schema back into a sketch. The library exports the same in both directions and is browser-safe.
88
+
89
+ The [specification](docs/SPEC.md) is at 0.2 and moves when the language does, which is not with every release. Not built: inheritance, and editing a projected schema so that what Skiss cannot express survives the edit (SPEC §8.1). [CHANGELOG.md](CHANGELOG.md) is what changed when.
87
90
 
88
91
  ## License
89
92
 
package/dist/cli.js CHANGED
@@ -10,7 +10,8 @@ var isWs = (c) => c === " " || c === " ";
10
10
  var trimWs = (s) => s.replace(/^[ \t]+/, "").replace(/[ \t]+$/, "");
11
11
  var CLASS_NAME = /^[A-Z][A-Za-z0-9]*$/;
12
12
  var FIELD_NAME = /^[a-z][A-Za-z0-9]*$/;
13
- var SYSTEM_OR_VALUE = /^[A-Za-z][A-Za-z0-9_-]*$/;
13
+ var SYSTEM_NAME = /^[A-Za-z][A-Za-z0-9_-]*$/;
14
+ var ENUM_VALUE = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
14
15
  var PRIMITIVES = {
15
16
  string: "string",
16
17
  int: "int",
@@ -315,7 +316,7 @@ function parseSystem(c, at) {
315
316
  system ?? afterSpan(at)
316
317
  );
317
318
  }
318
- if (!SYSTEM_OR_VALUE.test(system.text)) {
319
+ if (!SYSTEM_NAME.test(system.text)) {
319
320
  return fail(
320
321
  "E_UNPARSABLE",
321
322
  `A system name is letters, digits, \`-\` and \`_\`, starting with a letter: \`${system.text}\``,
@@ -373,10 +374,10 @@ function parseType(c, colon) {
373
374
  }
374
375
  if (words.length > 1) {
375
376
  for (const w of words) {
376
- if (!SYSTEM_OR_VALUE.test(w.text)) {
377
+ if (!ENUM_VALUE.test(w.text)) {
377
378
  return fail(
378
379
  "E_UNPARSABLE",
379
- `An enum value is letters, digits, \`-\` and \`_\`, starting with a letter: \`${w.text}\``,
380
+ `An enum value is letters, digits, \`-\` and \`_\`, and does not start with \`-\` or \`_\`: \`${w.text}\``,
380
381
  c.line,
381
382
  w
382
383
  );
@@ -513,6 +514,18 @@ function resolve(doc) {
513
514
  );
514
515
  } else if (field.type?.kind === "class") {
515
516
  reference(field.type.name);
517
+ } else if (field.type?.kind === "enum") {
518
+ const seen = /* @__PURE__ */ new Set();
519
+ for (const value of field.type.values) {
520
+ if (seen.has(value.text)) {
521
+ warn(
522
+ "W_DUPLICATE_ENUM_VALUE",
523
+ `value \`${value.text}\` is already in this enum; it is carried once`,
524
+ value
525
+ );
526
+ }
527
+ seen.add(value.text);
528
+ }
516
529
  }
517
530
  if (field.joinsTo !== void 0) {
518
531
  const { className, fieldName } = field.joinsTo;
@@ -626,7 +639,8 @@ function toLinkML(doc, opts) {
626
639
  const classNames = new Set(classes.map((cls) => cls.node.name.text));
627
640
  for (const name2 of resolved.undeclared) classNames.add(name2.text);
628
641
  const enums = nameEnums(classes, classNames);
629
- const prefixes = { linkml: "https://w3id.org/linkml/" };
642
+ const prefixes = nameKeyed();
643
+ prefixes.linkml = "https://w3id.org/linkml/";
630
644
  if (!Object.hasOwn(prefixes, schemaName)) prefixes[schemaName] = `${BASE_URI}/${schemaName}/`;
631
645
  const systemPrefix = /* @__PURE__ */ new Map();
632
646
  const addSystem = (system) => {
@@ -657,12 +671,12 @@ function toLinkML(doc, opts) {
657
671
  prefixes,
658
672
  imports: ["linkml:types"]
659
673
  };
660
- const out = {};
674
+ const out = nameKeyed();
661
675
  for (const cls of classes) {
662
676
  out[cls.node.name.text] = buildClass(cls, mappingPrefix, enums);
663
677
  }
664
678
  for (const name2 of resolved.undeclared) {
665
- if (!(name2.text in out)) out[name2.text] = { annotations: { undeclared: true } };
679
+ if (!Object.hasOwn(out, name2.text)) out[name2.text] = { annotations: { undeclared: true } };
666
680
  }
667
681
  if (Object.keys(out).length > 0) schema.classes = out;
668
682
  const enumBlock = buildEnums(classes, enums);
@@ -720,13 +734,13 @@ function nameEnums(classes, classNames) {
720
734
  return names;
721
735
  }
722
736
  function buildEnums(classes, enums) {
723
- const out = {};
737
+ const out = nameKeyed();
724
738
  for (const { node, fields } of classes) {
725
739
  for (const field of fields) {
726
740
  if (field.type?.kind !== "enum") continue;
727
741
  const name2 = enums.get(useKey(node.name.text, field.name.text));
728
- if (name2 === void 0 || name2 in out) continue;
729
- const values = {};
742
+ if (name2 === void 0 || Object.hasOwn(out, name2)) continue;
743
+ const values = nameKeyed();
730
744
  for (const value of field.type.values) values[value.text] = null;
731
745
  out[name2] = { permissible_values: values };
732
746
  }
@@ -745,7 +759,7 @@ function buildClass(cls, mappingPrefix, enums) {
745
759
  const target = node.similarTo.text;
746
760
  out.close_mappings = [`${mappingPrefix(target)}:${target}`];
747
761
  }
748
- const attributes = {};
762
+ const attributes = nameKeyed();
749
763
  for (const field of fields) {
750
764
  attributes[field.name.text] = buildAttribute(field, node.name.text, enums);
751
765
  }
@@ -783,10 +797,12 @@ function rangeOf(field, className, enums) {
783
797
  }
784
798
  }
785
799
  var RESERVED_PREFIXES = /* @__PURE__ */ new Set(["linkml", "xsd", "shex", "schema"]);
800
+ var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
801
+ var nameKeyed = () => /* @__PURE__ */ Object.create(null);
786
802
  var linkmlName = (text) => {
787
803
  const name2 = text.toLowerCase().replace(/[^a-z0-9]/g, "_");
788
804
  if (!/[a-z0-9]/.test(name2)) return "sketch";
789
- if (RESERVED_PREFIXES.has(name2)) return `${name2}_`;
805
+ if (RESERVED_PREFIXES.has(name2) || PROTOTYPE_KEYS.has(name2)) return `${name2}_`;
790
806
  return /^[0-9]/.test(name2) ? `_${name2}` : name2;
791
807
  };
792
808
  var capitalise = (text) => text.charAt(0).toUpperCase() + text.slice(1);
@@ -949,10 +965,15 @@ function typeText2(type) {
949
965
  }
950
966
  return type.many ? `${text}[]` : text;
951
967
  }
968
+ function writeDescription(text) {
969
+ const attached = text.replace(/[ \t]+\?(?=[ \t]|$)/g, "?");
970
+ return /^\?([ \t]|$)/.test(attached) ? `#${attached}` : `# ${attached}`;
971
+ }
972
+ var rewordsDescription = (text) => writeDescription(text) !== `# ${text}`;
952
973
  function withTrailer(head, node) {
953
974
  const parts2 = [];
954
975
  if (node.description !== void 0 && node.description !== "")
955
- parts2.push(`# ${node.description}`);
976
+ parts2.push(writeDescription(node.description));
956
977
  if (node.note !== void 0 && node.note !== "") parts2.push(`? ${node.note}`);
957
978
  if (parts2.length === 0) return head;
958
979
  const gap = head.length < TRAILER_COLUMN - 1 ? " ".repeat(TRAILER_COLUMN - head.length) : " ";
@@ -990,6 +1011,7 @@ var QUIET_SCHEMA_KEYS = /* @__PURE__ */ new Set([
990
1011
  "slots",
991
1012
  "enums"
992
1013
  ]);
1014
+ var REWORDED = "a standalone `?` is attached to the word before it";
993
1015
  var UNKNOWN_TYPE = /^[a-z][a-z0-9_-]*$/;
994
1016
  function fromLinkML(schema) {
995
1017
  const root = asRecord(schema);
@@ -1033,7 +1055,7 @@ function fromLinkML(schema) {
1033
1055
  const rawValues = get(asRecord(get(enumDefs, key2)) ?? {}, "permissible_values");
1034
1056
  const values = asRecord(rawValues);
1035
1057
  const keys = Object.keys(values ?? {});
1036
- const bad = keys.find((value) => !SYSTEM_OR_VALUE.test(value));
1058
+ const bad = keys.find((value) => !ENUM_VALUE.test(value));
1037
1059
  if (values === void 0 && present(rawValues)) {
1038
1060
  unwritable.set(key2, `${shown(rawValues)} is not a map of permissible values`);
1039
1061
  } else if (keys.length < 2) {
@@ -1064,14 +1086,26 @@ function fromLinkML(schema) {
1064
1086
  }
1065
1087
  continue;
1066
1088
  }
1089
+ const undeclared = annotations.get("undeclared");
1090
+ if (undeclared !== void 0 && typeof undeclared !== "boolean") {
1091
+ report("annotation", name2, notText("undeclared", undeclared));
1092
+ }
1067
1093
  const node = { name: at0(name2), fields: [], line: 0 };
1068
1094
  const description = oneLine(stringOf(get(def, "description")));
1069
- if (description !== void 0) node.description = description;
1095
+ if (description !== void 0) {
1096
+ node.description = description;
1097
+ if (rewordsDescription(description)) report("reworded", name2, REWORDED);
1098
+ }
1070
1099
  const system = annotations.get("system");
1071
- if (typeof system === "string" && SYSTEM_OR_VALUE.test(system)) node.system = at0(system);
1072
- else if (system !== void 0) report("annotation", name2, "`system` is not a system name");
1073
- const note = oneLine(stringOf(annotations.get("note")));
1074
- if (note !== void 0) node.note = note;
1100
+ if (typeof system === "string") {
1101
+ if (SYSTEM_NAME.test(system)) node.system = at0(system);
1102
+ else report("annotation", name2, "`system` is not a system name");
1103
+ } else if (system !== void 0) report("annotation", name2, notText("system", system));
1104
+ const rawNote = annotations.get("note");
1105
+ if (typeof rawNote === "string") {
1106
+ const note = oneLine(rawNote);
1107
+ if (note !== void 0) node.note = note;
1108
+ } else if (rawNote !== void 0) report("annotation", name2, notText("note", rawNote));
1075
1109
  const mappings = stringList(get(def, "close_mappings"));
1076
1110
  const first = mappings[0];
1077
1111
  const target = first === void 0 ? "" : localName(first);
@@ -1176,13 +1210,18 @@ function fromLinkML(schema) {
1176
1210
  line: 0
1177
1211
  };
1178
1212
  const description = oneLine(stringOf(get(def, "description")));
1179
- if (description !== void 0) field.description = description;
1213
+ if (description !== void 0) {
1214
+ field.description = description;
1215
+ if (rewordsDescription(description)) report("reworded", element, REWORDED);
1216
+ }
1180
1217
  const type = typeFor(element, name2, def);
1181
1218
  if (type !== void 0) field.type = type;
1182
1219
  const annotations = annotationsOf(def);
1183
1220
  const system = annotations.get("system");
1184
- if (typeof system === "string" && SYSTEM_OR_VALUE.test(system)) field.system = at0(system);
1185
- else if (system !== void 0) report("annotation", element, "`system` is not a system name");
1221
+ if (typeof system === "string") {
1222
+ if (SYSTEM_NAME.test(system)) field.system = at0(system);
1223
+ else report("annotation", element, "`system` is not a system name");
1224
+ } else if (system !== void 0) report("annotation", element, notText("system", system));
1186
1225
  const joins = annotations.get("joins_to");
1187
1226
  if (typeof joins === "string") {
1188
1227
  const dot = joins.indexOf(".");
@@ -1195,9 +1234,12 @@ function fromLinkML(schema) {
1195
1234
  reference(element, target, targetClass);
1196
1235
  reference(element, targetField, targetName);
1197
1236
  } else report("annotation", element, "`joins_to` is not `Class.field`");
1198
- } else if (joins !== void 0) report("annotation", element, "`joins_to` is not text");
1199
- const note = oneLine(stringOf(annotations.get("note")));
1200
- if (note !== void 0) field.note = note;
1237
+ } else if (joins !== void 0) report("annotation", element, notText("joins_to", joins));
1238
+ const rawNote = annotations.get("note");
1239
+ if (typeof rawNote === "string") {
1240
+ const note = oneLine(rawNote);
1241
+ if (note !== void 0) field.note = note;
1242
+ } else if (rawNote !== void 0) report("annotation", element, notText("note", rawNote));
1201
1243
  for (const other of Object.keys(def)) {
1202
1244
  if (!SLOT_KEYS.has(other)) {
1203
1245
  report(other, element);
@@ -1272,13 +1314,17 @@ var COUNTED = {
1272
1314
  class: ["class", "classes"],
1273
1315
  slot: ["slot", "slots"],
1274
1316
  schema: ["schema key", "schema keys"],
1317
+ narrowed: ["narrowed range", "narrowed ranges"],
1318
+ enum_detail: ["enum detail", "enum details"],
1319
+ annotation: ["unreadable annotation", "unreadable annotations"],
1320
+ reworded: ["description reworded", "descriptions reworded"],
1275
1321
  // `mixin: true` marks the class; `mixins: [M]` points at another one.
1276
1322
  mixin: ["mixin class", "mixin classes"],
1277
1323
  mixins: ["mixin", "mixins"],
1278
1324
  pattern: ["pattern", "patterns"],
1279
1325
  unit: ["unit", "units"]
1280
1326
  };
1281
- var ENUM_KINDS = /* @__PURE__ */ new Set(["enum_detail"]);
1327
+ var UNREADABLE = "unreadable";
1282
1328
  function formatDropped(dropped) {
1283
1329
  const groups = /* @__PURE__ */ new Map();
1284
1330
  for (const entry of dropped) {
@@ -1287,15 +1333,21 @@ function formatDropped(dropped) {
1287
1333
  else group.push(entry);
1288
1334
  }
1289
1335
  const drops = [];
1336
+ const notRead = [];
1290
1337
  let renamed = "";
1291
1338
  let inlined = "";
1292
1339
  for (const [kind, entries] of groups) {
1340
+ if (kind === UNREADABLE) {
1341
+ for (const entry of entries) notRead.push(entry.detail ?? "the schema could not be read");
1342
+ continue;
1343
+ }
1293
1344
  const phrase = phraseFor(kind, entries);
1294
1345
  if (kind === "renamed") renamed = phrase;
1295
1346
  else if (kind === "inlined") inlined = phrase;
1296
1347
  else drops.push(phrase);
1297
1348
  }
1298
1349
  const sentences = [];
1350
+ if (notRead.length > 0) sentences.push(`Not read: ${notRead.join("; ")}.`);
1299
1351
  if (drops.length > 0) sentences.push(`Dropped: ${drops.join(", ")}.`);
1300
1352
  if (renamed !== "") sentences.push(`Renamed: ${renamed}.`);
1301
1353
  if (inlined !== "") sentences.push(`Inlined: ${inlined}.`);
@@ -1305,11 +1357,10 @@ function phraseFor(kind, entries) {
1305
1357
  const n = entries.length;
1306
1358
  const counted = Object.hasOwn(COUNTED, kind) ? COUNTED[kind] : void 0;
1307
1359
  if (counted !== void 0) return `${n} ${n === 1 ? counted[0] : counted[1]}`;
1308
- return `${kind} on ${n} ${nounFor(kind, entries)}`;
1360
+ return `${kind} on ${n} ${nounFor(entries)}`;
1309
1361
  }
1310
- function nounFor(kind, entries) {
1362
+ function nounFor(entries) {
1311
1363
  const one = entries.length === 1;
1312
- if (ENUM_KINDS.has(kind)) return one ? "enum" : "enums";
1313
1364
  const slots = entries.filter((entry) => entry.element.includes(".")).length;
1314
1365
  if (slots === entries.length) return one ? "slot" : "slots";
1315
1366
  if (slots === 0) return one ? "class" : "classes";
@@ -1360,12 +1411,18 @@ function annotationsOf(def) {
1360
1411
  if (annotations === void 0) return out;
1361
1412
  for (const tag of Object.keys(annotations)) {
1362
1413
  const raw = get(annotations, tag);
1363
- const value = asRecord(raw) === void 0 ? raw : get(asRecord(raw) ?? {}, "value");
1364
- if (typeof value === "string" || typeof value === "boolean") out.set(tag, value);
1365
- else out.set(tag, String(value));
1414
+ const long = asRecord(raw);
1415
+ const value = long === void 0 ? raw : get(long, "value");
1416
+ out.set(tag, value ?? null);
1366
1417
  }
1367
1418
  return out;
1368
1419
  }
1420
+ function notText(tag, value) {
1421
+ if (value === null) return `\`${tag}\` was written with no value`;
1422
+ if (Array.isArray(value)) return `\`${tag}\` is a list, not text`;
1423
+ if (typeof value === "object") return `\`${tag}\` is a map, not text`;
1424
+ return `\`${tag}\` is a ${typeof value}, not text`;
1425
+ }
1369
1426
  function slotKeysOf(def) {
1370
1427
  const keys = Object.keys(asRecord(get(def, "attributes")) ?? {});
1371
1428
  for (const slot of stringList(get(def, "slots"))) {
@@ -1390,7 +1447,7 @@ var schemaElement = (root) => stringOf(get(root, "name")) ?? "schema";
1390
1447
  var nothing = (element, detail) => ({
1391
1448
  document: parse(""),
1392
1449
  source: "",
1393
- dropped: [{ kind: "schema", element, detail }]
1450
+ dropped: [{ kind: UNREADABLE, element, detail }]
1394
1451
  });
1395
1452
 
1396
1453
  // src/import.ts
@@ -1417,7 +1474,7 @@ function notYAML(error) {
1417
1474
  }
1418
1475
 
1419
1476
  // src/index.ts
1420
- var VERSION = "0.3.0";
1477
+ var VERSION = "0.4.0";
1421
1478
 
1422
1479
  // src/cli.ts
1423
1480
  var HELP = `Usage: skiss <command> [options]
@@ -1450,7 +1507,8 @@ wrote has, so their line numbers are lines of that sketch.
1450
1507
  Exit codes:
1451
1508
  0 the output was produced
1452
1509
  1 --strict and the input has diagnostics (the output is still written)
1453
- 2 usage error, missing file or unreadable input
1510
+ 2 usage error, missing file, or unreadable input: for import, a text no
1511
+ schema could be read out of, which produces no sketch at all
1454
1512
  70 internal error, a bug in skiss
1455
1513
  `;
1456
1514
  var EXIT_OK = 0;
@@ -1520,9 +1578,15 @@ async function main(argv) {
1520
1578
  `);
1521
1579
  if (values.output === void 0) process.stdout.write(output);
1522
1580
  else await writeOutput(values.output, output);
1581
+ if (unreadableInput(command, diagnostics, dropped)) return EXIT_USAGE;
1523
1582
  const strict = values.strict === true && (diagnostics.length > 0 || dropped.length > 0);
1524
1583
  return strict ? EXIT_STRICT : EXIT_OK;
1525
1584
  }
1585
+ function unreadableInput(command, diagnostics, dropped) {
1586
+ if (command !== "import") return false;
1587
+ if (dropped.some((entry) => entry.kind === "unreadable")) return true;
1588
+ return diagnostics.some((d) => d.code === "E_NOT_YAML");
1589
+ }
1526
1590
  function runCommand(command, source, file, values) {
1527
1591
  if (command === "import") return importLinkML(source);
1528
1592
  if (command === "compile") {
@@ -1568,6 +1632,12 @@ function reason(error) {
1568
1632
  }
1569
1633
  return String(error);
1570
1634
  }
1635
+ for (const stream of [process.stdout, process.stderr]) {
1636
+ stream.on("error", (error) => {
1637
+ if (error.code === "EPIPE") process.exit(EXIT_OK);
1638
+ throw error;
1639
+ });
1640
+ }
1571
1641
  main(process.argv.slice(2)).then(
1572
1642
  (code) => {
1573
1643
  process.exitCode = code;
package/dist/index.d.ts CHANGED
@@ -68,7 +68,7 @@ type Severity = 'error' | 'warning';
68
68
  * `resolve` the `W_` codes, and `importLinkML` the one code of its own,
69
69
  * `E_NOT_YAML`, for a text no schema can be read out of.
70
70
  */
71
- type DiagnosticCode = 'E_UNPARSABLE' | 'E_FIELD_WITHOUT_CLASS' | 'E_MISSING_TYPE' | 'E_UNCLOSED_MANY' | 'E_BAD_NAME' | 'W_UNKNOWN_TYPE' | 'W_UNDECLARED_CLASS' | 'W_UNDECLARED_FIELD' | 'W_DUPLICATE_CLASS' | 'W_DUPLICATE_FIELD' | 'W_MULTIPLE_IDENTIFIERS' | 'E_NOT_YAML';
71
+ type DiagnosticCode = 'E_UNPARSABLE' | 'E_FIELD_WITHOUT_CLASS' | 'E_MISSING_TYPE' | 'E_UNCLOSED_MANY' | 'E_BAD_NAME' | 'W_UNKNOWN_TYPE' | 'W_UNDECLARED_CLASS' | 'W_UNDECLARED_FIELD' | 'W_DUPLICATE_CLASS' | 'W_DUPLICATE_FIELD' | 'W_DUPLICATE_ENUM_VALUE' | 'W_MULTIPLE_IDENTIFIERS' | 'E_NOT_YAML';
72
72
  interface Diagnostic {
73
73
  severity: Severity;
74
74
  code: DiagnosticCode;
@@ -175,9 +175,9 @@ declare function formatDiagnostic(d: Diagnostic, file?: string): string;
175
175
  /**
176
176
  * One thing the projection could not carry. `kind` is the LinkML key, or one
177
177
  * of the projection's own kinds: `renamed`, `narrowed`, `inlined`,
178
- * `enum_detail`, `annotation`, `schema`. `element` names what carried it as
179
- * the sketch names it — `Class`, `Class.field` — or, for an enum, its LinkML
180
- * name, which the sketch does not keep.
178
+ * `enum_detail`, `annotation`, `reworded`, `schema`, `unreadable`. `element`
179
+ * names what carried it as the sketch names it — `Class`, `Class.field` — or,
180
+ * for an enum, its LinkML name, which the sketch does not keep.
181
181
  */
182
182
  interface Dropped {
183
183
  kind: string;
@@ -215,6 +215,6 @@ interface ResolvedDocument extends Document {
215
215
  }
216
216
  declare function resolve(doc: Document): ResolvedDocument;
217
217
 
218
- declare const VERSION = "0.3.0";
218
+ declare const VERSION = "0.4.0";
219
219
 
220
220
  export { type ClassNode, type CompileOptions, type CompileResult, type Diagnostic, type DiagnosticCode, type Document, type Dropped, type FieldNode, type FromLinkMLResult, type ImportResult, type JoinRef, type LinkMLAnnotations, type LinkMLAttribute, type LinkMLClass, type LinkMLCompileOptions, type LinkMLEnum, type LinkMLOptions, type LinkMLSchema, type MermaidCompileOptions, type MermaidOptions, type Name, type Primitive, type ResolvedDocument, type SerializeFormat, type Severity, type TypeRef, VERSION, compile, formatDiagnostic, formatDropped, fromLinkML, importLinkML, parse, resolve, serialize, toLinkML, toMermaid, toSkiss };