diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7a532f..52e9d09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -194,9 +194,6 @@ importers: '@types/shexj': specifier: ^2.1.4 version: 2.1.7 - copyfiles: - specifier: ^2.4.1 - version: 2.4.1 typescript: specifier: ^5.9.2 version: 5.9.2 @@ -1817,9 +1814,6 @@ packages: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - clone@2.1.2: resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} engines: {node: '>=0.8'} @@ -1899,10 +1893,6 @@ packages: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} - copyfiles@2.4.1: - resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} - hasBin: true - core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2303,10 +2293,6 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.4.0: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} @@ -2581,9 +2567,6 @@ packages: resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} engines: {node: '>=16'} - isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -3025,9 +3008,6 @@ packages: resolution: {integrity: sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ==} engines: {node: '>=6.0.0'} - noms@0.0.0: - resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -3427,9 +3407,6 @@ packages: readable-stream-node-to-web@1.0.1: resolution: {integrity: sha512-OGzi2VKLa8H259kAx7BIwuRrXHGcxeHj4RdASSgEGBP9Q2wowdPvBc65upF4Q9O05qWgKqBw1+9PiLTtObl7uQ==} - readable-stream@1.0.34: - resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -3484,10 +3461,6 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - require-relative@0.8.7: resolution: {integrity: sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==} @@ -3684,9 +3657,6 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string_decoder@0.10.31: - resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} - string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -3778,9 +3748,6 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - tiny-conventional-commits-parser@0.0.1: resolution: {integrity: sha512-N5+AZWdBeHNSgTIaxvx0+9mFrnW4H1BbjQ84H7i3TuWSkno8Hju886hLaHZhE/hYEKrfrfl/uHurqpZJHDuYGQ==} @@ -4043,10 +4010,6 @@ packages: uploadthing: optional: true - untildify@4.0.0: - resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} - engines: {node: '>=8'} - update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true @@ -4335,17 +4298,9 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - xxhash-wasm@1.1.0: resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - yallist@2.1.2: resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} @@ -4355,18 +4310,10 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -6364,12 +6311,6 @@ snapshots: cli-boxes@3.0.0: {} - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - clone@2.1.2: {} clsx@2.1.1: {} @@ -6433,16 +6374,6 @@ snapshots: dependencies: is-what: 4.1.16 - copyfiles@2.4.1: - dependencies: - glob: 7.2.3 - minimatch: 3.1.2 - mkdirp: 1.0.4 - noms: 0.0.0 - through2: 2.0.5 - untildify: 4.0.0 - yargs: 16.2.0 - core-util-is@1.0.3: {} cross-fetch@3.2.0(encoding@0.1.13): @@ -6884,8 +6815,6 @@ snapshots: gensync@1.0.0-beta.2: {} - get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} get-intrinsic@1.3.0: @@ -7227,8 +7156,6 @@ snapshots: dependencies: is-inside-container: 1.0.0 - isarray@0.0.1: {} - isarray@1.0.0: {} isexe@2.0.0: {} @@ -7877,11 +7804,6 @@ snapshots: node-version@1.2.0: {} - noms@0.0.0: - dependencies: - inherits: 2.0.4 - readable-stream: 1.0.34 - normalize-path@3.0.0: {} npm-run-path@6.0.0: @@ -8279,13 +8201,6 @@ snapshots: readable-stream-node-to-web@1.0.1: {} - readable-stream@1.0.34: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 0.0.1 - string_decoder: 0.10.31 - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -8386,8 +8301,6 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - require-directory@2.1.1: {} - require-relative@0.8.7: {} resolve-from@4.0.0: {} @@ -8645,8 +8558,6 @@ snapshots: get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 - string_decoder@0.10.31: {} - string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -8776,11 +8687,6 @@ snapshots: dependencies: any-promise: 1.3.0 - through2@2.0.5: - dependencies: - readable-stream: 2.3.8 - xtend: 4.0.2 - tiny-conventional-commits-parser@0.0.1: {} tiny-inflate@1.0.3: {} @@ -8990,8 +8896,6 @@ snapshots: ofetch: 1.4.1 ufo: 1.6.1 - untildify@4.0.0: {} - update-browserslist-db@1.1.3(browserslist@4.26.0): dependencies: browserslist: 4.26.0 @@ -9364,32 +9268,16 @@ snapshots: xmlchars@2.2.0: {} - xtend@4.0.2: {} - xxhash-wasm@1.1.0: {} - y18n@5.0.8: {} - yallist@2.1.2: {} yallist@3.1.1: {} yallist@4.0.0: {} - yargs-parser@20.2.4: {} - yargs-parser@21.1.1: {} - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.4 - yocto-queue@0.1.0: {} yocto-queue@1.2.1: {} diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/shapeHandler.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/shapeHandler.ts index 98946f6..8992b7b 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/shapeHandler.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/shapeHandler.ts @@ -1,6 +1,6 @@ import * as shapeManager from "./shapeManager"; import type { WasmConnection, Diff, Scope } from "./types"; -import type { ShapeType, OrmBase } from "@nextgraph-monorepo/ng-shex-orm"; +import type { ShapeType, BaseType } from "@nextgraph-monorepo/ng-shex-orm"; import type { Person } from "../../shapes/ldo/personShape.typings"; import type { Cat } from "../../shapes/ldo/catShape.typings"; import type { TestObject } from "../../shapes/ldo/testShape.typings"; @@ -17,7 +17,7 @@ interface WasmMessage { connectionId: string; diff?: Diff; shapeType?: ShapeType; - initialData?: OrmBase; + initialData?: BaseType; } export const mockTestObject = { @@ -78,7 +78,7 @@ const mockShapeObject2 = { // Single BroadcastChannel for wasm-land side const communicationChannel = new BroadcastChannel("shape-manager"); -function getInitialObjectByShapeId(shapeId?: string): T { +function getInitialObjectByShapeId(shapeId?: string): T { if (shapeId?.includes("TestObject")) return mockTestObject as unknown as T; if (shapeId?.includes("Person")) return mockShapeObject1 as unknown as T; if (shapeId?.includes("Cat")) return mockShapeObject2 as unknown as T; diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/README.md b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/README.md deleted file mode 100644 index ef7439e..0000000 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# SPARQL builders - -Utilities to build SPARQL SELECT and CONSTRUCT queries from a ShapeConstraint structure. - -Exports: - -- buildSelectQuery(shape, options) -- buildConstructQuery(shape, options) - -Options: - -- prefixes: Record -- graph: named graph IRI or CURIE -- includeOptionalForMinZero: wrap min=0 predicates in OPTIONAL (default true) diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildConstruct.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildConstruct.ts index 31b4ed0..7a72649 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildConstruct.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildConstruct.ts @@ -1,17 +1,4 @@ -import type { - BuildContext, - PredicateConstraint, - ShapeConstraint, - SparqlBuildOptions, -} from "./common"; -import { - predicateToSparql, - prefixesToText, - toIriOrCurie, - uniqueVar, - valuesBlock, - varToken, -} from "./common"; +import type { Predicate, Shape, Schema } from "@nextgraph-monorepo/ng-shex-orm"; /** * Build a SPARQL CONSTRUCT query from a ShapeConstraint definition. @@ -19,131 +6,215 @@ import { * but still appear in the CONSTRUCT template so that matched triples are constructed. */ export function buildConstructQuery( - shape: ShapeConstraint, - options?: SparqlBuildOptions, + shape: Shape, + schema: Schema, + options?: SparqlBuildOptions ): string { - const ctx: BuildContext = { usedVars: new Set() }; - const prefixes = prefixesToText(options?.prefixes); - const subject = toIriOrCurie(shape.subject); - - const templateLines: string[] = []; - const whereLines: string[] = []; - const postFilters: string[] = []; - const valuesBlocks: string[] = []; - - const rootVar = - subject.startsWith("?") || subject.startsWith("$") - ? subject - : uniqueVar(ctx, "s"); - if (!subject.startsWith("?") && !subject.startsWith("$")) { - valuesBlocks.push(valuesBlock(rootVar, [subject] as any)); - } - - const predicates = Array.isArray(shape.predicates) - ? shape.predicates - : [...shape.predicates]; - for (const pred of predicates) { - addConstructPattern( - ctx, - pred, - rootVar, - templateLines, - whereLines, - postFilters, - valuesBlocks, - options, + const ctx: BuildContext = { usedVars: new Set() }; + const prefixes = prefixesToText(options?.prefixes); + const subject = shape.iri; + + const templateLines: string[] = []; + const whereLines: string[] = []; + const postFilters: string[] = []; + const valuesBlocks: string[] = []; + + const rootVar = + subject.startsWith("?") || subject.startsWith("$") + ? subject + : uniqueVar(ctx, "s"); + if (!subject.startsWith("?") && !subject.startsWith("$")) { + valuesBlocks.push(valuesBlock(rootVar, [subject] as any)); + } + + const predicates = Array.isArray(shape.predicates) + ? shape.predicates + : [...shape.predicates]; + for (const pred of predicates) { + addConstructPattern( + ctx, + pred, + rootVar, + templateLines, + whereLines, + postFilters, + valuesBlocks, + options + ); + } + + const graphWrap = (body: string) => + options?.graph + ? `GRAPH ${toIriOrCurie(options.graph)} {\n${body}\n}` + : body; + + const where = [ + ...valuesBlocks, + graphWrap(whereLines.join("\n")), + ...postFilters, + ] + .filter(Boolean) + .join("\n"); + + const template = templateLines.join("\n"); + + return [prefixes, `CONSTRUCT {`, template, `} WHERE {`, where, `}`].join( + "\n" ); - } - - const graphWrap = (body: string) => - options?.graph - ? `GRAPH ${toIriOrCurie(options.graph)} {\n${body}\n}` - : body; - - const where = [ - ...valuesBlocks, - graphWrap(whereLines.join("\n")), - ...postFilters, - ] - .filter(Boolean) - .join("\n"); - - const template = templateLines.join("\n"); - - return [prefixes, `CONSTRUCT {`, template, `} WHERE {`, where, `}`].join( - "\n", - ); } function addConstructPattern( - ctx: BuildContext, - pred: PredicateConstraint, - subjectVar: string, - template: string[], - where: string[], - postFilters: string[], - valuesBlocks: string[], - options?: SparqlBuildOptions, + ctx: BuildContext, + pred: Predicate, + subjectVar: string, + template: string[], + where: string[], + postFilters: string[], + valuesBlocks: string[], + options?: SparqlBuildOptions ) { - const p = predicateToSparql(pred.uri); - const objVar = uniqueVar(ctx, pred.displayName || "o"); - const objTerm = - pred.type === "nested" && - pred.nested?.subject && - !pred.nested.subject.match(/^\?|^\$/) - ? toIriOrCurie(pred.nested.subject) - : objVar; - - const triple = `${subjectVar} ${p} ${objTerm} .`; - - const isOptional = - (pred.min ?? 0) === 0 && (options?.includeOptionalForMinZero ?? true); + const p = `<${pred.predicateUri}>`; + const objVar = uniqueVar(ctx, pred.readablePredicate); + + const triple = `${subjectVar} ${p} ${objTerm} .`; + + const isOptional = + (pred.minCardinality ?? 0) === 0 && + (options?.includeOptionalForMinZero ?? true); + + if (pred.type === "nested" && pred.nestedShape) { + template.push(triple); + const nestedBody: string[] = [triple]; + const nestedPreds = pred.nestedShape.predicates; + + for (const n of nestedPreds) { + addConstructPattern( + ctx, + n, + objTerm, + template, + nestedBody, + postFilters, + valuesBlocks, + options + ); + } + const block = nestedBody.join("\n"); + where.push(isOptional ? `OPTIONAL {\n${block}\n}` : block); + return; + } - if (pred.type === "nested" && pred.nested) { + // Non-nested template.push(triple); - const nestedBody: string[] = [triple]; - const nestedPreds = Array.isArray(pred.nested.predicates) - ? pred.nested.predicates - : [...pred.nested.predicates]; - for (const n of nestedPreds) { - addConstructPattern( - ctx, - n, - objTerm, - template, - nestedBody, - postFilters, - valuesBlocks, - options, - ); + const blockLines: string[] = [triple]; + + if (pred.type === "literal" && pred.literalValue !== undefined) { + if (Array.isArray(pred.literalValue)) { + valuesBlocks.push(valuesBlock(objVar, pred.literalValue as any[])); + } else { + const lit = + typeof pred.literalValue === "string" || + typeof pred.literalValue === "number" || + typeof pred.literalValue === "boolean" + ? pred.literalValue + : String(pred.literalValue); + postFilters.push( + `FILTER(${objVar} = ${typeof lit === "string" ? `"${String(lit).replace(/"/g, '\\"')}"` : lit})` + ); + } } - const block = nestedBody.join("\n"); + + const block = blockLines.join("\n"); where.push(isOptional ? `OPTIONAL {\n${block}\n}` : block); - return; - } - - // Non-nested - template.push(triple); - const blockLines: string[] = [triple]; - - if (pred.type === "literal" && pred.literalValue !== undefined) { - if (Array.isArray(pred.literalValue)) { - valuesBlocks.push(valuesBlock(objVar, pred.literalValue as any[])); - } else { - const lit = - typeof pred.literalValue === "string" || - typeof pred.literalValue === "number" || - typeof pred.literalValue === "boolean" - ? pred.literalValue - : String(pred.literalValue); - postFilters.push( - `FILTER(${objVar} = ${typeof lit === "string" ? `"${String(lit).replace(/"/g, '\\"')}"` : lit})`, - ); +} + +export type LiteralKind = + | "number" + | "string" + | "boolean" + | "nested" + | "literal"; + +export interface SparqlBuildOptions { + prefixes?: Record; + graph?: string; // IRI of the named graph to query, if any + includeOptionalForMinZero?: boolean; // default true +} + +export const defaultPrefixes: Record = { + xsd: "http://www.w3.org/2001/XMLSchema#", + rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + rdfs: "http://www.w3.org/2000/01/rdf-schema#", +}; + +export function prefixesToText(prefixes?: Record): string { + const all = { ...defaultPrefixes, ...(prefixes ?? {}) }; + return Object.entries(all) + .map(([p, iri]) => `PREFIX ${p}: <${iri}>`) + .join("\n"); +} + +export function safeVarName(name: string): string { + const base = name + .replace(/[^a-zA-Z0-9_]/g, "_") + .replace(/^([0-9])/, "_$1") + .slice(0, 60); + return base || "v"; +} + +export function varToken(name: string): string { + const n = + name.startsWith("?") || name.startsWith("$") ? name.slice(1) : name; + return `?${safeVarName(n)}`; +} + +export function formatLiteral(value: string | number | boolean): string { + if (typeof value === "number") return String(value); + if (typeof value === "boolean") return value ? "true" : "false"; + // default string literal + const escaped = value.replace(/"/g, '\\"'); + return `"${escaped}"`; +} + +export function formatTermForValues(value: string | number | boolean): string { + if (typeof value === "number" || typeof value === "boolean") + return formatLiteral(value); + // strings: detect IRI or CURIE and keep raw; otherwise quote + const v = value.trim(); + const looksLikeIri = v.startsWith("<") && v.endsWith(">"); + const looksLikeHttp = v.includes("://"); + const looksLikeCurie = + /^[A-Za-z_][A-Za-z0-9_-]*:.+$/u.test(v) && !looksLikeHttp; + if (looksLikeIri || looksLikeHttp || looksLikeCurie) { + return looksLikeHttp ? `<${v}>` : v; } - } + return formatLiteral(v); +} + +export function valuesBlock( + varName: string, + values: Array +): string { + const rendered = values.map(formatTermForValues).join(" "); + return `VALUES ${varName} { ${rendered} }`; +} - const block = blockLines.join("\n"); - where.push(isOptional ? `OPTIONAL {\n${block}\n}` : block); +export interface BuildContext { + // Tracks used variable names to avoid collisions + usedVars: Set; +} + +export function uniqueVar(ctx: BuildContext, base: string): string { + let candidate = varToken(base); + if (!ctx.usedVars.has(candidate)) { + ctx.usedVars.add(candidate); + return candidate; + } + let i = 2; + while (ctx.usedVars.has(`${candidate}_${i}`)) i++; + const unique = `${candidate}_${i}`; + ctx.usedVars.add(unique); + return unique; } export default buildConstructQuery; diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildSelect.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildSelect.ts deleted file mode 100644 index 57e6118..0000000 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildSelect.ts +++ /dev/null @@ -1,152 +0,0 @@ -import type { - BuildContext, - PredicateConstraint, - ShapeConstraint, - SparqlBuildOptions, -} from "./common"; -import { - predicateToSparql, - prefixesToText, - toIriOrCurie, - uniqueVar, - valuesBlock, - varToken, -} from "./common"; - -/** - * Build a SPARQL SELECT query from a ShapeConstraint definition. - * The query matches the shape subject and constraints; optional predicates (min=0) are wrapped in OPTIONAL. - */ -export function buildSelectQuery( - shape: ShapeConstraint, - options?: SparqlBuildOptions, -): string { - const ctx: BuildContext = { usedVars: new Set() }; - const prefixes = prefixesToText(options?.prefixes); - const subject = toIriOrCurie(shape.subject); - - const selectVars: string[] = []; - const whereLines: string[] = []; - const postFilters: string[] = []; - const valuesBlocks: string[] = []; - - // ensure a consistent root variable when subject is a variable - const rootVar = - subject.startsWith("?") || subject.startsWith("$") - ? subject - : uniqueVar(ctx, "s"); - if (!subject.startsWith("?") && !subject.startsWith("$")) { - // bind fixed subject via VALUES for portability - valuesBlocks.push(valuesBlock(rootVar, [subject] as any)); - } - - const predicates = Array.isArray(shape.predicates) - ? shape.predicates - : [...shape.predicates]; - - for (const pred of predicates) { - addPredicatePattern( - ctx, - pred, - rootVar, - whereLines, - selectVars, - postFilters, - valuesBlocks, - options, - ); - } - - const graphWrap = (body: string) => - options?.graph - ? `GRAPH ${toIriOrCurie(options.graph)} {\n${body}\n}` - : body; - - const where = [ - ...valuesBlocks, - graphWrap(whereLines.join("\n")), - ...postFilters, - ] - .filter(Boolean) - .join("\n"); - - const select = selectVars.length ? selectVars.join(" ") : "*"; - - return [prefixes, `SELECT ${select} WHERE {`, where, `}`].join("\n"); -} - -function addPredicatePattern( - ctx: BuildContext, - pred: PredicateConstraint, - subjectVar: string, - where: string[], - selectVars: string[], - postFilters: string[], - valuesBlocks: string[], - options?: SparqlBuildOptions, -) { - const p = predicateToSparql(pred.uri); - const objVar = uniqueVar(ctx, pred.displayName || "o"); - const objTerm = - pred.type === "nested" && - pred.nested?.subject && - !pred.nested.subject.match(/^\?|^\$/) - ? toIriOrCurie(pred.nested.subject) - : objVar; - - const triple = `${subjectVar} ${p} ${objTerm} .`; - - const isOptional = - (pred.min ?? 0) === 0 && (options?.includeOptionalForMinZero ?? true); - - if (pred.type === "nested" && pred.nested) { - // For nested, we select the nested object var and then recurse - if (objTerm === objVar) selectVars.push(objVar); - const nestedBody: string[] = [triple]; - const nestedPreds = Array.isArray(pred.nested.predicates) - ? pred.nested.predicates - : [...pred.nested.predicates]; - for (const n of nestedPreds) { - addPredicatePattern( - ctx, - n, - objTerm, - nestedBody, - selectVars, - postFilters, - valuesBlocks, - options, - ); - } - const block = nestedBody.join("\n"); - where.push(isOptional ? `OPTIONAL {\n${block}\n}` : block); - return; - } - - // Non-nested: literals or IRIs - selectVars.push(objVar); - const blockLines: string[] = [triple]; - - if (pred.type === "literal" && pred.literalValue !== undefined) { - if (Array.isArray(pred.literalValue)) { - // VALUES block for IN-like matching - valuesBlocks.push(valuesBlock(objVar, pred.literalValue as any[])); - } else { - // simple equality filter - const lit = - typeof pred.literalValue === "string" || - typeof pred.literalValue === "number" || - typeof pred.literalValue === "boolean" - ? pred.literalValue - : String(pred.literalValue); - postFilters.push( - `FILTER(${objVar} = ${typeof lit === "string" ? `"${String(lit).replace(/"/g, '\\"')}"` : lit})`, - ); - } - } - - const block = blockLines.join("\n"); - where.push(isOptional ? `OPTIONAL {\n${block}\n}` : block); -} - -export default buildSelectQuery; diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildSparqlConstructFromShape.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildSparqlConstructFromShape.ts new file mode 100644 index 0000000..7cfb525 --- /dev/null +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/buildSparqlConstructFromShape.ts @@ -0,0 +1,140 @@ +import type { Predicate, Shape, Schema } from "@nextgraph-monorepo/ng-shex-orm"; + +export const buildConstructQuery = ({ + schema, + shapeId, +}: { + schema: Schema; + shapeId: keyof Schema; +}): string => { + const rootShape = schema[shapeId]; + + const constructStatements: { + s: string; + p: string; + o: string; + optional: boolean; + literals: Predicate["literalValue"]; + }[] = []; + + const idToVarName: Record = {}; + const getVarNameFor = (id: string) => { + const currentName = idToVarName[id]; + if (currentName) return currentName; + + const newVar = `o${Object.entries(idToVarName).length + 1}`; + idToVarName[id] = newVar; + return newVar; + }; + + // Create s,p,o records where subject and object var names are mapped to shape or predicate ids. + const addTriples = (shape: Shape) => { + const predicates = shape.predicates; + const shapeId = shape.iri; + + for (const pred of predicates) { + const subjectVarName = getVarNameFor(shapeId); + + if (pred.type === "nested") { + if (typeof pred.nestedShape !== "string") + throw new Error("Nested shapes must be by reference"); + + // If a name for this shape was assigned already, it's triples have been added + // and we don't have to recurse. + const shapeAlreadyRegistered = !!idToVarName[pred.nestedShape]; + + const shapeVarName = getVarNameFor(pred.nestedShape); + + constructStatements.push({ + s: `?${subjectVarName}`, + p: `<${pred.predicateUri}>`, + o: `?${shapeVarName}`, + optional: pred.minCardinality < 1, + literals: pred.literalValue, + // TODO: eitherOf ? + }); + + if (!shapeAlreadyRegistered) + addTriples(schema[pred.nestedShape]); + } else { + const objVarName = getVarNameFor( + shapeId + "__separator__" + pred.predicateUri + ); + + constructStatements.push({ + s: `?${subjectVarName}`, + p: `<${pred.predicateUri}>`, + o: `?${objVarName}`, + optional: pred.minCardinality < 1, + literals: pred.literalValue, + // TODO: eitherOf ? + }); + } + } + }; + + addTriples(rootShape); + + const construct = `CONSTRUCT { +${constructStatements.map(({ s, p, o }) => ` ${s} ${p} ${o} .\n`).join("")} }`; + + const statementToWhere = ({ + s, + p, + o, + optional, + }: { + s: string; + p: string; + o: string; + optional: boolean; + }) => { + if (optional) return ` OPTIONAL { ${s} ${p} ${o} . }\n`; + else return ` ${s} ${p} ${o} .\n`; + }; + + const literalToSparqlFormat = ( + literal: string | number | boolean + ): string => { + if (typeof literal === "number") return String(literal); + if (typeof literal === "boolean") return literal ? "true" : "false"; + if (typeof literal === "string") { + return isIri(literal) + ? `<${literal}>` + : `"${escapeString(literal)}"`; + } + return `"${String(literal)}"`; + }; + + // Filters for optional values. + const filters = constructStatements + .filter((statement) => statement.literals !== undefined) + .map((statement) => { + const vals = arrayOf(statement.literals!); + if (vals.length === 0) return ""; + if (vals.length === 1) { + return ` FILTER(${statement.o} = ${literalToSparqlFormat(vals[0]!)})\n`; + } + const list = vals.map(literalToSparqlFormat).join(", "); + return ` FILTER(${statement.o} IN (${list}))\n`; + }) + .join(""); + + const where = `WHERE { + ${constructStatements.map(statementToWhere).join("")} + ${filters} + }`; + + return `${construct}\n${where}`; +}; + +const arrayOf = (arrayOrLiteral: T | T[]) => { + if (typeof arrayOrLiteral === "undefined" || arrayOrLiteral === null) + return []; + if (Array.isArray(arrayOrLiteral)) return arrayOrLiteral; + return [arrayOrLiteral]; +}; + +const isIri = (str: string) => /^[a-zA-Z][a-zA-Z0-9+.-]{1,7}:/.test(str); + +const escapeString = (str: string) => str.replace(/["\\]/g, "\\$&"); diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/common.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/common.ts deleted file mode 100644 index aaed2c6..0000000 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/common.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Shared helpers and types to build SPARQL queries from ShapeConstraint - */ - -export type LiteralKind = - | "number" - | "string" - | "boolean" - | "nested" - | "literal"; - -export interface PredicateConstraint { - displayName: string; - uri: string; - type: LiteralKind; - literalValue?: number | string | boolean | number[] | string[]; - nested?: ShapeConstraint; - min: number; - max: number; - currentCount: number; -} - -export interface ShapeConstraint { - subject: string; - // In upstream code this is typed as a 1-length tuple; we normalize to an array here - predicates: PredicateConstraint[] | [PredicateConstraint]; -} - -export interface SparqlBuildOptions { - prefixes?: Record; - graph?: string; // IRI of the named graph to query, if any - includeOptionalForMinZero?: boolean; // default true -} - -export const defaultPrefixes: Record = { - xsd: "http://www.w3.org/2001/XMLSchema#", - rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", - rdfs: "http://www.w3.org/2000/01/rdf-schema#", -}; - -export function prefixesToText(prefixes?: Record): string { - const all = { ...defaultPrefixes, ...(prefixes ?? {}) }; - return Object.entries(all) - .map(([p, iri]) => `PREFIX ${p}: <${iri}>`) - .join("\n"); -} - -export function toIriOrCurie(term: string): string { - // variable - if (term.startsWith("?") || term.startsWith("$")) return term; - // blank node - if (term.startsWith("_:")) return term; - // full IRI - if (term.includes("://")) return `<${term}>`; - // fallback: assume CURIE or already-angled - if (term.startsWith("<") && term.endsWith(">")) return term; - return term; // CURIE, caller must ensure prefix provided -} - -export function predicateToSparql(uri: string): string { - // Allow CURIEs or IRIs - return toIriOrCurie(uri); -} - -export function safeVarName(name: string): string { - const base = name - .replace(/[^a-zA-Z0-9_]/g, "_") - .replace(/^([0-9])/, "_$1") - .slice(0, 60); - return base || "v"; -} - -export function varToken(name: string): string { - const n = name.startsWith("?") || name.startsWith("$") ? name.slice(1) : name; - return `?${safeVarName(n)}`; -} - -export function formatLiteral(value: string | number | boolean): string { - if (typeof value === "number") return String(value); - if (typeof value === "boolean") return value ? "true" : "false"; - // default string literal - const escaped = value.replace(/"/g, '\\"'); - return `"${escaped}"`; -} - -export function formatTermForValues(value: string | number | boolean): string { - if (typeof value === "number" || typeof value === "boolean") - return formatLiteral(value); - // strings: detect IRI or CURIE and keep raw; otherwise quote - const v = value.trim(); - const looksLikeIri = v.startsWith("<") && v.endsWith(">"); - const looksLikeHttp = v.includes("://"); - const looksLikeCurie = - /^[A-Za-z_][A-Za-z0-9_-]*:.+$/u.test(v) && !looksLikeHttp; - if (looksLikeIri || looksLikeHttp || looksLikeCurie) { - return looksLikeHttp ? `<${v}>` : v; - } - return formatLiteral(v); -} - -export function valuesBlock( - varName: string, - values: Array, -): string { - const rendered = values.map(formatTermForValues).join(" "); - return `VALUES ${varName} { ${rendered} }`; -} - -export interface BuildContext { - // Tracks used variable names to avoid collisions - usedVars: Set; -} - -export function uniqueVar(ctx: BuildContext, base: string): string { - let candidate = varToken(base); - if (!ctx.usedVars.has(candidate)) { - ctx.usedVars.add(candidate); - return candidate; - } - let i = 2; - while (ctx.usedVars.has(`${candidate}_${i}`)) i++; - const unique = `${candidate}_${i}`; - ctx.usedVars.add(unique); - return unique; -} diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/sparqlConstruct.test.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/sparqlConstruct.test.ts new file mode 100644 index 0000000..c32421e --- /dev/null +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/sparqlConstruct.test.ts @@ -0,0 +1,9 @@ +import { buildConstructQuery } from "./buildSparqlConstructFromShape.ts"; +import { testShapeSchema } from "./testShape.schema.ts"; + +console.log( + buildConstructQuery({ + schema: testShapeSchema, + shapeId: "http://example.org/TestObject", + }) +); diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/testShape.schema.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/testShape.schema.ts new file mode 100644 index 0000000..5a57db5 --- /dev/null +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/sparql/testShape.schema.ts @@ -0,0 +1,129 @@ +import type { Schema } from "@nextgraph-monorepo/ng-shex-orm"; + +/** + * ============================================================================= + * testShapeSchema: Schema for testShape + * ============================================================================= + */ +export const testShapeSchema: Schema = { + "http://example.org/TestObject": { + iri: "http://example.org/TestObject", + predicates: [ + { + type: "literal", + literalValue: ["TestObject"], + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", + readablePredicate: "type", + extra: true, + }, + { + type: "string", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/stringValue", + readablePredicate: "stringValue", + }, + { + type: "number", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/numValue", + readablePredicate: "numValue", + }, + { + type: "boolean", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/boolValue", + readablePredicate: "boolValue", + }, + { + type: "number", + maxCardinality: -1, + minCardinality: 0, + predicateUri: "http://example.org/arrayValue", + readablePredicate: "arrayValue", + }, + { + type: "nested", + nestedShape: + "http://example.org/TestObject||http://example.org/objectValue", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/objectValue", + readablePredicate: "objectValue", + }, + { + type: "nested", + nestedShape: + "http://example.org/TestObject||http://example.org/anotherObject", + maxCardinality: -1, + minCardinality: 0, + predicateUri: "http://example.org/anotherObject", + readablePredicate: "anotherObject", + }, + { + type: "eitherOf", + eitherOf: [ + { + type: "string", + }, + { + type: "number", + }, + ], + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/numOrStr", + readablePredicate: "numOrStr", + }, + ], + }, + "http://example.org/TestObject||http://example.org/objectValue": { + iri: "http://example.org/TestObject||http://example.org/objectValue", + predicates: [ + { + type: "string", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/nestedString", + readablePredicate: "nestedString", + }, + { + type: "number", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/nestedNum", + readablePredicate: "nestedNum", + }, + { + type: "number", + maxCardinality: -1, + minCardinality: 0, + predicateUri: "http://example.org/nestedArray", + readablePredicate: "nestedArray", + }, + ], + }, + "http://example.org/TestObject||http://example.org/anotherObject": { + iri: "http://example.org/TestObject||http://example.org/anotherObject", + predicates: [ + { + type: "string", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/prop1", + readablePredicate: "prop1", + }, + { + type: "number", + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/prop2", + readablePredicate: "prop2", + }, + ], + }, +}; diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/types.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/types.ts index d23d74b..a3b3da8 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/types.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/ng-mock/wasm-land/types.ts @@ -1,4 +1,4 @@ -import type { ShapeType, OrmBase } from "@nextgraph-monorepo/ng-shex-orm"; +import type { ShapeType, BaseType } from "@nextgraph-monorepo/ng-shex-orm"; import type { Patch } from "@nextgraph-monorepo/ng-signals"; /** The Scope of a shape request */ @@ -10,7 +10,7 @@ export type Diff = Patch[]; export type ObjectState = object; /** A connection established between wasm-land and js-land for subscription of a shape. */ -export type WasmConnection = { +export type WasmConnection = { id: string; shape: ShapeType; state: ObjectState; diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.schema.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.schema.ts index c5cdf10..a3fb7fe 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.schema.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.schema.ts @@ -11,7 +11,7 @@ export const catShapeSchema: Schema = { predicates: [ { type: "literal", - literalValue: ["Cat"], + literalValue: ["http://example.org/Cat"], maxCardinality: 1, minCardinality: 1, predicateUri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", @@ -40,7 +40,7 @@ export const catShapeSchema: Schema = { }, { type: "nested", - nestedSchema: "http://example.org/Cat||http://example.org/address", + nestedShape: "http://example.org/Cat||http://example.org/address", maxCardinality: 1, minCardinality: 1, predicateUri: "http://example.org/address", diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.typings.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.typings.ts index d75ed9d..a7c3c46 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.typings.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/catShape.typings.ts @@ -14,7 +14,7 @@ export interface Cat { /** * Original IRI: http://www.w3.org/1999/02/22-rdf-syntax-ns#type */ - type: "Cat"; + type: string; /** * Original IRI: http://example.org/name */ diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.schema.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.schema.ts index 2839f36..c987324 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.schema.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.schema.ts @@ -11,7 +11,7 @@ export const personShapeSchema: Schema = { predicates: [ { type: "literal", - literalValue: ["Person"], + literalValue: ["http://example.org/Person"], maxCardinality: 1, minCardinality: 1, predicateUri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", @@ -26,7 +26,7 @@ export const personShapeSchema: Schema = { }, { type: "nested", - nestedSchema: "http://example.org/Person||http://example.org/address", + nestedShape: "http://example.org/Person||http://example.org/address", maxCardinality: 1, minCardinality: 1, predicateUri: "http://example.org/address", diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.typings.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.typings.ts index a2d53e2..db985e9 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.typings.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/personShape.typings.ts @@ -14,7 +14,7 @@ export interface Person { /** * Original IRI: http://www.w3.org/1999/02/22-rdf-syntax-ns#type */ - type: "Person"; + type: string; /** * Original IRI: http://example.org/name */ diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.schema.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.schema.ts index 5806054..7479b5d 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.schema.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.schema.ts @@ -11,7 +11,7 @@ export const testShapeSchema: Schema = { predicates: [ { type: "literal", - literalValue: ["TestObject"], + literalValue: ["http://example.org/TestObject"], maxCardinality: 1, minCardinality: 1, predicateUri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", @@ -48,7 +48,7 @@ export const testShapeSchema: Schema = { }, { type: "nested", - nestedSchema: + nestedShape: "http://example.org/TestObject||http://example.org/objectValue", maxCardinality: 1, minCardinality: 1, @@ -57,7 +57,7 @@ export const testShapeSchema: Schema = { }, { type: "nested", - nestedSchema: + nestedShape: "http://example.org/TestObject||http://example.org/anotherObject", maxCardinality: -1, minCardinality: 0, @@ -65,12 +65,28 @@ export const testShapeSchema: Schema = { readablePredicate: "anotherObject", }, { - type: "string", + type: "eitherOf", + eitherOf: [ + { + type: "string", + }, + { + type: "number", + }, + ], maxCardinality: 1, minCardinality: 1, predicateUri: "http://example.org/numOrStr", readablePredicate: "numOrStr", }, + { + type: "literal", + literalValue: ["lit1", "lit2"], + maxCardinality: 1, + minCardinality: 1, + predicateUri: "http://example.org/lit1Or2", + readablePredicate: "lit1Or2", + }, ], }, "http://example.org/TestObject||http://example.org/objectValue": { diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.typings.ts b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.typings.ts index b04d85e..046be0b 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.typings.ts +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/ldo/testShape.typings.ts @@ -14,7 +14,7 @@ export interface TestObject { /** * Original IRI: http://www.w3.org/1999/02/22-rdf-syntax-ns#type */ - type: "TestObject"; + type: string; /** * Original IRI: http://example.org/stringValue */ @@ -69,5 +69,9 @@ export interface TestObject { /** * Original IRI: http://example.org/numOrStr */ - numOrStr: string; + numOrStr: string | number; + /** + * Original IRI: http://example.org/lit1Or2 + */ + lit1Or2: "lit1" | "lit2"; } diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/catShape.shex b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/catShape.shex index 5751278..7dedc2f 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/catShape.shex +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/catShape.shex @@ -2,7 +2,7 @@ PREFIX ex: PREFIX xsd: ex:Cat { - a ["Cat"] ; + a [ ex:Cat ] ; ex:name xsd:string ; ex:age xsd:integer ; ex:numberOfHomes xsd:integer ; diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/personShape.shex b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/personShape.shex index e2859e2..174f883 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/personShape.shex +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/personShape.shex @@ -2,7 +2,7 @@ PREFIX ex: PREFIX xsd: ex:Person { - a ["Person"] ; + a [ ex:Person ] ; ex:name xsd:string ; ex:address { ex:street xsd:string ; diff --git a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/testShape.shex b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/testShape.shex index 6e7ede0..6c9ba8c 100644 --- a/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/testShape.shex +++ b/sdk/ng-sdk-js/examples/multi-framework-signals/src/shapes/shex/testShape.shex @@ -2,7 +2,7 @@ PREFIX ex: PREFIX xsd: ex:TestObject EXTRA a { - a ["TestObject"] ; + a [ ex:TestObject ] ; ex:stringValue xsd:string ; ex:numValue xsd:integer ; ex:boolValue xsd:boolean ; @@ -13,9 +13,9 @@ ex:TestObject EXTRA a { ex:nestedArray xsd:integer* ; } ; ex:anotherObject { - ex:prop1 xsd:string; + ex:prop1 xsd:string ; ex:prop2 xsd:integer ; } * ; - ex:numOrStr xsd:string; - # TODO: ShapeOr -- | ex:numOrStr xsd:integer + ex:numOrStr xsd:string OR xsd:integer ; + ex:lit1Or2 ["lit1" "lit2"] ; } diff --git a/sdk/ng-sdk-js/ng-shex-orm/package.json b/sdk/ng-sdk-js/ng-shex-orm/package.json index 7ad887c..89aa33a 100644 --- a/sdk/ng-sdk-js/ng-shex-orm/package.json +++ b/sdk/ng-sdk-js/ng-shex-orm/package.json @@ -5,7 +5,7 @@ "type": "module", "main": "src/index.ts", "bin": { - "ldo": "./dist/cli.js" + "ldo": "./src/cli.ts" }, "scripts": { "build": "pnpm run build:ts", @@ -59,6 +59,9 @@ "src" ], "publishConfig": { + "bin": { + "ldo": "./dist/cli.js" + }, "access": "public", "main": "./dist/index.js", "types": "./dist/index.d.ts" diff --git a/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/converter.ts b/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/converter.ts index d3e4cfa..8bfaaec3 100644 --- a/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/converter.ts +++ b/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/converter.ts @@ -80,7 +80,7 @@ function flattenSchema(shapes: Shape[]): ShapeSchema { // Find nested, unflattened (i.e. anonymous) schemas in properties. const nestedSchemaPredicates = shape.predicates.filter( (pred) => - pred.type === "nested" && typeof pred.nestedSchema === "object" + pred.type === "nested" && typeof pred.nestedShape === "object" ); for (const pred of nestedSchemaPredicates) { @@ -89,12 +89,12 @@ function flattenSchema(shapes: Shape[]): ShapeSchema { // Recurse const flattened = flattenSchema([ { - ...(pred.nestedSchema as Shape), + ...(pred.nestedShape as Shape), iri: newId, }, ]); // Replace the nested schema with its new id. - pred.nestedSchema = newId; + pred.nestedShape = newId; schema = { ...schema, ...flattened }; } diff --git a/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJSchemaTransformer.ts b/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJSchemaTransformer.ts index f2358f8..ffecf7d 100644 --- a/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJSchemaTransformer.ts +++ b/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJSchemaTransformer.ts @@ -1,6 +1,61 @@ import ShexJTraverser from "@ldo/traverser-shexj"; -import { SchemaProperty, SchemaValue, Shape } from "../../types.ts"; -import { ObjectLiteral } from "../../ShexJTypes.ts"; +import type { Predicate, DataType, Shape } from "../../types.ts"; +import type { ObjectLiteral } from "../../ShexJTypes.ts"; + +const rdfDataTypeToBasic = (dataType: string) => { + switch (dataType) { + case "http://www.w3.org/2001/XMLSchema#string": + case "http://www.w3.org/2001/XMLSchema#ENTITIES": + case "http://www.w3.org/2001/XMLSchema#ENTITY": + case "http://www.w3.org/2001/XMLSchema#ID": + case "http://www.w3.org/2001/XMLSchema#IDREF": + case "http://www.w3.org/2001/XMLSchema#IDREFS": + case "http://www.w3.org/2001/XMLSchema#language": + case "http://www.w3.org/2001/XMLSchema#Name": + case "http://www.w3.org/2001/XMLSchema#NCName": + case "http://www.w3.org/2001/XMLSchema#NMTOKEN": + case "http://www.w3.org/2001/XMLSchema#NMTOKENS": + case "http://www.w3.org/2001/XMLSchema#normalizedString": + case "http://www.w3.org/2001/XMLSchema#QName": + case "http://www.w3.org/2001/XMLSchema#token": + return "string"; + case "http://www.w3.org/2001/XMLSchema#date": + case "http://www.w3.org/2001/XMLSchema#dateTime": + case "http://www.w3.org/2001/XMLSchema#duration": + case "http://www.w3.org/2001/XMLSchema#gDay": + case "http://www.w3.org/2001/XMLSchema#gMonth": + case "http://www.w3.org/2001/XMLSchema#gMonthDay": + case "http://www.w3.org/2001/XMLSchema#gYear": + case "http://www.w3.org/2001/XMLSchema#gYearMonth": + case "http://www.w3.org/2001/XMLSchema#time": + return "string"; + case "http://www.w3.org/2001/XMLSchema#byte": + case "http://www.w3.org/2001/XMLSchema#decimal": + case "http://www.w3.org/2001/XMLSchema#double": + case "http://www.w3.org/2001/XMLSchema#float": + case "http://www.w3.org/2001/XMLSchema#int": + case "http://www.w3.org/2001/XMLSchema#integer": + case "http://www.w3.org/2001/XMLSchema#long": + case "http://www.w3.org/2001/XMLSchema#negativeInteger": + case "http://www.w3.org/2001/XMLSchema#nonNegativeInteger": + case "http://www.w3.org/2001/XMLSchema#nonPositiveInteger": + case "http://www.w3.org/2001/XMLSchema#positiveInteger": + case "http://www.w3.org/2001/XMLSchema#short": + case "http://www.w3.org/2001/XMLSchema#unsignedLong": + case "http://www.w3.org/2001/XMLSchema#unsignedInt": + case "http://www.w3.org/2001/XMLSchema#unsignedShort": + case "http://www.w3.org/2001/XMLSchema#unsignedByte": + return "number"; + case "http://www.w3.org/2001/XMLSchema#boolean": + return "boolean"; + case "http://www.w3.org/2001/XMLSchema#hexBinary": + return "string"; + case "http://www.w3.org/2001/XMLSchema#anyURI": + return "iri"; + default: + return "string"; + } +}; export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< { @@ -8,9 +63,9 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< ShapeDecl: { return: Shape }; Shape: { return: Shape }; EachOf: { return: Shape }; - TripleConstraint: { return: SchemaProperty }; - NodeConstraint: { return: SchemaValue }; - ShapeOr: { return: (SchemaValue | Shape | string)[] }; + TripleConstraint: { return: Predicate }; + NodeConstraint: { return: DataType }; + ShapeOr: { return: (DataType | Shape | string)[] }; ShapeAnd: { return: never }; ShapeNot: { return: never }; ShapeExternal: { return: never }; @@ -63,7 +118,7 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< predicates: transformedChildren.expressions.map( // We disregard cases where properties are referenced (strings) // or where they consist of Unions or Intersections (not supported). - (expr) => expr as SchemaProperty + (expr) => expr as Predicate ), }; }, @@ -89,9 +144,9 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< // Reference to nested object return { type: "nested", - nestedSchema: transformedChildren.valueExpr, + nestedShape: transformedChildren.valueExpr, ...commonProperties, - } satisfies SchemaProperty; + } satisfies Predicate; } else if ( transformedChildren.valueExpr && (transformedChildren.valueExpr as Shape).predicates @@ -99,9 +154,9 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< // Nested object return { type: "nested", - nestedSchema: transformedChildren.valueExpr as Shape, + nestedShape: transformedChildren.valueExpr as Shape, ...commonProperties, - } satisfies SchemaProperty; + } satisfies Predicate; } else if (Array.isArray(transformedChildren.valueExpr)) { return { type: "eitherOf", @@ -111,12 +166,12 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< } else { // type or literal const nodeConstraint = - transformedChildren.valueExpr as SchemaValue; + transformedChildren.valueExpr as DataType; return { type: nodeConstraint.type, literalValue: nodeConstraint.literals, ...commonProperties, - } satisfies SchemaProperty; + } satisfies Predicate; } }, }, @@ -124,40 +179,20 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< NodeConstraint: { transformer: async (nodeConstraint) => { if (nodeConstraint.datatype) { - switch (nodeConstraint.datatype) { - case "http://www.w3.org/2001/XMLSchema#boolean": - return { type: "boolean" }; - case "http://www.w3.org/2001/XMLSchema#byte": - case "http://www.w3.org/2001/XMLSchema#decimal": - case "http://www.w3.org/2001/XMLSchema#double": - case "http://www.w3.org/2001/XMLSchema#float": - case "http://www.w3.org/2001/XMLSchema#int": - case "http://www.w3.org/2001/XMLSchema#integer": - case "http://www.w3.org/2001/XMLSchema#long": - case "http://www.w3.org/2001/XMLSchema#negativeInteger": - case "http://www.w3.org/2001/XMLSchema#nonNegativeInteger": - case "http://www.w3.org/2001/XMLSchema#nonPositiveInteger": - case "http://www.w3.org/2001/XMLSchema#positiveInteger": - case "http://www.w3.org/2001/XMLSchema#short": - case "http://www.w3.org/2001/XMLSchema#unsignedLong": - case "http://www.w3.org/2001/XMLSchema#unsignedInt": - case "http://www.w3.org/2001/XMLSchema#unsignedShort": - case "http://www.w3.org/2001/XMLSchema#unsignedByte": - return { type: "number" }; - default: - return { type: "string" }; // treat most as string - } + return { + type: rdfDataTypeToBasic(nodeConstraint.datatype), + }; } if (nodeConstraint.nodeKind) { // Something reference-like. - return { type: "string" }; + return { type: "iri" }; } if (nodeConstraint.values) { return { type: "literal", literals: nodeConstraint.values.map( // TODO: We do not convert them to number or boolean or lang tag. - (valueRecord) => (valueRecord as ObjectLiteral).value + (valueRecord) => valueRecord.value || valueRecord.id ), }; } @@ -173,12 +208,12 @@ export const ShexJSchemaTransformerCompact = ShexJTraverser.createTransformer< // Transformer from ShapeOr ShapeOr: { transformer: async (shapeOr, getTransformedChildren) => { - const tc = await getTransformedChildren(); + const { shapeExprs } = await getTransformedChildren(); // Either a shape IRI, a nested shape or a node CompactSchemaValue (node constraint). - return (Array.isArray(tc) ? tc : [tc]) as ( + return (Array.isArray(shapeExprs) ? shapeExprs : [shapeExprs]) as ( | string | Shape - | SchemaValue + | DataType )[]; }, }, diff --git a/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJTypingTransformer.ts b/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJTypingTransformer.ts index cb9696e..c5e4ec7 100644 --- a/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJTypingTransformer.ts +++ b/sdk/ng-sdk-js/ng-shex-orm/src/schema-converter/transformers/ShexJTypingTransformer.ts @@ -677,11 +677,8 @@ export const ShexJTypingTransformerCompact = ShexJTraverser.createTransformer< ShapeOr: { transformer: async (_shapeOr, getTransformedChildren) => { const tc = await getTransformedChildren(); - const valid: dom.Type[] = []; - tc.shapeExprs.forEach((t) => { - if (typeof t === "object") valid.push(t); - }); - return dom.create.union(valid); + + return dom.create.union(tc.shapeExprs); }, }, diff --git a/sdk/ng-sdk-js/ng-shex-orm/src/types.ts b/sdk/ng-sdk-js/ng-shex-orm/src/types.ts index d55c2b6..a32197b 100644 --- a/sdk/ng-sdk-js/ng-shex-orm/src/types.ts +++ b/sdk/ng-sdk-js/ng-shex-orm/src/types.ts @@ -1,9 +1,9 @@ -export interface ShapeType { +export interface ShapeType { schema: Schema; - shape: "http://example.org/Cat"; + shape: string; } -export interface OrmBase extends Record { +export interface BaseType extends Record { id: string; } @@ -13,17 +13,17 @@ export type Schema = { export interface Shape { iri: string; - predicates: SchemaProperty[]; + predicates: Predicate[]; } -export type SchemaValue = { +export type DataType = { literals?: number[] | string[] | boolean; - type: "number" | "string" | "boolean" | "literal"; + type: "number" | "string" | "boolean" | "iri" | "literal"; }; -export interface SchemaProperty { +export interface Predicate { /** Type of property. */ - type: "number" | "string" | "boolean" | "literal" | "nested" | "eitherOf"; + type: DataType["type"] | "nested" | "eitherOf"; /** The RDF predicate URI. */ predicateUri: string; /** The alias of the `predicateUri` when serialized to a JSON object. */ @@ -31,13 +31,13 @@ export interface SchemaProperty { /** The required literal value(s), if type is `literal`. Others are allowed, if `extra` is true. */ literalValue?: number | string | boolean | number[] | string[]; /** If type is `nested`, the shape or its IRI. */ - nestedSchema?: string | Shape; + nestedShape?: string | Shape; /** Maximum allowed number of values. `-1` means infinite. */ maxCardinality: number; /** Minimum required number of values */ minCardinality: number; /** If type is `eitherOf`, specifies multiple allowed types (CompactSchemaValue, shapes, or shape IRI). */ - eitherOf?: (SchemaValue | Shape | string)[]; + eitherOf?: (DataType | Shape | string)[]; /** If other (additional) values are permitted. Useful for literals. */ extra?: boolean; } diff --git a/sdk/ng-sdk-js/ng-signals/src/connector/createSignalObjectForShape.ts b/sdk/ng-sdk-js/ng-signals/src/connector/createSignalObjectForShape.ts index 8212da3..964acf1 100644 --- a/sdk/ng-sdk-js/ng-signals/src/connector/createSignalObjectForShape.ts +++ b/sdk/ng-sdk-js/ng-signals/src/connector/createSignalObjectForShape.ts @@ -10,9 +10,9 @@ import type { DeepPatch, DeepSignalObject, } from "@nextgraph-monorepo/ng-alien-deepsignals"; -import type { ShapeType, OrmBase } from "@nextgraph-monorepo/ng-shex-orm"; +import type { ShapeType, BaseType } from "@nextgraph-monorepo/ng-shex-orm"; -interface PoolEntry { +interface PoolEntry { connectionId: string; key: string; shapeType: ShapeType; @@ -37,7 +37,7 @@ interface WasmMessage { connectionId: string; diff?: Diff; shapeType?: ShapeType; - initialData?: OrmBase; + initialData?: BaseType; } function canonicalScope(scope: Scope | undefined): string { @@ -150,7 +150,7 @@ const cleanupSignalRegistry = }) : null; -export function createSignalObjectForShape( +export function createSignalObjectForShape( shapeType: ShapeType, scope?: Scope ) { diff --git a/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/react/useShape.ts b/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/react/useShape.ts index 2db7b2f..fe26e4a 100644 --- a/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/react/useShape.ts +++ b/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/react/useShape.ts @@ -1,11 +1,11 @@ -import type { OrmBase } from "@nextgraph-monorepo/ng-shex-orm"; +import type { BaseType } from "@nextgraph-monorepo/ng-shex-orm"; import { watch } from "@nextgraph-monorepo/ng-alien-deepsignals"; import type { ShapeType } from "@nextgraph-monorepo/ng-shex-orm"; import { useEffect, useRef, useState } from "react"; import { createSignalObjectForShape } from "../../connector/createSignalObjectForShape.ts"; import type { Scope } from "../../types.ts"; -const useShape = ( +const useShape = ( shape: ShapeType, scope: Scope = "" ) => { diff --git a/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/svelte/useShape.svelte.ts b/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/svelte/useShape.svelte.ts index 447426a..cd680f1 100644 --- a/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/svelte/useShape.svelte.ts +++ b/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/svelte/useShape.svelte.ts @@ -7,7 +7,7 @@ import { getDeepSignalRootId, type DeepPatch, } from "@nextgraph-monorepo/ng-alien-deepsignals"; -import type { OrmBase, ShapeType } from "@nextgraph-monorepo/ng-shex-orm"; +import type { BaseType, ShapeType } from "@nextgraph-monorepo/ng-shex-orm"; /** Base result contract for a deepSignal-backed Svelte integration. */ export interface UseDeepSignalResult extends Readable { @@ -88,7 +88,7 @@ export interface UseShapeRuneResult extends UseDeepSignalResult { /** * Shape-specific rune: constructs the signal object for a shape then delegates to {@link useDeepSignal}. */ -export function useShapeRune( +export function useShapeRune( shape: ShapeType, scope?: Scope ): UseShapeRuneResult { diff --git a/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/vue/useShape.ts b/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/vue/useShape.ts index 4be288e..a595cc0 100644 --- a/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/vue/useShape.ts +++ b/sdk/ng-sdk-js/ng-signals/src/frontendAdapters/vue/useShape.ts @@ -2,9 +2,9 @@ import { createSignalObjectForShape } from "../../connector/createSignalObjectFo import type { Scope } from "../../types.ts"; import useDeepSignal from "./useDeepSignal.ts"; import { onBeforeUnmount } from "vue"; -import type { OrmBase, ShapeType } from "@nextgraph-monorepo/ng-shex-orm"; +import type { BaseType, ShapeType } from "@nextgraph-monorepo/ng-shex-orm"; -export function useShape( +export function useShape( shape: ShapeType, scope?: Scope ) {