Repository navigation
Add @enum schema property for sh:in literal union types - #179
Conversation
Carry sh:in string literal values through the schema pipeline so TypeScript consumers get literal union types instead of plain string. - Add "@enum" to Property and ExpandedProperty types - Narrow SchemaInterface via @enum (skipped for @multilang) - Extract sh:in literal values in the SHACL converter - Emit "@enum" in the schema printer Co-Authored-By: Claude <noreply@anthropic.com>
`deno fmt --check` failed CI on the nested conditional in `ConvertPropertyType`, so lint and test never ran. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01StkJxf1Y3wKTe4cm2oo6bZ
There was a problem hiding this comment.
🟡 Changes recommended
The new enum plumbing has a couple of concrete edge-case bugs (mixed-type sh:in lists and empty enum arrays) that can produce incorrect output and/or narrow types to never.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR introduces enum support across the SHACL→Schema and Schema→Script pipeline by translating sh:in string-literal lists into a schema enumValues field and emitting @enum in generated scripts, plus updating the runtime schema/type interfaces to narrow string properties to literal unions.
Changes:
- Convert
sh:instring-literal lists intoenumValuesduring SHACL→Schema conversion. - Emit
@enum(asas const) when printing schemas to TS scripts, based onenumValues. - Extend schema runtime types/utilities to accept
@enumand narrow property types to literal unions; add/adjust tests accordingly.
File summaries
| File | Description |
|---|---|
| tests/scripts/shacl_to_schema.test.ts | Updates expectations to include enumValues for sh:in string literal lists. |
| tests/scripts/schema_to_script.test.ts | Adds tests ensuring enumValues emits @enum (including with @optional). |
| tests/schema.test.ts | Adds type-level/runtime tests for enum narrowing, optional/array enums, and multilang interaction. |
| scripts/shacl_to_schema.ts | Extracts enumValues from sh:in constraints and merges enum constraints across shapes. |
| scripts/schema_to_script.ts | Adds enumValues to PropertySpec and prints it as @enum in generated scripts. |
| library/schema/utils.ts | Allows @enum to pass through schema expansion. |
| library/schema/schema.ts | Adds @enum to Property and ExpandedProperty types. |
| library/schema/interface.ts | Uses @enum to narrow string properties to literal union types (except for @multilang). |
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Addressed PR review comments, hopefully it's good like this. ShEx could be done as a follow-up. |
There was a problem hiding this comment.
🔵 Needs a closer look
Resolve enum/type compatibility, intersect conjunctive enum constraints, and document @enum in the canonical schema reference.
Review details
Suppressed comments (4)
Previously missed (2) — in code that hasn't changed since the last review.
library/schema/interface.ts:43
- Because
@enumis declared asreadonly string[], this branch currently overrides any declared@type. A schema such as{ "@type": xsd.integer, "@enum": ["1", "2"] as const }is accepted and inferred as"1" | "2", whileexpandSchemaand the encoder/decoder still usexsd:integerand produce numbers. Restrict@enumto string-compatible properties or validate/resolve this combination instead of silently changing the public type.
scripts/shacl_to_schema.ts:312 - When two
sh:propertyshapes constrain the same path, SHACL applies both constraints (the surrounding comment at lines 296-298 calls this an AND), so twosh:inlists must be intersected. Choosingb.enumValueshere can generate a union containing values rejected bya(for example,("a" "b")plus("b" "c")produces"b" | "c"instead of only"b"). Combine both non-empty lists by intersection, and only fall back to the single list when the other shape has no enum constraint.
library/schema/schema.ts:16
- The new public
@enumschema key is not documented in the canonical schema reference:docs/components/schema.mdsays its example contains all supported variations (lines 192-236), but the feature list and complete example omit@enumand its literal-union behavior. Please document hand-authored schemas alongside this type change; the generator-specific note does not cover that API.
"@enum"?: readonly string[];
scripts/shacl_to_schema.ts:441
sh:andbranches are conjunctive, but this assignment overwrites any earlierinValues. With branches allowing("a" "b")and("b" "c"), the output keeps only the last branch instead of the intersection("b"), producing an unsound literal union. Accumulate/intersect enum values across the direct constraints and allsh:andbranches.
if (sub.inValues !== undefined) c.inValues = sub.inValues;
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
- Review effort level: Lite
|
@thenonameguy Thanks for the PR! Since this PR extends LDkit schema, it needs careful consideration. One of the things I see right now - the new I will test this PR in the upcoming days and will let you know what I think, whether we could eventually merge it to the project. Overall I like the idea very much. But it is a big change and I need to make sure that it plays nice with the rest of LDkit and that it is fully backwards compatible - especially in terms of TypeScript typings. |
karelklima
left a comment
There was a problem hiding this comment.
Thanks again for the PR, I was able to test it and it generally works as I expected.
There is one important thing to improve that is related to how TypeScript schema is inferred, otherwise it looks great.
|
Published in 2.8.0 |
No description provided.