@manta-eu/codegen 0.1.9 → 0.1.10

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/README.md CHANGED
@@ -68,9 +68,9 @@ Two traps:
68
68
 
69
69
  - The API grants a datastore to a person, or to a service account holding the `operator` realm role.
70
70
  `manta-codegen` holds it; a service account without it is refused the datastore.
71
- - The API can compare the token's `azp` against its own `VITE_KEYCLOAK_CLIENT_ID` and answer 401 for
72
- any other client. That check is off today (`authorizedPartyCheckEnabled`). Turning it on 401s
73
- both `<realm>-cli` and `manta-codegen` unless it learns to accept them.
71
+ - The API can answer 401 for a client the realm never admitted to it. That check is off today
72
+ (`authorizedPartyCheckEnabled`). `<realm>-cli` and `manta-codegen` are admitted: both carry the
73
+ realm's `manta-api` client scope. A client of your own needs that scope too.
74
74
 
75
75
  ## What the datastore does not hold
76
76
 
package/dist/cli.js CHANGED
@@ -62,3 +62,4 @@ program
62
62
  });
63
63
  registerAuthCommands(program, { label: "manta-codegen" });
64
64
  await program.parseAsync();
65
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -16,3 +16,4 @@ export async function fetchRealmShapes(endpoint, token, fetchImpl = fetch) {
16
16
  targetClasses: countTargetClasses(`${shacl}\n${ontology}`),
17
17
  };
18
18
  }
19
+ //# sourceMappingURL=fetch-shapes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-shapes.js","sourceRoot":"","sources":["../src/fetch-shapes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AAUrB,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,WAAmB;IAChE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,kBAAkB,CAAC,WAAW,CAAC,SAAS,CAAC;AACpF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,KAAkB,EAClB,YAAuB,KAAK;IAE5B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;IACtH,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,EAAE,CACrD,gBAAgB,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,SAAS,CAAC,CACvF,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,EAAE,CACxD,gBAAgB,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,SAAS,CAAC,CAC1F,CAAC;IAEF,OAAO;QACL,SAAS,EAAE,0BAA0B,CAAC,gBAAgB,CAAC;QACvD,gBAAgB;QAChB,KAAK;QACL,QAAQ;QACR,aAAa,EAAE,kBAAkB,CAAC,GAAG,KAAK,KAAK,QAAQ,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
package/dist/generate.js CHANGED
@@ -75,3 +75,4 @@ export async function generatePackage({ shacl, ontology, vocabBase }, outDir) {
75
75
  rmSync(stageDir, { recursive: true, force: true });
76
76
  }
77
77
  }
78
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/G,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEzE,kGAAkG;AAClG,MAAM,UAAU,YAAY,CAAC,QAAgB,UAAU,EAAE;IACvD,KAAK,IAAI,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC7C,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;AAClF,CAAC;AAED,6FAA6F;AAC7F,MAAM,SAAS,GAAG,6BAA6B,CAAC;AAEhD,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAE/C,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAc,EAAE,IAAY;IACjE,OAAO,MAAM,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,cAAc,CAAC,MAAc;IACpC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,MAAM,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,MAAc;IAC1D,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAEvF,IAAI,UAAU,KAAK,MAAM;YAAE,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,MAAM,WAAW,GAAG,aAAa,CAAC;AAElC,6FAA6F;AAC7F,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAEvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAE9B,MAAM,KAAK,GAAG,iBAAiB,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAElG,MAAM,IAAI,KAAK,CAAC,+DAA+D,WAAW,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtH,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,MAAc;IACxD,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,YAAY,CACV,OAAO,CAAC,QAAQ,EAChB,CAAC,YAAY,EAAE,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,GAAG,WAAW,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,EACzG,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CACrE,CAAC;IAEF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,yBAAyB,CAAC,CAAC;IACjF,CAAC;IAED,sBAAsB,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAgB,EAAE,MAAc;IAChG,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAE/D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC5C,aAAa,CAAC,MAAM,EAAE,MAAM,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;QACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzB,MAAM,uBAAuB,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC"}
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ export { failOnUnknownNamespace, generatePackage, removeGeneratedFiles } from ".
3
3
  export { sortSchemas } from "./sort-schemas.js";
4
4
  export { countTargetClasses } from "./shapes.js";
