main
Laurin Weger 2 weeks ago
parent 3188733329
commit 3f73d6267a
No known key found for this signature in database
GPG Key ID: 9B372BB0B792770F
  1. 76
      packages/schema-converter-shex/src/schema/ShexJSchemaTransformerCompact.ts
  2. 6
      packages/schema-converter-shex/src/typing/shexjToTypingCompact.ts

@ -2,23 +2,34 @@ import type { ObjectLiteral } from "@ldo/traverser-shexj";
import ShexJTraverser from "@ldo/traverser-shexj"; import ShexJTraverser from "@ldo/traverser-shexj";
export interface CompactShape { export interface CompactShape {
schemaUri: string; iri: string;
predicates: CompactSchemaProperty[]; predicates: CompactSchemaProperty[];
} }
type NodeConstraintRet = { type CompactSchemaValue = {
literals?: number[] | string[] | boolean; literals?: number[] | string[] | boolean;
type: "number" | "string" | "boolean" | "literal"; type: "number" | "string" | "boolean" | "literal";
}; };
interface CompactSchemaProperty { interface CompactSchemaProperty {
type: "number" | "string" | "boolean" | "nested" | "literal"; /** Type of property. */
type: "number" | "string" | "boolean" | "literal" | "nested" | "eitherOf";
/** The RDF predicate URI. */
predicateUri: string; predicateUri: string;
/** The alias of the `predicateUri` when serialized to a JSON object. */
readablePredicate: string; readablePredicate: string;
/** The required literal value(s), if type is `literal`. Others are allowed, if `extra` is true. */
literalValue?: number | string | boolean | number[] | string[]; literalValue?: number | string | boolean | number[] | string[];
/** If type is `nested`, the shape or its IRI. */
nestedSchema?: string | CompactShape; nestedSchema?: string | CompactShape;
/** Maximum allowed number of values. `-1` means infinite. */
maxCardinality: number; maxCardinality: number;
/** Minimum required number of values */
minCardinality: number; minCardinality: number;
/** If type is `eitherOf`, specifies multiple allowed types (CompactSchemaValue, shapes, or shape IRI). */
eitherOf?: (CompactSchemaValue | CompactShape | string)[];
/** If other (additional) values are permitted. Useful for literals. */
extra?: boolean;
} }
export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer<
@ -28,15 +39,14 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer<
Shape: { return: CompactShape }; Shape: { return: CompactShape };
EachOf: { return: CompactShape }; EachOf: { return: CompactShape };
TripleConstraint: { return: CompactSchemaProperty }; TripleConstraint: { return: CompactSchemaProperty };
NodeConstraint: { return: NodeConstraintRet }; NodeConstraint: { return: CompactSchemaValue };
ShapeOr: { return: never }; ShapeOr: { return: (CompactSchemaValue | CompactShape | string)[] };
ShapeAnd: { return: never }; ShapeAnd: { return: never };
ShapeNot: { return: never }; ShapeNot: { return: never };
ShapeExternal: { return: never }; ShapeExternal: { return: never };
}, },
null null
>({ >({
// Transformer from Schema to interfaces
Schema: { Schema: {
transformer: async (_schema, getTransformedChildren) => { transformer: async (_schema, getTransformedChildren) => {
const transformedChildren = await getTransformedChildren(); const transformedChildren = await getTransformedChildren();
@ -45,35 +55,41 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer<
}, },
}, },
// Transformer from ShapeDecl to interface
ShapeDecl: { ShapeDecl: {
transformer: async (shapeDecl, getTransformedChildren) => { transformer: async (shapeDecl, getTransformedChildren) => {
const schema = await getTransformedChildren(); const schema = await getTransformedChildren();
const shape = schema.shapeExpr as CompactShape;
return { ...schema.shapeExpr, schemaUri: shapeDecl.id } as CompactShape; return { ...shape, iri: shapeDecl.id } as CompactShape;
}, },
}, },
// Transformer from Shape to interface
Shape: { Shape: {
transformer: async (_shape, getTransformedChildren, setReturnPointer) => { transformer: async (_shape, getTransformedChildren) => {
// TODO: We don't handles those // TODO: We don't handles those
_shape.closed; _shape.closed;
_shape.extra;
const transformedChildren = await getTransformedChildren(); const transformedChildren = await getTransformedChildren();
// Return prelim or expression or assign things? const compactShape = transformedChildren.expression as CompactShape;
return transformedChildren.expression as CompactShape;
for (const extra of _shape.extra || []) {
const extraPredicate = compactShape.predicates.find(
(p) => p.predicateUri === extra,
);
if (extraPredicate) extraPredicate.extra = true;
}
return compactShape;
}, },
}, },
// Transformer from EachOf to object type. EachOf contains the `expressions` array of properties (TripleConstraint) // EachOf contains the `expressions` array of properties (TripleConstraint)
EachOf: { EachOf: {
transformer: async (eachOf, getTransformedChildren, setReturnPointer) => { transformer: async (eachOf, getTransformedChildren) => {
const transformedChildren = await getTransformedChildren(); const transformedChildren = await getTransformedChildren();
return { return {
schemaUri: "", iri: "",
predicates: transformedChildren.expressions.map( predicates: transformedChildren.expressions.map(
// We disregard cases where properties are referenced (strings) // We disregard cases where properties are referenced (strings)
// or where they consist of Unions or Intersections (not supported). // or where they consist of Unions or Intersections (not supported).
@ -83,7 +99,6 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer<
}, },
}, },
// Transformer from triple constraints to type properties.
TripleConstraint: { TripleConstraint: {
transformer: async ( transformer: async (
tripleConstraint, tripleConstraint,
@ -116,10 +131,16 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer<
nestedSchema: transformedChildren.valueExpr as CompactShape, nestedSchema: transformedChildren.valueExpr as CompactShape,
...commonProperties, ...commonProperties,
} satisfies CompactSchemaProperty; } satisfies CompactSchemaProperty;
} else if (Array.isArray(transformedChildren.valueExpr)) {
return {
type: "eitherOf",
eitherOf: transformedChildren.valueExpr,
...commonProperties,
};
} else { } else {
// type or literal // type or literal
const nodeConstraint = const nodeConstraint =
transformedChildren.valueExpr as NodeConstraintRet; transformedChildren.valueExpr as CompactSchemaValue;
return { return {
type: nodeConstraint.type, type: nodeConstraint.type,
literalValue: nodeConstraint.literals, literalValue: nodeConstraint.literals,
@ -129,7 +150,6 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer<
}, },
}, },
// Transformer from node constraint to type
NodeConstraint: { NodeConstraint: {
transformer: async (nodeConstraint) => { transformer: async (nodeConstraint) => {
if (nodeConstraint.datatype) { if (nodeConstraint.datatype) {
@ -179,28 +199,34 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer<
}, },
}, },
// Transformer from ShapeOr to union type // Transformer from ShapeOr
ShapeOr: { ShapeOr: {
transformer: async () => { transformer: async (shapeOr, getTransformedChildren) => {
throw new Error("ShapeOr not supported (compact)"); const tc = await getTransformedChildren();
// Either a shape IRI, a nested shape or a node CompactSchemaValue (node constraint).
return (Array.isArray(tc) ? tc : [tc]) as (
| string
| CompactShape
| CompactSchemaValue
)[];
}, },
}, },
// Transformer from ShapeAnd to intersection type // Transformer from ShapeAnd
ShapeAnd: { ShapeAnd: {
transformer: async () => { transformer: async () => {
throw new Error("ShapeAnd not supported (compact)"); throw new Error("ShapeAnd not supported (compact)");
}, },
}, },
// Transformer from ShapeNot to type - not supported. // Transformer from ShapeNot - not supported.
ShapeNot: { ShapeNot: {
transformer: async () => { transformer: async () => {
throw new Error("ShapeNot not supported (compact)"); throw new Error("ShapeNot not supported (compact)");
}, },
}, },
// Transformer from ShapeExternal to type - not supported. // Transformer from ShapeExternal - not supported.
ShapeExternal: { ShapeExternal: {
transformer: async () => { transformer: async () => {
throw new Error("ShapeExternal not supported (compact)"); throw new Error("ShapeExternal not supported (compact)");

@ -69,7 +69,7 @@ function flattenSchema(shapes: CompactShape[]): CompactSchema {
let schema: CompactSchema = {}; let schema: CompactSchema = {};
for (const shape of shapes) { for (const shape of shapes) {
schema[shape.schemaUri] = shape; schema[shape.iri] = shape;
// Find nested, unflattened (i.e. anonymous) schemas in properties. // Find nested, unflattened (i.e. anonymous) schemas in properties.
const nestedSchemaPredicates = shape.predicates.filter( const nestedSchemaPredicates = shape.predicates.filter(
@ -77,13 +77,13 @@ function flattenSchema(shapes: CompactShape[]): CompactSchema {
); );
for (const pred of nestedSchemaPredicates) { for (const pred of nestedSchemaPredicates) {
const newId = shape.schemaUri + "::" + pred.predicateUri; const newId = shape.iri + "||" + pred.predicateUri;
// Recurse // Recurse
const flattened = flattenSchema([ const flattened = flattenSchema([
{ {
...(pred.nestedSchema as CompactShape), ...(pred.nestedSchema as CompactShape),
schemaUri: newId, iri: newId,
}, },
]); ]);
// Replace the nested schema with its new id. // Replace the nested schema with its new id.

Loading…
Cancel
Save