@sdd-method/verify-cli 5.4.0 → 5.4.1

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.
@@ -90,13 +90,15 @@ function find(view, catalogue, column, value) {
90
90
  return undefined;
91
91
  }
92
92
  /** The element's references: each non-external foreign key with a value. */
93
- export function referencesOf(schema, e) {
93
+ export function referencesOf(schema, e, profile = "") {
94
94
  const cat = catalogueOf(schema, e.catalogue);
95
95
  if (!cat)
96
96
  return [];
97
97
  const out = [];
98
98
  for (const fk of cat.foreignKeys) {
99
- if (fk.external)
99
+ // An external key names another SDD's element; so does one external for this SDD's profile (an application or
100
+ // integration model naming a data item the platform model owns), as the FK validator and the graph projection read it.
101
+ if (fk.external || (profile !== "" && (fk.externalForProfiles ?? []).includes(profile)))
100
102
  continue;
101
103
  const v = e.columns[fk.column];
102
104
  if (v === undefined || v === "")
@@ -121,7 +123,7 @@ function naturalKey(cat, e) {
121
123
  * catalogue of another class, against its built rows), no cycle through a self-reference, natural keys unique, and
122
124
  * domain invariants naming their entity's own attributes and relationships.
123
125
  */
124
- export function validateView(schema, view, built, problems, unresolved, addedBy = () => undefined) {
126
+ export function validateView(schema, view, built, problems, unresolved, addedBy = () => undefined, profile = "") {
125
127
  // A reference to an open change's addition, from outside that change and its dependants (§4.11 proof 3).
126
128
  const outside = (catalogue, id) => {
127
129
  const by = addedBy(catalogue, id);
@@ -135,7 +137,7 @@ export function validateView(schema, view, built, problems, unresolved, addedBy
135
137
  problems.push(...shape);
136
138
  if (!cat || cat.sourceOfTruth !== STRUCTURE)
137
139
  continue;
138
- for (const r of referencesOf(schema, e)) {
140
+ for (const r of referencesOf(schema, e, profile)) {
139
141
  if (r.structural) {
140
142
  if (!find(view, r.catalogue, r.targetColumn, r.value))
141
143
  problems.push(`${e.file}: ${elementKey(catalogue, e.id)}: ${r.column} ${JSON.stringify(r.value)} names no ${r.catalogue} element in this view (${elementKey(r.catalogue, r.value)})${r.targetColumn === "id" ? outside(r.catalogue, r.value) : ""}`);
@@ -218,7 +220,7 @@ export function validateView(schema, view, built, problems, unresolved, addedBy
218
220
  * A base revision that no longer matches the current element is reported as moved: the change is revalidated.
219
221
  * `addedElsewhere` holds the elements other open changes add, for a reference into one of them.
220
222
  */
221
- export function validateDeltas(schema, current, deltas, addedElsewhere, problems) {
223
+ export function validateDeltas(schema, current, deltas, addedElsewhere, problems, profile = "") {
222
224
  const ownAdded = new Set();
223
225
  const dependsOn = new Set();
224
226
  for (const d of deltas) {
@@ -281,7 +283,7 @@ export function validateDeltas(schema, current, deltas, addedElsewhere, problems
281
283
  }
282
284
  // Reads: every element an added or modified element references.
283
285
  for (const e of [...d.added, ...d.modified]) {
284
- for (const r of referencesOf(schema, e)) {
286
+ for (const r of referencesOf(schema, e, profile)) {
285
287
  if (!r.structural)
286
288
  continue;
287
289
  const target = r.targetColumn === "id" ? r.value : find(current, r.catalogue, r.targetColumn, r.value)?.id;
@@ -162,7 +162,7 @@ export async function checkStructuralModel(repo, options = {}) {
162
162
  // The current view.
163
163
  const unresolved = new Set();
164
164
  const currentProblems = [];
165
- validateView(schema, view, builtIn(built, allNew, new Set()), currentProblems, unresolved, addedBy);
165
+ validateView(schema, view, builtIn(built, allNew, new Set()), currentProblems, unresolved, addedBy, profile);
166
166
  problems.push(...currentProblems);
167
167
  const elementCount = [...view.values()].reduce((n, m) => n + m.size, 0);
168
168
  lines.push(files === null ? `model: none (${STRUCTURE_DIR}/ absent)` : `model: ${files.length} partition file(s), ${elementCount} element(s) in ${view.size} catalogue(s)`);
@@ -211,7 +211,7 @@ export async function checkStructuralModel(repo, options = {}) {
211
211
  if (s.noOp && s.deltas.length > 0)
212
212
  problems.push(`${s.noOp.file}: a no-op claim beside ${s.deltas.length} partition delta(s); state one or the other`);
213
213
  const elsewhere = new Map([...addedByChange].filter(([, c]) => c !== s.change));
214
- validateDeltas(schema, view, s.deltas, elsewhere, problems);
214
+ validateDeltas(schema, view, s.deltas, elsewhere, problems, profile);
215
215
  // A behaviour delta for a feature the model does not hold needs that feature added here.
216
216
  const adds = new Set(s.deltas.flatMap((d) => d.added.filter((e) => e.catalogue === "features").map((e) => e.id)));
217
217
  for (const feature of await subdirs(join(repo, dir, "specs"))) {
@@ -238,7 +238,7 @@ export async function checkStructuralModel(repo, options = {}) {
238
238
  if (oc.structure.deltas.length === 0)
239
239
  continue;
240
240
  const at = [];
241
- validateView(schema, viewAt(view, name, open), builtIn(built, allNew, additions.contracts(closure(name, open))), at, new Set(), addedBy);
241
+ validateView(schema, viewAt(view, name, open), builtIn(built, allNew, additions.contracts(closure(name, open))), at, new Set(), addedBy, profile);
242
242
  for (const p of at) {
243
243
  if (known.has(p))
244
244
  continue;
@@ -250,7 +250,7 @@ export async function checkStructuralModel(repo, options = {}) {
250
250
  const agreed = agreedOrder(open);
251
251
  if (agreed.length > 0) {
252
252
  const inIntended = [];
253
- validateView(schema, intended(view, open), builtIn(built, allNew, additions.contracts(agreed)), inIntended, new Set(), addedBy);
253
+ validateView(schema, intended(view, open), builtIn(built, allNew, additions.contracts(agreed)), inIntended, new Set(), addedBy, profile);
254
254
  for (const p of inIntended) {
255
255
  if (known.has(p) || atAgreed.has(p))
256
256
  continue;
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.18.0",
3
- "built_against_sdd_cli": "5.4.0"
2
+ "version": "0.18.1",
3
+ "built_against_sdd_cli": "5.4.1"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "5.4.0",
3
- "built_against_sdd_cli": "5.4.0"
2
+ "version": "5.4.1",
3
+ "built_against_sdd_cli": "5.4.1"
4
4
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sdd-method/verify-cli",
3
- "version": "5.4.0",
4
- "sddCliVersion": "5.4.0",
3
+ "version": "5.4.1",
4
+ "sddCliVersion": "5.4.1",
5
5
  "description": "Verify an SDD repository without changing it — validate, list, and read-only catalogue and pack checks. Ships only the code those verbs reach; it cannot write to the repository it is pointed at. Authoring and maintenance are in @sdd-method/sdd-cli.",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",