5
5
  export { mergeShapes, realmPrefix, sortQuads } from "./turtle.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAoB,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,oBAAoB,EAAqB,MAAM,eAAe,CAAC;AACjH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
package/dist/shapes.js CHANGED
@@ -76,3 +76,4 @@ export function countTargetClasses(turtle) {
76
76
  }
77
77
  return Object.fromEntries([...seen].map(([group, classes]) => [group, classes.size]).sort());
78
78
  }
79
+ //# sourceMappingURL=shapes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shapes.js","sourceRoot":"","sources":["../src/shapes.ts"],"names":[],"mappings":"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"}
@@ -31,3 +31,4 @@ export function sortSchemas(source) {
31
31
  const sorted = [...declarations].sort(byName).map((each) => each.text);
32
32
  return `${[...header, sorted.join("\n\n")].join("\n")}\n`;
33
33
  }
34
+ //# sourceMappingURL=sort-schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sort-schemas.js","sourceRoot":"","sources":["../src/sort-schemas.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAM1C,SAAS,kBAAkB,CAAC,KAAe;IACzC,MAAM,MAAM,GAAe,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,KAAe;IACpC,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhE,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IAE1D,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;AACpH,CAAC;AAED,qGAAqG;AACrG,SAAS,MAAM,CAAC,IAAiB,EAAE,KAAkB;IACnD,OAAO,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,gGAAgG;AAChG,yFAAyF;AACzF,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE3D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAE7C,MAAM,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEvE,OAAO,GAAG,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5D,CAAC"}
package/dist/turtle.js CHANGED
@@ -52,3 +52,4 @@ export function mergeShapes(shacl, ontology, vocabBase) {
52
52
  prefixes: namePrefixes({ ...shapes.prefixes, ...subclasses.prefixes }, vocabBase),
53
53
  });
54
54
  }
55
+ //# sourceMappingURL=turtle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turtle.js","sourceRoot":"","sources":["../src/turtle.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manta-eu/codegen",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "CLI that generates LDkit schemas from a realm's SHACL shapes, read from its datastore",
5
5
  "homepage": "https://developers.manta.eu",
