diff --git a/packages/schema-converter-shex/src/typing/ShexJTypingTransformer.ts b/packages/schema-converter-shex/src/typing/ShexJTypingTransformer.ts index 272aa58..445107c 100644 --- a/packages/schema-converter-shex/src/typing/ShexJTypingTransformer.ts +++ b/packages/schema-converter-shex/src/typing/ShexJTypingTransformer.ts @@ -45,6 +45,18 @@ export const ShexJTypingTransformer = ShexJTraverser.createTransformer< NodeConstraint: { return: dom.Type; }; + ShapeOr: { + return: dom.UnionType; + }; + ShapeAnd: { + return: dom.IntersectionType; + }; + ShapeNot: { + return: never; + }; + ShapeExternal: { + return: never; + }; }, ShexJTypeTransformerContext >({ @@ -82,7 +94,7 @@ export const ShexJTypingTransformer = ShexJTraverser.createTransformer< } else { // TODO: Handle other items throw new Error( - "Cannot handle ShapeOr, ShapeAnd, ShapeNot, ShapeExternal, or NodeConstraint", + "Cannot handle ShapeOr, ShapeAnd, ShapeNot, ShapeExternal, or NodeConstraint direcly on ShapeDecl.", ); } }, @@ -330,4 +342,34 @@ export const ShexJTypingTransformer = ShexJTraverser.createTransformer< return dom.type.undefined; }, }, + ShapeOr: { + transformer: async (shapeOr, getTransformedChildren) => { + const transformedChildren = await getTransformedChildren(); + const validTypes: dom.Type[] = []; + transformedChildren.shapeExprs.forEach((type) => { + if (typeof type === "object") validTypes.push(type); + }); + return dom.create.union(validTypes); + }, + }, + ShapeAnd: { + transformer: async (shapeAnd, getTransformedChildren) => { + const transformedChildren = await getTransformedChildren(); + const validTypes: dom.Type[] = []; + transformedChildren.shapeExprs.forEach((type) => { + if (typeof type === "object") validTypes.push(type); + }); + return dom.create.intersection(validTypes); + }, + }, + ShapeNot: { + transformer: async () => { + throw new Error("ShapeNot is not supported"); + }, + }, + ShapeExternal: { + transformer: async () => { + throw new Error("ShapeExternal is not supported"); + }, + }, }); diff --git a/packages/schema-converter-shex/test/context.test.ts b/packages/schema-converter-shex/test/context.test.ts index 0df8e48..152eb4a 100644 --- a/packages/schema-converter-shex/test/context.test.ts +++ b/packages/schema-converter-shex/test/context.test.ts @@ -9,7 +9,9 @@ describe("context", () => { const schema: Schema = parser .construct("https://ldo.js.org/") .parse(shexc); + // console.log("SCHEMA:", JSON.stringify(schema, null, 2)); const context = await shexjToContext(schema); + // console.log("CONTEXT:", JSON.stringify(context, null, 2)); expect(context).toEqual(successfulContext); }); }); diff --git a/packages/schema-converter-shex/test/testData/andSimple.ts b/packages/schema-converter-shex/test/testData/andSimple.ts new file mode 100644 index 0000000..54010cf --- /dev/null +++ b/packages/schema-converter-shex/test/testData/andSimple.ts @@ -0,0 +1,47 @@ +import type { TestData } from "./testData"; + +/** + * AND SIMPLE + */ +export const andSimple: TestData = { + name: "andSimple", + shexc: ` + PREFIX ex: + + ex:MediaContainerShape { + a [ ex:MediaContainer ]; + ex:videoImage (@ex:VideoShape AND @ex:ImageShape) ; + } + + ex:VideoShape { + a [ ex:Video ]; + } + + ex:ImageShape { + a [ ex:Image ]; + } + `, + sampleTurtle: "", + baseNode: "", + successfulContext: { + MediaContainer: { + "@id": "https://example.com/MediaContainer", + "@context": { + type: { + "@id": "@type", + }, + videoImage: { + "@id": "https://example.com/videoImage", + "@type": "@id", + }, + }, + }, + type: { + "@id": "@type", + }, + Video: "https://example.com/Video", + Image: "https://example.com/Image", + }, + successfulTypings: + 'import {ContextDefinition} from "jsonld"\n\nexport interface MediaContainerShape {\n "@id"?: string;\n "@context"?: ContextDefinition;\n type: {\n "@id": "MediaContainer";\n };\n videoImage: VideoShape & ImageShape;\n}\n\nexport interface VideoShape {\n "@id"?: string;\n "@context"?: ContextDefinition;\n type: {\n "@id": "Video";\n };\n}\n\nexport interface ImageShape {\n "@id"?: string;\n "@context"?: ContextDefinition;\n type: {\n "@id": "Image";\n };\n}\n\n', +}; diff --git a/packages/schema-converter-shex/test/testData/orSimple.ts b/packages/schema-converter-shex/test/testData/orSimple.ts new file mode 100644 index 0000000..b23ac84 --- /dev/null +++ b/packages/schema-converter-shex/test/testData/orSimple.ts @@ -0,0 +1,53 @@ +import type { TestData } from "./testData"; + +/** + * OR SIMPLE + */ +export const orSimple: TestData = { + name: "orSimple", + shexc: ` + PREFIX ex: + + ex:MediaContainerShape { + a [ ex:MediaContainer ]; + ex:primaryMedia (@ex:VideoShape OR @ex:ImageShape) ; + ex:media (@ex:VideoShape OR @ex:ImageShape) * ; + } + + ex:VideoShape { + a [ ex:Video ]; + } + + ex:ImageShape { + a [ ex:Image ]; + } + `, + sampleTurtle: "", + baseNode: "", + successfulContext: { + MediaContainer: { + "@id": "https://example.com/MediaContainer", + "@context": { + type: { + "@id": "@type", + }, + primaryMedia: { + "@id": "https://example.com/primaryMedia", + "@type": "@id", + }, + media: { + "@id": "https://example.com/media", + "@type": "@id", + "@isCollection": true, + }, + }, + }, + type: { + "@id": "@type", + }, + Video: "https://example.com/Video", + Image: "https://example.com/Image", + }, + successfulTypings: + 'import {ContextDefinition} from "jsonld"\n\nexport interface MediaContainerShape {\n "@id"?: string;\n "@context"?: ContextDefinition;\n type: {\n "@id": "MediaContainer";\n };\n primaryMedia: VideoShape | ImageShape;\n media?: (VideoShape | ImageShape)[];\n}\n\nexport interface VideoShape {\n "@id"?: string;\n "@context"?: ContextDefinition;\n type: {\n "@id": "Video";\n };\n}\n\nexport interface ImageShape {\n "@id"?: string;\n "@context"?: ContextDefinition;\n type: {\n "@id": "Image";\n };\n}\n\n', +}; diff --git a/packages/schema-converter-shex/test/testData/testData.ts b/packages/schema-converter-shex/test/testData/testData.ts index bf4d599..04dac04 100644 --- a/packages/schema-converter-shex/test/testData/testData.ts +++ b/packages/schema-converter-shex/test/testData/testData.ts @@ -7,6 +7,8 @@ import { simple } from "./simple"; import { extendsSimple } from "./extendsSimple"; import { reusedPredicates } from "./reusedPredicates"; import { oldExtends } from "./oldExtends"; +import { orSimple } from "./orSimple"; +import { andSimple } from "./andSimple"; export interface TestData { name: string; @@ -26,4 +28,6 @@ export const testData: TestData[] = [ extendsSimple, oldExtends, reusedPredicates, + orSimple, + andSimple, ]; diff --git a/packages/schema-converter-shex/test/typing.test.ts b/packages/schema-converter-shex/test/typing.test.ts index 6321e26..f9a828e 100644 --- a/packages/schema-converter-shex/test/typing.test.ts +++ b/packages/schema-converter-shex/test/typing.test.ts @@ -9,7 +9,10 @@ describe("typing", () => { const schema: Schema = parser .construct("https://ldo.js.org/") .parse(shexc); + // console.log("SCHEMA:", JSON.stringify(schema, null, 2)); const [typings] = await shexjToTyping(schema); + // console.log(typings.typingsString); + // console.log(JSON.stringify(typings.typingsString)); expect(typings.typingsString).toBe(successfulTypings); }); });