visigraph 0.0.6 → 0.0.7
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 +5 -4
- package/dist/main.js +166 -17
- package/dist/main.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# visigraph
|
|
2
2
|
|
|
3
3
|
Command line for [VisiGraph](https://github.com/textologylabs/visigraph):
|
|
4
|
-
|
|
4
|
+
bringing your architecture to life.
|
|
5
5
|
|
|
6
|
-
Early, pre-1.0. Today it validates a model. Next it builds a static
|
|
7
|
-
|
|
8
|
-
a
|
|
6
|
+
Early, pre-1.0. Today it validates a model. Next it builds a static site
|
|
7
|
+
from one: an explorable model you can zoom, drill into and follow, with
|
|
8
|
+
journeys you can play on top. No server; works as a file, a GitLab Pages
|
|
9
|
+
site or a Confluence embed.
|
|
9
10
|
|
|
10
11
|
```sh
|
|
11
12
|
npm install -g visigraph
|
package/dist/main.js
CHANGED
|
@@ -2856,10 +2856,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2856
2856
|
* @param {string} flag
|
|
2857
2857
|
* @private
|
|
2858
2858
|
*/
|
|
2859
|
-
unknownOption(
|
|
2859
|
+
unknownOption(flag2) {
|
|
2860
2860
|
if (this._allowUnknownOption) return;
|
|
2861
2861
|
let suggestion = "";
|
|
2862
|
-
if (
|
|
2862
|
+
if (flag2.startsWith("--") && this._showSuggestionAfterError) {
|
|
2863
2863
|
let candidateFlags = [];
|
|
2864
2864
|
let command = this;
|
|
2865
2865
|
do {
|
|
@@ -2867,9 +2867,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2867
2867
|
candidateFlags = candidateFlags.concat(moreFlags);
|
|
2868
2868
|
command = command.parent;
|
|
2869
2869
|
} while (command && !command._enablePositionalOptions);
|
|
2870
|
-
suggestion = suggestSimilar(
|
|
2870
|
+
suggestion = suggestSimilar(flag2, candidateFlags);
|
|
2871
2871
|
}
|
|
2872
|
-
const message = `error: unknown option '${
|
|
2872
|
+
const message = `error: unknown option '${flag2}'${suggestion}`;
|
|
2873
2873
|
this.error(message, { code: "commander.unknownOption" });
|
|
2874
2874
|
}
|
|
2875
2875
|
/**
|
|
@@ -10807,16 +10807,86 @@ function lineOf(range, lines) {
|
|
|
10807
10807
|
return `line ${line}, column ${col}`;
|
|
10808
10808
|
}
|
|
10809
10809
|
|
|
10810
|
+
// ../core/dist/kinds.js
|
|
10811
|
+
var FAMILIES = ["container", "endpoint", "entity"];
|
|
10812
|
+
var KindRegistry = class _KindRegistry {
|
|
10813
|
+
families = /* @__PURE__ */ new Map();
|
|
10814
|
+
static of(...extensions) {
|
|
10815
|
+
const r = new _KindRegistry();
|
|
10816
|
+
for (const e of extensions)
|
|
10817
|
+
r.register(e);
|
|
10818
|
+
return r;
|
|
10819
|
+
}
|
|
10820
|
+
register(extension) {
|
|
10821
|
+
for (const definition of extension.kinds) {
|
|
10822
|
+
if (!FAMILIES.includes(definition.family)) {
|
|
10823
|
+
throw new Error(`extension '${extension.name}': unknown family '${definition.family}'`);
|
|
10824
|
+
}
|
|
10825
|
+
const table = this.families.get(definition.family) ?? /* @__PURE__ */ new Map();
|
|
10826
|
+
const existing = table.get(definition.kind);
|
|
10827
|
+
if (existing) {
|
|
10828
|
+
throw new Error(`extension '${extension.name}': ${definition.family} kind '${definition.kind}' is already registered by '${existing.extension}'`);
|
|
10829
|
+
}
|
|
10830
|
+
table.set(definition.kind, { definition, extension: extension.name });
|
|
10831
|
+
this.families.set(definition.family, table);
|
|
10832
|
+
}
|
|
10833
|
+
return this;
|
|
10834
|
+
}
|
|
10835
|
+
/** True when at least one kind is registered for the family, so kinds in it are checked. */
|
|
10836
|
+
governs(family) {
|
|
10837
|
+
return (this.families.get(family)?.size ?? 0) > 0;
|
|
10838
|
+
}
|
|
10839
|
+
get(family, kind) {
|
|
10840
|
+
return this.families.get(family)?.get(kind)?.definition;
|
|
10841
|
+
}
|
|
10842
|
+
kinds(family) {
|
|
10843
|
+
return [...this.families.get(family)?.keys() ?? []].sort();
|
|
10844
|
+
}
|
|
10845
|
+
};
|
|
10846
|
+
function checkKind(registry, family, element) {
|
|
10847
|
+
if (!registry || !registry.governs(family))
|
|
10848
|
+
return [];
|
|
10849
|
+
const kind = element.kind;
|
|
10850
|
+
if (kind === void 0)
|
|
10851
|
+
return [];
|
|
10852
|
+
if (typeof kind !== "string")
|
|
10853
|
+
return [["kind", `${family} kind must be a string`]];
|
|
10854
|
+
const def = registry.get(family, kind);
|
|
10855
|
+
if (!def)
|
|
10856
|
+
return [["kind", `unknown ${family} kind '${kind}'; registered: ${registry.kinds(family).join(", ")}`]];
|
|
10857
|
+
const out = [];
|
|
10858
|
+
for (const [name, decl] of Object.entries(def.properties)) {
|
|
10859
|
+
const value = element[name];
|
|
10860
|
+
if (value === void 0) {
|
|
10861
|
+
if (decl.required)
|
|
10862
|
+
out.push([name, `${family} kind '${kind}' requires '${name}'`]);
|
|
10863
|
+
continue;
|
|
10864
|
+
}
|
|
10865
|
+
if (typeof value !== decl.type) {
|
|
10866
|
+
out.push([name, `'${name}' on ${family} kind '${kind}' must be a ${decl.type}`]);
|
|
10867
|
+
continue;
|
|
10868
|
+
}
|
|
10869
|
+
if (decl.enum && !decl.enum.includes(value)) {
|
|
10870
|
+
out.push([name, `'${name}' on ${family} kind '${kind}' must be one of ${decl.enum.join(", ")}; got '${String(value)}'`]);
|
|
10871
|
+
}
|
|
10872
|
+
}
|
|
10873
|
+
return out;
|
|
10874
|
+
}
|
|
10875
|
+
|
|
10810
10876
|
// ../core/dist/resolve.js
|
|
10811
10877
|
function resolve(model, options = {}) {
|
|
10812
|
-
const r = new Resolver();
|
|
10878
|
+
const r = new Resolver(options.kinds);
|
|
10813
10879
|
const root = r.declare(model, model.system, void 0, { file: options.file ?? "", prefix: "" });
|
|
10814
10880
|
r.bind(root, void 0);
|
|
10815
10881
|
r.check(root);
|
|
10816
10882
|
return { root, diagnostics: r.diagnostics };
|
|
10817
10883
|
}
|
|
10818
10884
|
var Resolver = class {
|
|
10885
|
+
kinds;
|
|
10819
10886
|
diagnostics = [];
|
|
10887
|
+
constructor(kinds2) {
|
|
10888
|
+
this.kinds = kinds2;
|
|
10889
|
+
}
|
|
10820
10890
|
/** Scopes by interior identity, so a shared file is one scope. */
|
|
10821
10891
|
scopes = /* @__PURE__ */ new Map();
|
|
10822
10892
|
locs = /* @__PURE__ */ new Map();
|
|
@@ -10855,6 +10925,8 @@ var Resolver = class {
|
|
|
10855
10925
|
return;
|
|
10856
10926
|
}
|
|
10857
10927
|
scope.entities.set(entity.id, entity);
|
|
10928
|
+
for (const [suffix2, message] of checkKind(this.kinds, "entity", entity))
|
|
10929
|
+
err(`${path}.${suffix2}`, message);
|
|
10858
10930
|
});
|
|
10859
10931
|
eachListed(node.journeys, "journeys", err, (journey, path) => {
|
|
10860
10932
|
if (scope.journeys.has(journey.id)) {
|
|
@@ -10868,6 +10940,8 @@ var Resolver = class {
|
|
|
10868
10940
|
err(`${path}.id`, `duplicate container id '${child.id}'`);
|
|
10869
10941
|
return;
|
|
10870
10942
|
}
|
|
10943
|
+
for (const [suffix2, message] of checkKind(this.kinds, "container", child))
|
|
10944
|
+
err(`${path}.${suffix2}`, message);
|
|
10871
10945
|
const link = child[LINKED];
|
|
10872
10946
|
const childLoc = link ? { file: link.file, prefix: "" } : { file: loc.file, prefix: `${loc.prefix}${path}.` };
|
|
10873
10947
|
scope.children.set(child.id, this.declare(child, child.id, child, childLoc, scope.path));
|
|
@@ -10881,6 +10955,8 @@ var Resolver = class {
|
|
|
10881
10955
|
err(`${path}.id`, `duplicate endpoint id '${endpoint.id}' in container '${container.id}'`);
|
|
10882
10956
|
}
|
|
10883
10957
|
endpointIds.add(endpoint.id);
|
|
10958
|
+
for (const [suffix2, message] of checkKind(this.kinds, "endpoint", endpoint))
|
|
10959
|
+
err(`${path}.${suffix2}`, message);
|
|
10884
10960
|
});
|
|
10885
10961
|
const stateIds = /* @__PURE__ */ new Set();
|
|
10886
10962
|
eachListed(container.state, "state", err, (state, path) => {
|
|
@@ -10937,6 +11013,21 @@ var Resolver = class {
|
|
|
10937
11013
|
const loc = this.locs.get(scope);
|
|
10938
11014
|
const err = (path, message) => this.err(loc, path, message);
|
|
10939
11015
|
const node = scope.container ?? this.rootNode(scope);
|
|
11016
|
+
eachListed(node.containers, "containers", () => {
|
|
11017
|
+
}, (container, cPath) => {
|
|
11018
|
+
if (container[LINKED])
|
|
11019
|
+
return;
|
|
11020
|
+
eachListed(container.endpoints, `${cPath}.endpoints`, () => {
|
|
11021
|
+
}, (endpoint, ePath) => {
|
|
11022
|
+
for (const key of ["accepts", "returns"]) {
|
|
11023
|
+
if (endpoint[key] === void 0)
|
|
11024
|
+
continue;
|
|
11025
|
+
const entity = ref(endpoint[key], `${ePath}.${key}`, err);
|
|
11026
|
+
if (entity)
|
|
11027
|
+
this.lookupMember(scope, entity, "entity", `${ePath}.${key}`, err);
|
|
11028
|
+
}
|
|
11029
|
+
});
|
|
11030
|
+
});
|
|
10940
11031
|
eachListed(node.journeys, "journeys", err, (journey, path) => {
|
|
10941
11032
|
const hasSteps = journey.steps !== void 0;
|
|
10942
11033
|
const hasScenarios = journey.scenarios !== void 0;
|
|
@@ -10985,20 +11076,30 @@ var Resolver = class {
|
|
|
10985
11076
|
this.lookupContainer(scope, from, `${p}.from`, err);
|
|
10986
11077
|
const to = ref(step.to, `${p}.to`, err);
|
|
10987
11078
|
const target = to ? this.lookupContainer(scope, to, `${p}.to`, err) : void 0;
|
|
11079
|
+
let endpointDecl;
|
|
10988
11080
|
if (step.endpoint !== void 0) {
|
|
10989
11081
|
const endpoint = ref(step.endpoint, `${p}.endpoint`, err);
|
|
10990
11082
|
if (endpoint && target) {
|
|
10991
11083
|
if (endpoint.includes(".")) {
|
|
10992
11084
|
err(`${p}.endpoint`, `endpoint '${endpoint}' must be a bare id on the 'to' container, not a path`);
|
|
10993
|
-
} else
|
|
10994
|
-
|
|
11085
|
+
} else {
|
|
11086
|
+
endpointDecl = (target.container?.endpoints ?? []).find((e) => e.id === endpoint);
|
|
11087
|
+
if (!endpointDecl)
|
|
11088
|
+
err(`${p}.endpoint`, `container '${to}' has no endpoint '${endpoint}'`);
|
|
10995
11089
|
}
|
|
10996
11090
|
}
|
|
10997
11091
|
}
|
|
10998
11092
|
if (step.payload !== void 0) {
|
|
10999
|
-
const
|
|
11000
|
-
|
|
11001
|
-
|
|
11093
|
+
const entityRef = isRecord(step.payload) ? ref(step.payload.entity, `${p}.payload.entity`, err) : ref(step.payload, `${p}.payload`, err);
|
|
11094
|
+
const payload = entityRef ? this.lookupMember(scope, entityRef, "entity", `${p}.payload`, err) : void 0;
|
|
11095
|
+
if (payload && endpointDecl?.accepts !== void 0 && target) {
|
|
11096
|
+
const owner = this.ownerScope(target);
|
|
11097
|
+
const accepted = owner ? this.lookupMember(owner, endpointDecl.accepts, "entity", `${p}.payload`, () => {
|
|
11098
|
+
}) : void 0;
|
|
11099
|
+
if (accepted && accepted !== payload) {
|
|
11100
|
+
err(`${p}.payload`, `endpoint '${step.endpoint}' on '${to}' accepts '${endpointDecl.accepts}', not '${entityRef}'`);
|
|
11101
|
+
}
|
|
11102
|
+
}
|
|
11002
11103
|
}
|
|
11003
11104
|
if (!STEP_KINDS.includes(step.kind)) {
|
|
11004
11105
|
err(`${p}.kind`, `kind must be one of ${STEP_KINDS.join(", ")}; got '${String(step.kind)}'`);
|
|
@@ -11029,19 +11130,27 @@ var Resolver = class {
|
|
|
11029
11130
|
}
|
|
11030
11131
|
return cur;
|
|
11031
11132
|
}
|
|
11032
|
-
/** Resolve `a.b.name` as container path `a.b` plus a member id. */
|
|
11033
11133
|
lookupMember(scope, pathStr, kind, at, err) {
|
|
11034
11134
|
const segments = pathStr.split(".");
|
|
11035
11135
|
const name = segments.pop();
|
|
11036
11136
|
const owner = segments.length === 0 ? scope : this.lookupContainer(scope, segments.join("."), at, err);
|
|
11037
11137
|
if (!owner)
|
|
11038
|
-
return
|
|
11039
|
-
const
|
|
11040
|
-
if (!
|
|
11138
|
+
return void 0;
|
|
11139
|
+
const found = kind === "entity" ? owner.entities.get(name) : owner.journeys.get(name);
|
|
11140
|
+
if (!found) {
|
|
11041
11141
|
err(at, segments.length === 0 ? `unknown ${kind} '${name}'` : `unknown ${kind} '${name}' in '${segments.join(".")}'`);
|
|
11042
|
-
return
|
|
11142
|
+
return void 0;
|
|
11043
11143
|
}
|
|
11044
|
-
return
|
|
11144
|
+
return found;
|
|
11145
|
+
}
|
|
11146
|
+
/** The scope a container is declared in: where its endpoint contracts resolve from. */
|
|
11147
|
+
ownerScope(target) {
|
|
11148
|
+
for (const s of this.scopes.values()) {
|
|
11149
|
+
for (const child of s.children.values())
|
|
11150
|
+
if (child === target)
|
|
11151
|
+
return s;
|
|
11152
|
+
}
|
|
11153
|
+
return void 0;
|
|
11045
11154
|
}
|
|
11046
11155
|
};
|
|
11047
11156
|
function loadedFile(req, loc) {
|
|
@@ -11098,6 +11207,36 @@ var EXIT = {
|
|
|
11098
11207
|
usage: 2
|
|
11099
11208
|
};
|
|
11100
11209
|
|
|
11210
|
+
// ../ext-http/dist/index.js
|
|
11211
|
+
var http = {
|
|
11212
|
+
name: "@visigraph/ext-http",
|
|
11213
|
+
kinds: [
|
|
11214
|
+
{
|
|
11215
|
+
family: "endpoint",
|
|
11216
|
+
kind: "http",
|
|
11217
|
+
description: "An HTTP endpoint: a method and a path on a container.",
|
|
11218
|
+
properties: {
|
|
11219
|
+
method: {
|
|
11220
|
+
type: "string",
|
|
11221
|
+
tier: "advanced",
|
|
11222
|
+
required: true,
|
|
11223
|
+
enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"],
|
|
11224
|
+
category: "transport"
|
|
11225
|
+
},
|
|
11226
|
+
path: {
|
|
11227
|
+
type: "string",
|
|
11228
|
+
tier: "advanced",
|
|
11229
|
+
required: true,
|
|
11230
|
+
category: "transport"
|
|
11231
|
+
}
|
|
11232
|
+
}
|
|
11233
|
+
}
|
|
11234
|
+
]
|
|
11235
|
+
};
|
|
11236
|
+
|
|
11237
|
+
// src/kinds.ts
|
|
11238
|
+
var kinds = KindRegistry.of(http);
|
|
11239
|
+
|
|
11101
11240
|
// src/commands/validate.ts
|
|
11102
11241
|
function registerValidate(program3) {
|
|
11103
11242
|
program3.command("validate").argument("<model>", "path to a model file (YAML)").description("check a model and every model it links or requires; every identifier must resolve").addHelpText(
|
|
@@ -11115,7 +11254,7 @@ async function validate(file) {
|
|
|
11115
11254
|
const parsed = await loadModel(file);
|
|
11116
11255
|
let diagnostics = parsed.diagnostics;
|
|
11117
11256
|
if (parsed.model) {
|
|
11118
|
-
diagnostics = diagnostics.concat(resolve(parsed.model, { file }).diagnostics);
|
|
11257
|
+
diagnostics = diagnostics.concat(resolve(parsed.model, { file, kinds }).diagnostics);
|
|
11119
11258
|
}
|
|
11120
11259
|
for (const d of diagnostics) {
|
|
11121
11260
|
const where = d.path ? `${d.file ?? file}:${d.path}` : d.file ?? file;
|
|
@@ -11388,11 +11527,21 @@ function relaunch() {
|
|
|
11388
11527
|
}
|
|
11389
11528
|
|
|
11390
11529
|
// src/main.ts
|
|
11530
|
+
for (const stream of [process.stdout, process.stderr]) {
|
|
11531
|
+
stream.on("error", (e) => {
|
|
11532
|
+
if (e.code === "EPIPE") process.exit(process.exitCode ?? 0);
|
|
11533
|
+
throw e;
|
|
11534
|
+
});
|
|
11535
|
+
}
|
|
11391
11536
|
var program2 = new Command();
|
|
11392
11537
|
program2.name("visigraph").addHelpText("before", `${DESCRIPTION}
|
|
11393
11538
|
`).version(VERSION, "-v, --version", "print the version and exit").helpOption("-h, --help", "print help and exit").helpCommand("help [command]", "print help for a command").showHelpAfterError("(run with --help for usage)").exitOverride();
|
|
11394
11539
|
registerValidate(program2);
|
|
11395
11540
|
var INSTANT = /* @__PURE__ */ new Set(["-v", "--version", "-h", "--help", "help"]);
|
|
11541
|
+
var [flag, maybeCommand] = process.argv.slice(2);
|
|
11542
|
+
if ((flag === "-h" || flag === "--help") && maybeCommand && program2.commands.some((c) => c.name() === maybeCommand)) {
|
|
11543
|
+
process.argv.splice(2, 2, "help", maybeCommand);
|
|
11544
|
+
}
|
|
11396
11545
|
try {
|
|
11397
11546
|
if (process.argv.length <= 2) {
|
|
11398
11547
|
program2.outputHelp();
|