6
6
  "keywords": [
@@ -29,7 +29,7 @@
29
29
  "ldkit": "^2.9.0",
30
30
  "n3": "^2.7.12",
31
31
  "prettier": "^3.8.1",
32
- "@manta-eu/auth": "0.1.9"
32
+ "@manta-eu/auth": "0.1.10"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^24.13.3",
@@ -42,7 +42,12 @@
42
42
  "main": "./dist/index.js",
43
43
  "types": "./dist/index.d.ts",
44
44
  "files": [
45
- "dist"
45
+ "dist",
46
+ "src",
47
+ "!src/**/*.test.*",
48
+ "!src/**/*.stories.*",
49
+ "!src/**/__fixtures__",
50
+ "!src/coverage"
46
51
  ],
47
52
  "publishConfig": {
48
53
  "access": "public"
package/src/cli.ts ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ cachedToken,
4
+ ciClientId,
5
+ clientIdHelp,
6
+ defaultDeployment,
7
+ describeError,
8
+ mintWithClientCredentials,
9
+ publicClientFrom,
10
+ registerAuthCommands,
11
+ type TokenSource,
12
+ userTokenSource,
13
+ } from "@manta-eu/auth";
14
+ import { Command, Option } from "commander";
15
+ import { resolve } from "node:path";
16
+ import { fetchRealmShapes, sparqlEndpoint, type RealmShapes } from "./fetch-shapes.js";
17
+ import { generatePackage } from "./generate.js";
18
+
19
+ type FetchOptions = {
20
+ apiUrl: string;
21
+ datastore: string;
22
+ keycloakUrl: string;
23
+ keycloakRealm: string;
24
+ clientId?: string;
25
+ scope?: string;
26
+ useDeviceCode?: boolean;
27
+ out: string;
28
+ };
29
+
30
+ // The secret stays out of the flags: an argument list is readable to every process on the machine.
31
+ function tokenSourceFor(options: FetchOptions): TokenSource {
32
+ const secret = process.env.MANTA_CLIENT_SECRET;
33
+
34
+ if (secret) {
35
+ const client = publicClientFrom({ ...options, clientId: options.clientId ?? ciClientId });
36
+
37
+ return cachedToken(() => mintWithClientCredentials({ ...client, clientSecret: secret, scope: options.scope }));
38
+ }
39
+
40
+ return userTokenSource(publicClientFrom(options), { label: "manta-codegen", useDeviceCode: options.useDeviceCode });
41
+ }
42
+
43
+ function reportTargetClasses(targetClasses: Record<string, number>): void {
44
+ const total = Object.values(targetClasses).reduce((sum, count) => sum + count, 0);
45
+
46
+ console.error(`manta-codegen: the datastore describes ${total} class(es):`);
47
+ for (const [prefix, count] of Object.entries(targetClasses)) console.error(` ${prefix}: ${count}`);
48
+
49
+ if (total === 0) console.error("manta-codegen: the datastore describes no class. Check the datastore id.");
50
+ }
51
+
52
+ async function readShapes(options: FetchOptions): Promise<RealmShapes> {
53
+ const token = tokenSourceFor(options);
54
+ const endpoint = sparqlEndpoint(options.apiUrl, options.datastore);
55
+ console.error(`manta-codegen: reading the shapes from ${endpoint}`);
56
+
57
+ const shapes = await fetchRealmShapes(endpoint, token);
58
+
59
+ console.error(`manta-codegen: the realm vocabulary base is ${shapes.vocabBase}`);
60
+ reportTargetClasses(shapes.targetClasses);
61
+
62
+ return shapes;
63
+ }
64
+
65
+ // The CLI keeps no copy of either graph: the directory holds generated code and nothing else.
66
+ async function generate(options: FetchOptions): Promise<void> {
67
+ const shapes = await readShapes(options);
68
+ const outDir = resolve(options.out);
69
+
70
+ await generatePackage(shapes, outDir);
71
+
72
+ console.error(`manta-codegen: wrote the LDkit schemas to ${outDir}`);
73
+ }
74
+
75
+ const program = new Command()
76
+ .name("manta-codegen")
77
+ .description("Generate LDkit schemas from a realm's SHACL shapes, read from its datastore.");
78
+
79
+ program
80
+ .command("generate")
81
+ .description("read the realm's shapes and generate the LDkit schemas, one file per namespace")
82
+ .option("--api-url <url>", "Manta API base URL", defaultDeployment.apiUrl)
83
+ .requiredOption("--datastore <id>", "datastore to read")
84
+ .option("--keycloak-url <url>", "Keycloak base URL", defaultDeployment.keycloakUrl)
85
+ .option("--keycloak-realm <realm>", "Keycloak realm", defaultDeployment.keycloakRealm)
86
+ .option("--client-id <id>", clientIdHelp)
87
+ .option("--scope <scope>", "OAuth scope to ask a service account token for")
88
+ .option("--use-device-code", "if a login is needed, use a one-time code instead of a browser redirect")
89
+ .addOption(new Option("--out <dir>", "directory to write into").default("./.ldkit"))
90
+ .action(async (options: FetchOptions) => {
91
+ try {
92
+ await generate(options);
93
+ } catch (error) {
94
+ console.error(`manta-codegen: ${describeError(error)}`);
95
+ process.exit(1);
96
+ }
97
+ });
98
+
99
+ registerAuthCommands(program, { label: "manta-codegen" });
100
+
101
+ await program.parseAsync();
@@ -0,0 +1,45 @@
1
+ import { type FetchLike, type TokenSource, withRenewal } from "@manta-eu/auth";
2
+ import {
3
+ countTargetClasses,
4
+ fetchGraphList,
5
+ fetchGraphTurtle,
6
+ findOntologyGraph,
7
+ shaclGraphIri,
8
+ vocabBaseFromOntologyGraph,
9
+ } from "./shapes.js";
10
+
11
+ export type RealmShapes = {
12
+ vocabBase: string;
13
+ ontologyGraphIri: string;
14
+ shacl: string;
15
+ ontology: string;
16
+ targetClasses: Record<string, number>;
17
+ };
18
+
19
+ export function sparqlEndpoint(apiUrl: string, datastoreId: string): string {
20
+ return `${apiUrl.replace(/\/$/, "")}/d/${encodeURIComponent(datastoreId)}/sparql`;
21
+ }
22
+
23
+ export async function fetchRealmShapes(
24
+ endpoint: string,
25
+ token: TokenSource,
26
+ fetchImpl: FetchLike = fetch,
27
+ ): Promise<RealmShapes> {
28
+ const graphs = await withRenewal(token, (accessToken) => fetchGraphList({ endpoint, token: accessToken }, fetchImpl));
29
+ const ontologyGraphIri = findOntologyGraph(graphs);
30
+
31
+ const shacl = await withRenewal(token, (accessToken) =>
32
+ fetchGraphTurtle({ endpoint, graphIri: shaclGraphIri, token: accessToken }, fetchImpl),
33
+ );
34
+ const ontology = await withRenewal(token, (accessToken) =>
35
+ fetchGraphTurtle({ endpoint, graphIri: ontologyGraphIri, token: accessToken }, fetchImpl),
36
+ );
37
+
38
+ return {
39
+ vocabBase: vocabBaseFromOntologyGraph(ontologyGraphIri),
40
+ ontologyGraphIri,
41
+ shacl,
42
+ ontology,
43
+ targetClasses: countTargetClasses(`${shacl}\n${ontology}`),
44
+ };
45
+ }
@@ -0,0 +1,99 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import { tmpdir } from "node:os";
5
+ import { dirname, join } from "node:path";
6
+ import { format, resolveConfig } from "prettier";
7
+ import { sortSchemas, splitDeclarations } from "./sort-schemas.js";
8
+ import { mergeShapes, realmPrefix } from "./turtle.js";
9
+
10
+ const ldkitEntry = () => createRequire(import.meta.url).resolve("ldkit");
11
+
12
+ // LDkit exports no entry for its own CLI, so the run addresses the file beside the package entry.
13
+ export function ldkitCliPath(entry: string = ldkitEntry()): string {
14
+ for (let dir = dirname(entry); dir !== dirname(dir); dir = dirname(dir)) {
15
+ const candidate = join(dir, "esm", "cli.js");
16
+ if (existsSync(candidate)) return candidate;
17
+ }
18
+
19
+ throw new Error("cannot find the LDkit CLI beside the resolved ldkit package.");
20
+ }
21
+
22
+ // LDkit writes a property name as a bare object key, and Meta sends terms such as `1dClick`.
23
+ const objectKey = /(?<=^\s+)[^\s"':]+(?=:\s)/gm;
24
+
25
+ const validName = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
26
+
27
+ export function quoteInvalidKeys(source: string): string {
28
+ return source.replace(objectKey, (key) => (validName.test(key) ? key : `"${key}"`));
29
+ }
30
+
31
+ // The settings come from the repository the file lands in, so the code matches its neighbors.
32
+ export async function formatTypeScript(source: string, path: string): Promise<string> {
33
+ return format(source, { ...(await resolveConfig(path)), filepath: path });
34
+ }
35
+
36
+ function generatedFiles(outDir: string): string[] {
37
+ return existsSync(outDir) ? readdirSync(outDir).filter((name) => name.endsWith(".ts")) : [];
38
+ }
39
+
40
+ // A schema the shapes no longer describe would keep its file, and its re-export, for ever.
41
+ export function removeGeneratedFiles(outDir: string): void {
42
+ for (const file of generatedFiles(outDir)) rmSync(join(outDir, file));
43
+ }
44
+
45
+ export async function normalizeGeneratedFiles(outDir: string): Promise<void> {
46
+ for (const file of generatedFiles(outDir)) {
47
+ const path = join(outDir, file);
48
+ const source = readFileSync(path, "utf8");
49
+ const normalized = await formatTypeScript(sortSchemas(quoteInvalidKeys(source)), path);
50
+
51
+ if (normalized !== source) writeFileSync(path, normalized);
52
+ }
53
+ }
54
+
55
+ const unknownFile = "_unknown.ts";
56
+
57
+ // LDkit cannot name a term whose prefix the endpoint left out, so it writes the IRI in full.
58
+ // That schema then addresses one realm for ever, whatever realm the next run reads.
59
+ export function failOnUnknownNamespace(outDir: string): void {
60
+ const path = join(outDir, unknownFile);
61
+
62
+ if (!existsSync(path)) return;
63
+
64
+ const names = splitDeclarations(readFileSync(path, "utf8")).declarations.map((each) => each.name);
65
+
66
+ throw new Error(`the endpoint named no prefix for some terms, so LDkit wrote ${unknownFile}: ${names.join(", ")}.`);
67
+ }
68
+
69
+ // The LDkit CLI reports a failure on stderr and still exits 0, so an empty directory is the signal.
70
+ export function runLdkit(shaclPath: string, outDir: string): void {
71
+ removeGeneratedFiles(outDir);
72
+ mkdirSync(outDir, { recursive: true });
73
+ execFileSync(
74
+ process.execPath,
75
+ [ldkitCliPath(), "shacl-to-package", "--prefix-alias", `${realmPrefix}=Manta`, "file", shaclPath, outDir],
76
+ { stdio: "inherit", env: { ...process.env, LC_ALL: "en_US.UTF-8" } },
77
+ );
78
+
79
+ if (!existsSync(join(outDir, "index.ts"))) {
80
+ throw new Error(`LDkit wrote no schema into ${outDir}. Read the error above.`);
81
+ }
82
+
83
+ failOnUnknownNamespace(outDir);
84
+ }
85
+
86
+ export type ShapeSources = { shacl: string; ontology: string; vocabBase: string };
87
+
88
+ export async function generatePackage({ shacl, ontology, vocabBase }: ShapeSources, outDir: string): Promise<void> {
89
+ const stageDir = mkdtempSync(join(tmpdir(), "manta-codegen-"));
90
+
91
+ try {
92
+ const merged = join(stageDir, "shapes.ttl");
93
+ writeFileSync(merged, await mergeShapes(shacl, ontology, vocabBase));
94
+ runLdkit(merged, outDir);
95
+ await normalizeGeneratedFiles(outDir);
96
+ } finally {
97
+ rmSync(stageDir, { recursive: true, force: true });
98
+ }
99
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { fetchRealmShapes, sparqlEndpoint, type RealmShapes } from "./fetch-shapes.js";
2
+ export { failOnUnknownNamespace, generatePackage, removeGeneratedFiles, type ShapeSources } from "./generate.js";
3
+ export { sortSchemas } from "./sort-schemas.js";
4
+ export { countTargetClasses } from "./shapes.js";
5
+ export { mergeShapes, realmPrefix, sortQuads } from "./turtle.js";
package/src/shapes.ts ADDED
@@ -0,0 +1,127 @@
1
+ import { type FetchLike, postTo, RefusedRequestError } from "@manta-eu/auth";
2
+
3
+ // The store puts the shapes here for every realm, so this one carries no realm identifier.
4
+ export const shaclGraphIri = "https://rdfox.com/default-base-iri/shacl";
5
+
6
+ const storeDefaultBaseIri = "https://rdfox.com/default-base-iri/";
7
+
8
+ const ontologyGraphSuffix = "ontology";
9
+
10
+ export function constructGraphQuery(graphIri: string): string {
11
+ if (graphIri.includes(">")) {
12
+ throw new Error(`the graph IRI ${graphIri} carries a ">", which cannot go into a query.`);
13
+ }
14
+
15
+ return `CONSTRUCT { ?s ?p ?o } WHERE { GRAPH <${graphIri}> { ?s ?p ?o } }`;
16
+ }
17
+
18
+ export function graphListQuery(): string {
19
+ return "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }";
20
+ }
21
+
22
+ type SparqlBinding = { g?: { value?: unknown } };
23
+
24
+ export function readGraphList(results: unknown): string[] {
25
+ const bindings = (results as { results?: { bindings?: SparqlBinding[] } }).results?.bindings ?? [];
26
+
27
+ return bindings.map((binding) => binding.g?.value).filter((value): value is string => typeof value === "string");
28
+ }
29
+
30
+ // The realm ontology graph is `<vocab base>ontology`, so finding it also yields the vocab base. The
31
+ // CLI therefore needs no realm name and ships no realm list.
32
+ export function findOntologyGraph(graphIris: readonly string[]): string {
33
+ const candidates = graphIris.filter(
34
+ (iri) => iri.endsWith(ontologyGraphSuffix) && !iri.startsWith(storeDefaultBaseIri),
35
+ );
36
+
37
+ if (candidates.length === 0) {
38
+ throw new Error(
39
+ `the datastore holds no ontology graph. Looked for an IRI that ends with ` +
40
+ `"${ontologyGraphSuffix}" among: ${graphIris.join(", ")}.`,
41
+ );
42
+ }
43
+
44
+ if (candidates.length > 1) {
45
+ throw new Error(`the datastore holds more than one ontology graph: ${candidates.join(", ")}.`);
46
+ }
47
+
48
+ return candidates[0] as string;
49
+ }
50
+
51
+ export function vocabBaseFromOntologyGraph(ontologyGraphIri: string): string {
52
+ return ontologyGraphIri.slice(0, -ontologyGraphSuffix.length);
53
+ }
54
+
55
+ export type DatastoreAccess = { endpoint: string; token: string };
56
+
57
+ export type GraphRequest = DatastoreAccess & { graphIri: string };
58
+
59
+ type SparqlCall = { query: string; accept: string; action: string };
60
+
61
+ async function runSparql(
62
+ { endpoint, token }: DatastoreAccess,
63
+ { query, accept, action }: SparqlCall,
64
+ fetchImpl: FetchLike,
65
+ ): Promise<Response> {
66
+ const response = await postTo(
67
+ endpoint,
68
+ {
69
+ method: "POST",
70
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/sparql-query", Accept: accept },
71
+ body: query,
72
+ },
73
+ fetchImpl,
74
+ );
75
+
76
+ if (!response.ok) throw refusal({ endpoint, action }, response, await response.text());
77
+
78
+ return response;
79
+ }
80
+
81
+ function refusal(call: { endpoint: string; action: string }, response: Response, body: string): Error {
82
+ const rejectsToken = response.status === 401 || response.status === 403;
83
+ const hint = rejectsToken ? " Check that the token carries access to this datastore." : "";
84
+
85
+ return new RefusedRequestError(
86
+ `${call.endpoint} refused ${call.action} with status ${response.status}.${hint} ${body.trim()}`,
87
+ response.status,
88
+ );
89
+ }
90
+
91
+ export async function fetchGraphTurtle(request: GraphRequest, fetchImpl: FetchLike = fetch): Promise<string> {
92
+ const call = {
93
+ query: constructGraphQuery(request.graphIri),
94
+ accept: "text/turtle",
95
+ action: `the read of <${request.graphIri}>`,
96
+ };
97
+
98
+ return (await runSparql(request, call, fetchImpl)).text();
99
+ }
100
+
101
+ export async function fetchGraphList(access: DatastoreAccess, fetchImpl: FetchLike = fetch): Promise<string[]> {
102
+ const call = { query: graphListQuery(), accept: "application/sparql-results+json", action: "the graph list" };
103
+
104
+ return readGraphList(await (await runSparql(access, call, fetchImpl)).json());
105
+ }
106
+
107
+ // The datastore serves the realm's own classes on the empty prefix, so the prefix group is optional.
108
+ const targetClass = /sh:targetClass\s+([A-Za-z][\w-]*)?:([A-Za-z][\w-]*)/g;
109
+
110
+ // The empty prefix reads as nothing in a report, and the reader needs a name for that group.
111
+ export const realmGroup = "(realm)";
112
+
113
+ // A thin result must be visible at once, rather than found later at query time.
114
+ export function countTargetClasses(turtle: string): Record<string, number> {
115
+ const seen = new Map<string, Set<string>>();
116
+
117
+ for (const [, prefix, localName] of turtle.matchAll(targetClass)) {
118
+ if (!localName) continue;
119
+
120
+ const group = prefix ?? realmGroup;
121
+ const classes = seen.get(group) ?? new Set<string>();
122
+ classes.add(localName);
123
+ seen.set(group, classes);
124
+ }
125
+
126
+ return Object.fromEntries([...seen].map(([group, classes]) => [group, classes.size]).sort());
127
+ }
@@ -0,0 +1,46 @@
1
+ const declaration = /^export const (\w+)/;
2
+
3
+ export type Declaration = { name: string; text: string };
4
+
5
+ export type SplitSource = { header: string[]; declarations: Declaration[] };
6
+
7
+ function groupByDeclaration(lines: string[]): string[][] {
8
+ const blocks: string[][] = [];
9
+
10
+ for (const line of lines) {
11
+ if (declaration.test(line)) blocks.push([]);
12
+ blocks[blocks.length - 1]?.push(line);
13
+ }
14
+
15
+ return blocks;
16
+ }
17
+
18
+ function toDeclaration(block: string[]): Declaration {
19
+ return { name: declaration.exec(block[0] ?? "")?.[1] ?? "", text: block.join("\n").trimEnd() };
20
+ }
21
+
22
+ export function splitDeclarations(source: string): SplitSource {
23
+ const lines = source.split("\n");
24
+ const start = lines.findIndex((line) => declaration.test(line));
25
+
26
+ if (start < 0) return { header: lines, declarations: [] };
27
+
28
+ return { header: lines.slice(0, start), declarations: groupByDeclaration(lines.slice(start)).map(toDeclaration) };
29
+ }
30
+
31
+ // A code point order, never localeCompare: the order must not follow the machine that ran the build.
32
+ function byName(left: Declaration, right: Declaration): number {
33
+ return left.name < right.name ? -1 : left.name > right.name ? 1 : 0;
34
+ }
35
+
36
+ // LDkit writes each schema in the order its shape arrives, so one new shape moves whole blocks.
37
+ // packages/ldo/scripts/sort-schemas.mjs holds the same rule, so the two outputs compare.
38
+ export function sortSchemas(source: string): string {
39
+ const { header, declarations } = splitDeclarations(source);
40
+
41
+ if (declarations.length === 0) return source;
42
+
43
+ const sorted = [...declarations].sort(byName).map((each) => each.text);
44
+
45
+ return `${[...header, sorted.join("\n\n")].join("\n")}\n`;
46
+ }
package/src/turtle.ts ADDED
@@ -0,0 +1,69 @@
1
+ import { Parser, Writer } from "n3";
2
+ import type { Quad, Term } from "n3";
3
+
4
+ // LDkit names each generated file after the prefix of the term it holds. The realm vocabulary
5
+ // reaches us on the empty prefix, which LDkit sends to `_unknown.ts`, so it needs a name here.
6
+ export const realmPrefix = "m";
7
+
8
+ export type ParsedTurtle = { quads: Quad[]; prefixes: Record<string, string> };
9
+
10
+ export function parseTurtle(turtle: string): ParsedTurtle {
11
+ const prefixes: Record<string, string> = {};
12
+ const quads = new Parser().parse(turtle, null, (prefix, iri) => {
13
+ prefixes[prefix] = iri.value;
14
+ });
15
+
16
+ return { quads, prefixes };
17
+ }
18
+
19
+ export function writeTurtle({ quads, prefixes }: ParsedTurtle): Promise<string> {
20
+ const writer = new Writer({ prefixes });
21
+ writer.addQuads(quads);
22
+
23
+ return new Promise((resolve, reject) => {
24
+ writer.end((error, result) => (error ? reject(error) : resolve(result)));
25
+ });
26
+ }
27
+
28
+ // A second prefix on the same IRI would let the writer pick either one, so the realm keeps only `m`.
29
+ export function namePrefixes(prefixes: Record<string, string>, vocabBase: string): Record<string, string> {
30
+ const named: Record<string, string> = { [realmPrefix]: vocabBase };
31
+
32
+ for (const [prefix, iri] of Object.entries(prefixes)) {
33
+ if (prefix !== "" && iri !== vocabBase) named[prefix] = iri;
34
+ }
35
+
36
+ return named;
37
+ }
38
+
39
+ function termParts(term: Term): string[] {
40
+ if (term.termType === "Literal") return ["2", term.value, term.language, term.datatype.value];
41
+ if (term.termType === "BlankNode") return ["1", term.value];
42
+
43
+ return ["0", term.value];
44
+ }
45
+
46
+ // A literal holds any text, so a separator character could give one key to two different quads.
47
+ export function quadKey(quad: Quad): string {
48
+ return JSON.stringify([quad.subject, quad.predicate, quad.object, quad.graph].map(termParts));
49
+ }
50
+
51
+ // A SPARQL CONSTRUCT promises no order, and LDkit reads the shapes in the order they arrive: it
52
+ // resolves an ambiguous term to whichever namespace it met last. One order gives one answer.
53
+ export function sortQuads(quads: readonly Quad[]): Quad[] {
54
+ const keyed = quads.map((quad) => ({ key: quadKey(quad), quad }));
55
+ keyed.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0));
56
+
57
+ return keyed.map((each) => each.quad);
58
+ }
59
+
60
+ // LDkit reads one document.
61
+ export function mergeShapes(shacl: string, ontology: string, vocabBase: string): Promise<string> {
62
+ const shapes = parseTurtle(shacl);
63
+ const subclasses = parseTurtle(ontology);
64
+
65
+ return writeTurtle({
66
+ quads: sortQuads([...shapes.quads, ...subclasses.quads]),
67
+ prefixes: namePrefixes({ ...shapes.prefixes, ...subclasses.prefixes }, vocabBase),
68
+ });
69
+ }