@google-cloud/kcmd 0.0.0-stage → 0.1.0

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.
Files changed (150) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +266 -2
  3. package/build/ts/kcmd/cli.js +19578 -0
  4. package/build/ts/kcmd/gcp/alloydb.d.ts +12 -0
  5. package/build/ts/kcmd/gcp/alloydb.js +70 -0
  6. package/build/ts/kcmd/gcp/api.d.ts +29 -0
  7. package/build/ts/kcmd/gcp/api.js +162 -0
  8. package/build/ts/kcmd/gcp/biglake.d.ts +16 -0
  9. package/build/ts/kcmd/gcp/biglake.js +50 -0
  10. package/build/ts/kcmd/gcp/bigquery.d.ts +57 -0
  11. package/build/ts/kcmd/gcp/bigquery.js +134 -0
  12. package/build/ts/kcmd/gcp/context.d.ts +10 -0
  13. package/build/ts/kcmd/gcp/context.js +74 -0
  14. package/build/ts/kcmd/gcp/crm.d.ts +13 -0
  15. package/build/ts/kcmd/gcp/crm.js +91 -0
  16. package/build/ts/kcmd/gcp/dataplex.d.ts +147 -0
  17. package/build/ts/kcmd/gcp/dataplex.js +406 -0
  18. package/build/ts/kcmd/gcp/index.d.ts +3 -0
  19. package/build/ts/kcmd/gcp/index.js +21 -0
  20. package/build/ts/kcmd/gcp/spanner.d.ts +63 -0
  21. package/build/ts/kcmd/gcp/spanner.js +123 -0
  22. package/build/ts/kcmd/index.d.ts +7 -0
  23. package/build/ts/kcmd/index.js +46 -0
  24. package/build/ts/kcmd/layout.d.ts +16 -0
  25. package/build/ts/kcmd/layout.js +31 -0
  26. package/build/ts/kcmd/layouts/documents.d.ts +24 -0
  27. package/build/ts/kcmd/layouts/documents.js +264 -0
  28. package/build/ts/kcmd/layouts/okf.d.ts +31 -0
  29. package/build/ts/kcmd/layouts/okf.js +344 -0
  30. package/build/ts/kcmd/layouts/semantic-model.d.ts +61 -0
  31. package/build/ts/kcmd/layouts/semantic-model.js +542 -0
  32. package/build/ts/kcmd/layouts/standard.d.ts +13 -0
  33. package/build/ts/kcmd/layouts/standard.js +108 -0
  34. package/build/ts/kcmd/manifest.d.ts +34 -0
  35. package/build/ts/kcmd/manifest.js +262 -0
  36. package/build/ts/kcmd/metadata.d.ts +25 -0
  37. package/build/ts/kcmd/metadata.js +8 -0
  38. package/build/ts/kcmd/okf/catalog_residue.d.ts +14 -0
  39. package/build/ts/kcmd/okf/catalog_residue.js +124 -0
  40. package/build/ts/kcmd/okf/concept.d.ts +14 -0
  41. package/build/ts/kcmd/okf/concept.js +104 -0
  42. package/build/ts/kcmd/okf/concept_to_entry.d.ts +8 -0
  43. package/build/ts/kcmd/okf/concept_to_entry.js +254 -0
  44. package/build/ts/kcmd/okf/init_okf_workspace.d.ts +15 -0
  45. package/build/ts/kcmd/okf/init_okf_workspace.js +115 -0
  46. package/build/ts/kcmd/okf/links.d.ts +23 -0
  47. package/build/ts/kcmd/okf/links.js +468 -0
  48. package/build/ts/kcmd/okf/okf_metadata.d.ts +12 -0
  49. package/build/ts/kcmd/okf/okf_metadata.js +82 -0
  50. package/build/ts/kcmd/semantic/bigquery.d.ts +22 -0
  51. package/build/ts/kcmd/semantic/bigquery.js +525 -0
  52. package/build/ts/kcmd/semantic/binding.d.ts +3 -0
  53. package/build/ts/kcmd/semantic/binding.js +97 -0
  54. package/build/ts/kcmd/semantic/catalog_entry.d.ts +24 -0
  55. package/build/ts/kcmd/semantic/catalog_entry.js +35 -0
  56. package/build/ts/kcmd/semantic/converters/owl/convert.d.ts +26 -0
  57. package/build/ts/kcmd/semantic/converters/owl/convert.js +41 -0
  58. package/build/ts/kcmd/semantic/converters/owl/model.d.ts +98 -0
  59. package/build/ts/kcmd/semantic/converters/owl/model.js +30 -0
  60. package/build/ts/kcmd/semantic/converters/owl/parse.d.ts +11 -0
  61. package/build/ts/kcmd/semantic/converters/owl/parse.js +634 -0
  62. package/build/ts/kcmd/semantic/converters/owl/to_ir.d.ts +19 -0
  63. package/build/ts/kcmd/semantic/converters/owl/to_ir.js +390 -0
  64. package/build/ts/kcmd/semantic/deploy_bigquery.d.ts +20 -0
  65. package/build/ts/kcmd/semantic/deploy_bigquery.js +226 -0
  66. package/build/ts/kcmd/semantic/deploy_knowledge_catalog.d.ts +129 -0
  67. package/build/ts/kcmd/semantic/deploy_knowledge_catalog.js +1396 -0
  68. package/build/ts/kcmd/semantic/deploy_spanner.d.ts +15 -0
  69. package/build/ts/kcmd/semantic/deploy_spanner.js +150 -0
  70. package/build/ts/kcmd/semantic/deployment_target.d.ts +93 -0
  71. package/build/ts/kcmd/semantic/deployment_target.js +379 -0
  72. package/build/ts/kcmd/semantic/graph_ddl.d.ts +34 -0
  73. package/build/ts/kcmd/semantic/graph_ddl.js +563 -0
  74. package/build/ts/kcmd/semantic/import_model.d.ts +50 -0
  75. package/build/ts/kcmd/semantic/import_model.js +1275 -0
  76. package/build/ts/kcmd/semantic/ir.d.ts +589 -0
  77. package/build/ts/kcmd/semantic/ir.js +247 -0
  78. package/build/ts/kcmd/semantic/kc_actions.d.ts +45 -0
  79. package/build/ts/kcmd/semantic/kc_actions.js +531 -0
  80. package/build/ts/kcmd/semantic/kc_constraints.d.ts +44 -0
  81. package/build/ts/kcmd/semantic/kc_constraints.js +279 -0
  82. package/build/ts/kcmd/semantic/kc_converter.d.ts +31 -0
  83. package/build/ts/kcmd/semantic/kc_converter.js +824 -0
  84. package/build/ts/kcmd/semantic/kc_custom_types.d.ts +70 -0
  85. package/build/ts/kcmd/semantic/kc_custom_types.js +828 -0
  86. package/build/ts/kcmd/semantic/kc_entries.d.ts +155 -0
  87. package/build/ts/kcmd/semantic/kc_entries.js +284 -0
  88. package/build/ts/kcmd/semantic/kc_ids.d.ts +103 -0
  89. package/build/ts/kcmd/semantic/kc_ids.js +191 -0
  90. package/build/ts/kcmd/semantic/knowledge_catalog.d.ts +32 -0
  91. package/build/ts/kcmd/semantic/knowledge_catalog.js +1043 -0
  92. package/build/ts/kcmd/semantic/loader.d.ts +262 -0
  93. package/build/ts/kcmd/semantic/loader.js +3440 -0
  94. package/build/ts/kcmd/semantic/names.d.ts +10 -0
  95. package/build/ts/kcmd/semantic/names.js +85 -0
  96. package/build/ts/kcmd/semantic/osi_converter.d.ts +60 -0
  97. package/build/ts/kcmd/semantic/osi_converter.js +911 -0
  98. package/build/ts/kcmd/semantic/parameters.d.ts +18 -0
  99. package/build/ts/kcmd/semantic/parameters.js +152 -0
  100. package/build/ts/kcmd/semantic/pull_kc.d.ts +14 -0
  101. package/build/ts/kcmd/semantic/pull_kc.js +346 -0
  102. package/build/ts/kcmd/semantic/resolve_inheritance.d.ts +54 -0
  103. package/build/ts/kcmd/semantic/resolve_inheritance.js +330 -0
  104. package/build/ts/kcmd/semantic/resolve_profiles.d.ts +250 -0
  105. package/build/ts/kcmd/semantic/resolve_profiles.js +1822 -0
  106. package/build/ts/kcmd/semantic/runtime/agent_tools.d.ts +93 -0
  107. package/build/ts/kcmd/semantic/runtime/agent_tools.js +243 -0
  108. package/build/ts/kcmd/semantic/runtime/dialect.d.ts +13 -0
  109. package/build/ts/kcmd/semantic/runtime/dialect.js +39 -0
  110. package/build/ts/kcmd/semantic/runtime/runtime.d.ts +94 -0
  111. package/build/ts/kcmd/semantic/runtime/runtime.js +318 -0
  112. package/build/ts/kcmd/semantic/runtime/store.d.ts +112 -0
  113. package/build/ts/kcmd/semantic/runtime/store.js +344 -0
  114. package/build/ts/kcmd/semantic/skills.d.ts +110 -0
  115. package/build/ts/kcmd/semantic/skills.js +697 -0
  116. package/build/ts/kcmd/semantic/source_dialect.d.ts +10 -0
  117. package/build/ts/kcmd/semantic/source_dialect.js +261 -0
  118. package/build/ts/kcmd/semantic/source_entries.d.ts +12 -0
  119. package/build/ts/kcmd/semantic/source_entries.js +282 -0
  120. package/build/ts/kcmd/semantic/spanner.d.ts +18 -0
  121. package/build/ts/kcmd/semantic/spanner.js +60 -0
  122. package/build/ts/kcmd/semantic/sql_expr_utils.d.ts +17 -0
  123. package/build/ts/kcmd/semantic/sql_expr_utils.js +221 -0
  124. package/build/ts/kcmd/semantic/sql_identifiers.d.ts +6 -0
  125. package/build/ts/kcmd/semantic/sql_identifiers.js +267 -0
  126. package/build/ts/kcmd/semantic/sql_parser.d.ts +44 -0
  127. package/build/ts/kcmd/semantic/sql_parser.js +378 -0
  128. package/build/ts/kcmd/semantic/transpile.d.ts +74 -0
  129. package/build/ts/kcmd/semantic/transpile.js +563 -0
  130. package/build/ts/kcmd/semantic/validate.d.ts +35 -0
  131. package/build/ts/kcmd/semantic/validate.js +1899 -0
  132. package/build/ts/kcmd/semantic/yaml_options.d.ts +6 -0
  133. package/build/ts/kcmd/semantic/yaml_options.js +58 -0
  134. package/build/ts/kcmd/semantic/yaml_update.d.ts +26 -0
  135. package/build/ts/kcmd/semantic/yaml_update.js +782 -0
  136. package/build/ts/kcmd/snapshot.d.ts +33 -0
  137. package/build/ts/kcmd/snapshot.js +379 -0
  138. package/build/ts/kcmd/source.d.ts +31 -0
  139. package/build/ts/kcmd/source.js +119 -0
  140. package/build/ts/kcmd/sources/bq-dataset.d.ts +17 -0
  141. package/build/ts/kcmd/sources/bq-dataset.js +131 -0
  142. package/build/ts/kcmd/sources/entrygroup.d.ts +21 -0
  143. package/build/ts/kcmd/sources/entrygroup.js +83 -0
  144. package/build/ts/kcmd/sources/kb.d.ts +21 -0
  145. package/build/ts/kcmd/sources/kb.js +82 -0
  146. package/build/ts/kcmd/sources/semantic-model.d.ts +18 -0
  147. package/build/ts/kcmd/sources/semantic-model.js +48 -0
  148. package/build/ts/kcmd/sync.d.ts +35 -0
  149. package/build/ts/kcmd/sync.js +697 -0
  150. package/package.json +62 -4
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ // How a model's CONSTRAINTS are encoded in Knowledge Catalog.
3
+ //
4
+ // One entry per constraint, parented to the model anchor, carrying one aspect
5
+ // that holds the invariant. An action is published the same way. Dataplex has
6
+ // no built-in constraint type, so the entry and aspect types are the custom
7
+ // `semantic-constraint` pair, declared in kc_custom_types.ts and created by
8
+ // `kcmd init --semantic-model`. That file lists what is custom; this one holds
9
+ // the encoding that fills the aspect.
10
+ //
11
+ // An entry of its own is what makes the invariant governable. A search can list
12
+ // every rule a model states, whichever way the rule is settled. Dropping a
13
+ // constraint from the model deletes its entry, so the catalog never advertises
14
+ // a rule the model stopped requiring.
15
+ //
16
+ // The five authored fields land in two places. `judgment`, `on_violation`,
17
+ // `severity` and `ai_context` go on the aspect, the last whole --
18
+ // aiContextField in kc_custom_types.ts says why. `description` goes on the
19
+ // entry source, where a pull of an action already reads it, and because a
20
+ // violation quotes that sentence back to the caller as the error, which makes
21
+ // it the entry's summary.
22
+ //
23
+ // The aspect type still DECLARES `expression` and `evaluation`, the two fields
24
+ // of the removed deterministic body, and nothing here writes either. They stay
25
+ // declared so an aspect type already created in a project keeps matching the
26
+ // one `kcmd init` would create, and so a catalog that still holds an
27
+ // expression-only constraint from an older push reads back as a skip with a
28
+ // reason rather than as a silent empty rule. See readConstraint.
29
+ //
30
+ // Both routing words are on the aspect because they are machine-readable, and
31
+ // they are two fields because they answer different questions: what the engine
32
+ // does about a breach, and how grave the breach is. A constraint that states
33
+ // neither is published without them and reads back the same way, so a default
34
+ // stays the IR's to define and a pull never invents a value the model never
35
+ // stated.
36
+ //
37
+ // Call sites: knowledge_catalog.ts emits the entries, kc_converter.ts reads
38
+ // them back, pull_kc.ts hydrates the aspect.
39
+ //
40
+ // WHEN A BUILT-IN CONSTRAINT TYPE SHIPS, follow the instructions at the top of
41
+ // kc_custom_types.ts. Nothing in this file changes, because the readers below
42
+ // match a type by its id suffix and ignore the project it lives in.
43
+ //
44
+ // The helpers at the bottom repeat a few lines from the modules above on
45
+ // purpose. This module imports only the IR, the entry shape and the type
46
+ // registry, so it can be swapped or deleted as a unit.
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.constraintEntryTypeName = constraintEntryTypeName;
49
+ exports.constraintAspectTypeName = constraintAspectTypeName;
50
+ exports.constraintAspectKey = constraintAspectKey;
51
+ exports.constraintEntryId = constraintEntryId;
52
+ exports.constraintOwnedPrefix = constraintOwnedPrefix;
53
+ exports.constraintEntries = constraintEntries;
54
+ exports.isConstraintEntry = isConstraintEntry;
55
+ exports.constraintAspectTypes = constraintAspectTypes;
56
+ exports.readConstraint = readConstraint;
57
+ const ir_1 = require("./ir");
58
+ const kc_custom_types_1 = require("./kc_custom_types");
59
+ // Full resource name of the constraint entry type for a destination.
60
+ function constraintEntryTypeName(dest) {
61
+ return (0, kc_custom_types_1.customEntryTypeName)(kc_custom_types_1.CONSTRAINT_TYPE_ID, dest);
62
+ }
63
+ // Full resource name of the constraint aspect type for a destination.
64
+ function constraintAspectTypeName(dest) {
65
+ return (0, kc_custom_types_1.customAspectTypeName)(kc_custom_types_1.CONSTRAINT_TYPE_ID, dest);
66
+ }
67
+ // Aspect-map key: the `project.location.type` reference form the client keys an
68
+ // entry's aspects by.
69
+ function constraintAspectKey(dest) {
70
+ return (0, kc_custom_types_1.customAspectKey)(kc_custom_types_1.CONSTRAINT_TYPE_ID, dest);
71
+ }
72
+ // The entry id of one constraint: `<model>.constraints.<name>`, alongside
73
+ // `<model>.metrics.<name>` and `<model>.actions.<name>`.
74
+ function constraintEntryId(modelId, constraintName) {
75
+ return `${modelId}.constraints.${slug(constraintName)}`;
76
+ }
77
+ // The entry-id prefix a model's constraints occupy, so delete reconciliation
78
+ // removes the entry of a constraint dropped from the model.
79
+ function constraintOwnedPrefix(modelId) {
80
+ return `${modelId}.constraints.`;
81
+ }
82
+ /**
83
+ * One entry per constraint, to append to the model's entries.
84
+ *
85
+ * Empty when the model declares no constraints, so a model without them is
86
+ * unchanged from before constraints existed. Warns once when it is non-empty:
87
+ * constraints reach Knowledge Catalog and nowhere else, which is worth saying
88
+ * out loud on a push that also deploys a graph.
89
+ */
90
+ function constraintEntries(model, modelId, ctx, warnings) {
91
+ const constraints = model.constraints ?? [];
92
+ if (!constraints.length)
93
+ return [];
94
+ const entries = [];
95
+ for (const constraint of constraints) {
96
+ const id = constraintEntryId(modelId, constraint.name);
97
+ if (!ctx.claim(id, `constraint '${constraint.name}'`))
98
+ continue;
99
+ entries.push({
100
+ name: ctx.entry(id),
101
+ entryType: constraintEntryTypeName(ctx),
102
+ parentEntry: ctx.anchor,
103
+ entrySource: compact({
104
+ displayName: constraint.name,
105
+ description: constraint.description,
106
+ }),
107
+ aspects: {
108
+ [constraintAspectKey(ctx)]: {
109
+ aspectType: constraintAspectTypeName(ctx),
110
+ data: constraintAspectData(constraint),
111
+ },
112
+ },
113
+ });
114
+ }
115
+ // Counted from what was emitted rather than from the model, so a name
116
+ // collision that skipped a constraint does not inflate the number.
117
+ if (entries.length)
118
+ warnings.push(`model '${model.name}': ${entries.length} constraint(s) published as ` +
119
+ `${kc_custom_types_1.CONSTRAINT_TYPE_ID} entries (Knowledge Catalog is the only ` +
120
+ `system a constraint reaches).`);
121
+ return entries;
122
+ }
123
+ // The aspect payload for one constraint: the invariant, what a violation of it
124
+ // does, how grave it is, and the whole of any `ai_context` declared on it.
125
+ //
126
+ // Every field here is read off the model. Nothing is computed, and in
127
+ // particular the aspect type's `evaluation` field is left unwritten: it existed
128
+ // to say which of two bodies a constraint used, and there is one body.
129
+ function constraintAspectData(constraint) {
130
+ return compact({
131
+ judgment: constraint.judgment,
132
+ aiContext: (0, kc_custom_types_1.aiContextAspectValue)(constraint.aiContext),
133
+ onViolation: constraint.onViolation,
134
+ severity: constraint.severity,
135
+ });
136
+ }
137
+ // ---------------------------------------------------------------------------
138
+ // Read side: a constraint entry -> the IR.
139
+ // ---------------------------------------------------------------------------
140
+ // True when an entry is one of a model's constraints. The match is on the entry
141
+ // type's id suffix, so the project the type lives in need not be known. That is
142
+ // what lets a pull keep working once the custom type is replaced by a built-in
143
+ // one.
144
+ function isConstraintEntry(entry) {
145
+ return entry.entryType?.endsWith(`/entryTypes/${kc_custom_types_1.CONSTRAINT_TYPE_ID}`) ??
146
+ false;
147
+ }
148
+ // The aspect type resource names to hydrate for a constraint entry. Named
149
+ // through the entry type's own project so the pull follows the type wherever it
150
+ // lives.
151
+ function constraintAspectTypes(entryTypeBase) {
152
+ return [`${entryTypeBase}/aspectTypes/${kc_custom_types_1.CONSTRAINT_TYPE_ID}`];
153
+ }
154
+ /**
155
+ * Recovers one constraint from its entry, the inverse of constraintEntries.
156
+ *
157
+ * Returns undefined, with a warning, for an entry that states no judgment: an
158
+ * invariant that states no rule would be pulled into a model that then fails
159
+ * its own push-side validation, so one bad entry degrades itself rather than
160
+ * the pull. An entry left over from a push that wrote the removed `expression`
161
+ * body lands there too, and the warning says so by name -- that catalog holds a
162
+ * rule this model can no longer state, and the author has to restate it.
163
+ *
164
+ * `evaluation` is not read. There is one body, so the word it carried says
165
+ * nothing the entry does not.
166
+ */
167
+ function readConstraint(entry, warnings) {
168
+ const name = entry.entrySource?.displayName || idOf(entry.name);
169
+ const data = constraintAspectDataOf(entry);
170
+ const judgment = aspectText(data.judgment);
171
+ if (!judgment) {
172
+ const stale = aspectText(data.expression) ?
173
+ `, though it states an expression -- the deterministic body was ` +
174
+ `removed, and the rule has to be restated in words` :
175
+ '';
176
+ warnings.push(`constraint '${name}': the ${kc_custom_types_1.CONSTRAINT_TYPE_ID} aspect has no ` +
177
+ `judgment${stale}; the constraint is skipped, and pushing this model ` +
178
+ `back will delete the entry`);
179
+ return undefined;
180
+ }
181
+ const constraint = { name, judgment };
182
+ const description = entry.entrySource?.description;
183
+ if (description !== undefined && description !== '')
184
+ constraint.description = description;
185
+ const onViolation = readEnum(name, 'onViolation', data.onViolation, ir_1.VIOLATION_EFFECTS, warnings);
186
+ if (onViolation)
187
+ constraint.onViolation = onViolation;
188
+ // A constraint must say what a violation does, so a pulled one that states no
189
+ // routing word is a model that will not push. Saying so here names the
190
+ // constraint while the pull is in front of the author; the alternative is a
191
+ // push error about a key they never wrote.
192
+ if (constraint.onViolation === undefined) {
193
+ warnings.push(`constraint '${name}': the ${kc_custom_types_1.CONSTRAINT_TYPE_ID} aspect states a ` +
194
+ `judgment but no onViolation, so the pulled constraint will not push ` +
195
+ `until one is added; a constraint must say whether a breach rejects, ` +
196
+ `escalates or warns`);
197
+ }
198
+ const severity = readEnum(name, 'severity', data.severity, ir_1.CONSTRAINT_SEVERITIES, warnings);
199
+ if (severity)
200
+ constraint.severity = severity;
201
+ const aiContext = (0, kc_custom_types_1.aiContextFromAspect)(data.aiContext);
202
+ if (aiContext)
203
+ constraint.aiContext = aiContext;
204
+ return constraint;
205
+ }
206
+ // The value an aspect field states, or undefined when it states none.
207
+ //
208
+ // A value outside the ones the IR defines is dropped with a warning rather than
209
+ // kept, because an unrecognized word would fail the pulled model's own
210
+ // push-side validation. What dropping costs differs by field. An unreadable
211
+ // `severity` leaves a rule unranked, which nothing reads yet. An unreadable
212
+ // `onViolation` has nothing to fall back to, because a constraint must state
213
+ // its routing word: the pulled model names the constraint and says the word is
214
+ // missing, which is the outcome to want when the catalog no longer says how a
215
+ // breach routes.
216
+ function readEnum(name, field, value, allowed, warnings) {
217
+ if (value === undefined || value === null)
218
+ return undefined;
219
+ // Only a string can be one of these words, and the check says so rather than
220
+ // coercing: `String(["escalate"])` is `escalate`, so a coercing reader would
221
+ // invent a routing word the catalog never stated. A blank or whitespace-only
222
+ // value is unset rather than wrong, the same reading a blank judgment gets.
223
+ if (typeof value === 'string') {
224
+ const text = value.trim();
225
+ if (text === '')
226
+ return undefined;
227
+ if (allowed.includes(text))
228
+ return text;
229
+ }
230
+ warnings.push(`constraint '${name}': the ${kc_custom_types_1.CONSTRAINT_TYPE_ID} aspect states ` +
231
+ `${field} ${showAspectValue(value)}, which is not one of ${allowed.join(', ')}; the constraint reads back without one`);
232
+ return undefined;
233
+ }
234
+ // How an unusable aspect value is quoted back in a warning: a string in single
235
+ // quotes, so the word reads plainly, and anything else as JSON, so the reader
236
+ // can see it was never a word at all.
237
+ function showAspectValue(value) {
238
+ return typeof value === 'string' ? `'${value.trim()}'` :
239
+ JSON.stringify(value);
240
+ }
241
+ // ---------------------------------------------------------------------------
242
+ // Local helpers (see the file header on why they are not shared).
243
+ // ---------------------------------------------------------------------------
244
+ // The constraint aspect's `data` from an entry, matched by the aspect key's
245
+ // `.semantic-constraint` suffix or the aspectType's
246
+ // `/aspectTypes/semantic-constraint` suffix, so it is found whichever project
247
+ // the type was provisioned in.
248
+ function constraintAspectDataOf(entry) {
249
+ for (const [key, aspect] of Object.entries(entry.aspects ?? {})) {
250
+ if (key.endsWith(`.${kc_custom_types_1.CONSTRAINT_TYPE_ID}`) ||
251
+ aspect.aspectType?.endsWith(`/aspectTypes/${kc_custom_types_1.CONSTRAINT_TYPE_ID}`)) {
252
+ return aspect.data ?? {};
253
+ }
254
+ }
255
+ return {};
256
+ }
257
+ // The trimmed text an aspect field states, or '' when it states none. A blank
258
+ // or whitespace-only value reads as unset, the same reading readEnum gives.
259
+ function aspectText(value) {
260
+ return typeof value === 'string' ? value.trim() : '';
261
+ }
262
+ // Entry ids allow letters, numbers, underscores, hyphens, and periods.
263
+ function slug(s) {
264
+ return s.replace(/[^A-Za-z0-9_.-]/g, '_');
265
+ }
266
+ // The id segment of a full entry resource name.
267
+ function idOf(name) {
268
+ return name.split('/').pop() ?? name;
269
+ }
270
+ // Drops undefined-valued keys so the emitted aspect (and its golden) only shows
271
+ // fields the model actually set.
272
+ function compact(obj) {
273
+ const out = {};
274
+ for (const [k, v] of Object.entries(obj)) {
275
+ if (v !== undefined)
276
+ out[k] = v;
277
+ }
278
+ return out;
279
+ }
@@ -0,0 +1,31 @@
1
+ import type { Entry, EntryLink } from '../gcp/dataplex';
2
+ import type { OverviewSidecar } from '../layouts/semantic-model';
3
+ import { SemanticModel } from './ir';
4
+ export interface ReadResult {
5
+ models: SemanticModel[];
6
+ warnings: string[];
7
+ secondGeneration?: boolean;
8
+ overviews?: Map<string, OverviewSidecar>;
9
+ }
10
+ /**
11
+ * Reconstructs the Semantic Model IR from Knowledge Catalog entries.
12
+ *
13
+ * Returns one model per `semantic-model` anchor plus any warnings (no anchor,
14
+ * an orphaned child, an entry missing its aspect data). Entries must already be
15
+ * hydrated with their `semantic-*` (and, for entities, `schema`) aspect data; a
16
+ * BASIC list omits aspect data, so the puller re-fetches each entry first.
17
+ *
18
+ * `entryLinks` are the `schema-join` links a pull fetched for the group (see
19
+ * `pull_kc`); each link between two of a model's entity entries is
20
+ * reconstructed as a 1:1 / 1:N relationship. Pass `[]` (the default) to
21
+ * reconstruct entities and metrics only.
22
+ *
23
+ * With `opts.v2Aspects` set, a model whose `semantic-model` aspect has
24
+ * `specVersion` is rebuilt from the second-generation types (see
25
+ * readModelV2), which reads no entry link.
26
+ */
27
+ export declare function modelsFromCatalogResources(entries: Entry[], entryLinks?: EntryLink[], opts?: {
28
+ v2Aspects?: boolean;
29
+ }): ReadResult;
30
+ export declare function linkDedupKey(link: EntryLink): string;
31
+ export declare function linkNamePrefix(modelName: string): string;