@narrative.io/data-collaboration-sdk-ts 2.103.0 → 2.106.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 (43) hide show
  1. package/build/access-tokens/types.d.ts +1 -0
  2. package/build/access-tokens/types.js +1 -0
  3. package/build/apps/index.d.ts +7 -0
  4. package/build/apps/index.js +9 -0
  5. package/build/collaboration-policy/core/filter-builder.js +7 -1
  6. package/build/collaboration-policy/core/jsonschema/json-schema-types.d.ts +45 -0
  7. package/build/collaboration-policy/core/jsonschema/json-schema-types.js +1 -0
  8. package/build/collaboration-policy/core/jsonschema/policy-branches.d.ts +49 -0
  9. package/build/collaboration-policy/core/jsonschema/policy-branches.js +1 -0
  10. package/build/collaboration-policy/core/jsonschema/policy-evaluator.d.ts +22 -0
  11. package/build/collaboration-policy/core/jsonschema/policy-evaluator.js +250 -0
  12. package/build/collaboration-policy/core/jsonschema/sql-builder.d.ts +79 -0
  13. package/build/collaboration-policy/core/jsonschema/sql-builder.js +306 -0
  14. package/build/collaboration-policy/core/types.d.ts +81 -10
  15. package/build/collaboration-policy/index.d.ts +5 -4
  16. package/build/collaboration-policy/index.js +4 -3
  17. package/build/collaboration-policy/useCollaborationPolicy.d.ts +13 -4
  18. package/build/collaboration-policy/useCollaborationPolicy.js +23 -1
  19. package/build/collaboration-policy/utils/path-helpers.d.ts +7 -3
  20. package/build/collaboration-policy/utils/path-helpers.js +6 -22
  21. package/build/datasets/index.d.ts +11 -2
  22. package/build/datasets/index.js +12 -0
  23. package/build/datasets/types.d.ts +25 -0
  24. package/build/forecast/types.d.ts +1 -1
  25. package/build/jobs/index.d.ts +3 -2
  26. package/build/jobs/index.js +2 -1
  27. package/build/jobs/types.d.ts +224 -26
  28. package/build/jobs/types.js +45 -1
  29. package/package.json +7 -6
  30. package/build/collaboration-policy/core/filter-utils.d.ts +0 -6
  31. package/build/collaboration-policy/core/filter-utils.js +0 -49
  32. package/build/collaboration-policy/core/policy-traverser.d.ts +0 -4
  33. package/build/collaboration-policy/core/policy-traverser.js +0 -99
  34. package/build/collaboration-policy/core/policy-validator.d.ts +0 -11
  35. package/build/collaboration-policy/core/policy-validator.js +0 -185
  36. package/build/collaboration-policy/core/sql-builder.d.ts +0 -37
  37. package/build/collaboration-policy/core/sql-builder.js +0 -346
  38. package/build/collaboration-policy/scripts/generate-policy-schema.d.ts +0 -2
  39. package/build/collaboration-policy/scripts/generate-policy-schema.js +0 -4
  40. package/build/collaboration-policy/types/collaboration-policy.d.ts +0 -1370
  41. package/build/collaboration-policy/types/collaboration-policy.js +0 -274
  42. package/build/collaboration-policy/types/index.d.ts +0 -2
  43. package/build/collaboration-policy/types/index.js +0 -1
@@ -1,185 +0,0 @@
1
- import { visitFilterAttributes } from "./filter-utils";
2
- export function validatePolicyAgainstDataset(policy, _dataset, attributes) {
3
- const result = {
4
- isValid: true,
5
- missingAttributes: [],
6
- missingMappings: [],
7
- errors: [],
8
- };
9
- const attributeByName = new Map();
10
- for (const attribute of attributes) {
11
- attributeByName.set(attribute.name, attribute);
12
- }
13
- // Validate the policy structure considering logical operators
14
- const validation = validatePolicyStructure(policy.policy.definition.structure, attributeByName);
15
- if (!validation.isValid) {
16
- result.isValid = false;
17
- result.errors.push(...validation.errors);
18
- // Extract unique missing attributes for backwards compatibility
19
- const allMissingAttributes = new Set();
20
- for (const error of validation.errors) {
21
- if (error.includes("Missing attributes:")) {
22
- const attrs = error
23
- .split("Missing attributes:")[1]
24
- ?.split(",")
25
- .map((s) => s.trim()) || [];
26
- for (const attr of attrs) {
27
- allMissingAttributes.add(attr);
28
- }
29
- }
30
- }
31
- result.missingAttributes = Array.from(allMissingAttributes);
32
- }
33
- const missingFilterAttributes = new Set();
34
- const filters = policy.policy.definition.filters ?? [];
35
- for (const filter of filters) {
36
- collectMissingAttributesFromFilter(filter, attributeByName, missingFilterAttributes);
37
- }
38
- visitStructureFilters(policy.policy.definition.structure, (filter) => collectMissingAttributesFromFilter(filter, attributeByName, missingFilterAttributes), attributeByName);
39
- if (missingFilterAttributes.size > 0) {
40
- result.isValid = false;
41
- const missingList = Array.from(missingFilterAttributes).sort();
42
- result.errors.push(`Filters reference missing attributes: ${missingList.join(", ")}`);
43
- for (const attr of missingList) {
44
- if (!result.missingAttributes.includes(attr)) {
45
- result.missingAttributes.push(attr);
46
- }
47
- }
48
- }
49
- return result;
50
- }
51
- function validatePolicyStructure(structure, attributeByName) {
52
- if (!structure || typeof structure !== "object") {
53
- return { isValid: true, errors: [] };
54
- }
55
- const struct = structure;
56
- // Handle anyOf - at least one must be valid
57
- if (struct.anyOf && Array.isArray(struct.anyOf)) {
58
- for (const option of struct.anyOf) {
59
- const optionValidation = validatePolicyStructure(option, attributeByName);
60
- if (optionValidation.isValid) {
61
- // If any option is valid, the whole anyOf is valid
62
- return { isValid: true, errors: [] };
63
- }
64
- }
65
- // If no options are valid, collect all errors
66
- const allErrors = [];
67
- for (const option of struct.anyOf) {
68
- const optionValidation = validatePolicyStructure(option, attributeByName);
69
- allErrors.push(...optionValidation.errors);
70
- }
71
- return {
72
- isValid: false,
73
- errors: [
74
- `None of the anyOf options are satisfied. Issues: ${allErrors.join("; ")}`,
75
- ],
76
- };
77
- }
78
- // Handle allOf - all must be valid
79
- if (struct.allOf && Array.isArray(struct.allOf)) {
80
- const allErrors = [];
81
- for (const requirement of struct.allOf) {
82
- const reqValidation = validatePolicyStructure(requirement, attributeByName);
83
- if (!reqValidation.isValid) {
84
- allErrors.push(...reqValidation.errors);
85
- }
86
- }
87
- return allErrors.length > 0
88
- ? { isValid: false, errors: allErrors }
89
- : { isValid: true, errors: [] };
90
- }
91
- // Handle single field with attribute
92
- if (struct.field &&
93
- struct.field.type ===
94
- "attribute") {
95
- const attributeName = struct.field
96
- .attribute_name;
97
- const errors = [];
98
- // Check if attribute exists - we don't need to check mappings anymore
99
- // since we use company_data.<attribute_name> format
100
- if (!attributeByName.has(attributeName)) {
101
- errors.push(`Missing attributes: ${attributeName}`);
102
- }
103
- return errors.length > 0
104
- ? { isValid: false, errors }
105
- : { isValid: true, errors: [] };
106
- }
107
- // For other structures, recursively validate
108
- for (const value of Object.values(struct)) {
109
- if (typeof value === "object") {
110
- const childValidation = validatePolicyStructure(value, attributeByName);
111
- if (!childValidation.isValid) {
112
- return childValidation;
113
- }
114
- }
115
- }
116
- return { isValid: true, errors: [] };
117
- }
118
- /**
119
- * Checks if a branch is satisfied (all required attributes exist).
120
- * For anyOf: at least one child must be satisfied.
121
- * For allOf: all children must be satisfied.
122
- * For field nodes: the attribute must exist.
123
- */
124
- function isBranchSatisfied(node, attributeByName) {
125
- if (!node || typeof node !== "object") {
126
- return true;
127
- }
128
- if ("field" in node) {
129
- const field = node.field;
130
- if (field.type === "attribute" && field.attribute_name) {
131
- return attributeByName.has(field.attribute_name);
132
- }
133
- return true;
134
- }
135
- if ("anyOf" in node && Array.isArray(node.anyOf)) {
136
- return node.anyOf.some((child) => isBranchSatisfied(child, attributeByName));
137
- }
138
- if ("allOf" in node && Array.isArray(node.allOf)) {
139
- return node.allOf.every((child) => isBranchSatisfied(child, attributeByName));
140
- }
141
- return true;
142
- }
143
- /**
144
- * Visits filters only in satisfied branches of the policy structure.
145
- * For anyOf nodes, only visits filters in branches where the required attributes exist.
146
- * For allOf nodes, visits filters in all branches (since all must be satisfied).
147
- */
148
- function visitStructureFilters(node, visitor, attributeByName) {
149
- if (!node || typeof node !== "object") {
150
- return;
151
- }
152
- if ("field" in node) {
153
- // Only visit filters if this branch is satisfied
154
- if (isBranchSatisfied(node, attributeByName)) {
155
- const filters = node.filters;
156
- if (filters) {
157
- for (const filter of filters) {
158
- visitor(filter);
159
- }
160
- }
161
- }
162
- return;
163
- }
164
- if ("anyOf" in node && Array.isArray(node.anyOf)) {
165
- // Only visit filters in satisfied branches
166
- for (const child of node.anyOf) {
167
- if (isBranchSatisfied(child, attributeByName)) {
168
- visitStructureFilters(child, visitor, attributeByName);
169
- }
170
- }
171
- }
172
- if ("allOf" in node && Array.isArray(node.allOf)) {
173
- // For allOf, visit all branches (they all must be satisfied)
174
- for (const child of node.allOf) {
175
- visitStructureFilters(child, visitor, attributeByName);
176
- }
177
- }
178
- }
179
- function collectMissingAttributesFromFilter(filter, attributesByName, missingAttributes) {
180
- visitFilterAttributes(filter, (attributeName) => {
181
- if (!attributesByName.has(attributeName)) {
182
- missingAttributes.add(attributeName);
183
- }
184
- });
185
- }
@@ -1,37 +0,0 @@
1
- import type { Attribute } from "../../attributes/types";
2
- import type { Dataset } from "../../datasets/types";
3
- import type { CollaborationPolicyType } from "../types";
4
- import type { PolicyMatchResult, PolicySqlFragments } from "./types";
5
- export declare function buildPolicySqlWithValidation(dataset: Dataset, policies: CollaborationPolicyType[], attributes: Attribute[]): PolicyMatchResult;
6
- /**
7
- * Categorizes collaboration policies into matching and non-matching groups based on dataset compatibility.
8
- *
9
- * This function validates each policy against the provided dataset and attributes to determine
10
- * whether the policy can be successfully applied. Policies are categorized as matching if they
11
- * have all required attributes available, or non-matching if they're missing required attributes
12
- * or mappings.
13
- *
14
- * @param policies - Array of collaboration policies to categorize
15
- * @param dataset - The dataset to validate policies against
16
- * @param attributes - Available attributes for validation
17
- * @returns Object containing matching policies, non-matching policies, and detailed skip information
18
- *
19
- * @example
20
- * ```typescript
21
- * const { matching, nonMatching, skippedDetails } = categorizePolicies(
22
- * allPolicies,
23
- * myDataset,
24
- * availableAttributes
25
- * );
26
- *
27
- * console.log(`${matching.length} policies can be applied`);
28
- * console.log(`${nonMatching.length} policies were skipped`);
29
- * skippedDetails.forEach(skip => console.log(`Skipped ${skip.name}: ${skip.reason}`));
30
- * ```
31
- */
32
- export declare function categorizePolicies(policies: CollaborationPolicyType[], dataset: Dataset, attributes: Attribute[]): {
33
- matching: CollaborationPolicyType[];
34
- nonMatching: CollaborationPolicyType[];
35
- skippedDetails: PolicyMatchResult["skippedPolicies"];
36
- };
37
- export declare function buildPolicySql(dataset: Dataset, policies: CollaborationPolicyType[], attributes: Attribute[]): PolicySqlFragments;
@@ -1,346 +0,0 @@
1
- import { normalizePathValue } from "../utils/path-helpers";
2
- import { buildSelectAlias, resolveAttributeExpression, } from "../utils/sql-helpers";
3
- import { filterToSql } from "./filter-builder";
4
- import { traversePolicy } from "./policy-traverser";
5
- import { validatePolicyAgainstDataset } from "./policy-validator";
6
- function buildAttributeIndexes(attributes) {
7
- const byId = new Map();
8
- const byName = new Map();
9
- for (const attribute of attributes) {
10
- byId.set(attribute.id, attribute);
11
- byName.set(attribute.name, attribute);
12
- }
13
- return { byId, byName };
14
- }
15
- /**
16
- * Converts an ISO 8601 duration string to milliseconds for comparison.
17
- * This is an approximation for human-readable durations (months/years vary in length).
18
- *
19
- * @param duration - ISO 8601 duration string (e.g., "PT1H", "P1D", "P1M")
20
- * @returns Duration in milliseconds
21
- */
22
- function parseDurationToMilliseconds(duration) {
23
- const regex = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
24
- const matches = duration.match(regex);
25
- if (!matches) {
26
- throw new Error(`Invalid ISO 8601 duration format: ${duration}`);
27
- }
28
- const [, years, months, weeks, days, hours, minutes, seconds] = matches.map((m) => Number.parseInt(m || "0", 10));
29
- // Approximate conversions (months = 30 days, years = 365 days)
30
- const milliseconds = years * 365 * 24 * 60 * 60 * 1000 +
31
- months * 30 * 24 * 60 * 60 * 1000 +
32
- weeks * 7 * 24 * 60 * 60 * 1000 +
33
- days * 24 * 60 * 60 * 1000 +
34
- hours * 60 * 60 * 1000 +
35
- minutes * 60 * 1000 +
36
- seconds * 1000;
37
- return milliseconds;
38
- }
39
- /**
40
- * Finds the smallest (most frequent) refresh schedule from a list of ISO 8601 duration strings.
41
- * The smallest duration means the most frequent refresh rate.
42
- *
43
- * @param schedules - Array of ISO 8601 duration strings
44
- * @returns The smallest duration in milliseconds, or 2592000000 (30 days/1 month) if no schedules provided
45
- */
46
- function getSmallestRefreshSchedule(schedules) {
47
- // Default to monthly (30 days in milliseconds)
48
- const defaultMonthlyMs = 30 * 24 * 60 * 60 * 1000;
49
- if (schedules.length === 0) {
50
- return defaultMonthlyMs;
51
- }
52
- if (schedules.length === 1) {
53
- try {
54
- return parseDurationToMilliseconds(schedules[0]);
55
- }
56
- catch (error) {
57
- console.warn(`Invalid refresh schedule: ${schedules[0]}, using default`, error);
58
- return defaultMonthlyMs;
59
- }
60
- }
61
- // Find the schedule with the smallest duration (most frequent refresh)
62
- let smallestValue = Number.MAX_SAFE_INTEGER;
63
- for (const schedule of schedules) {
64
- try {
65
- const value = parseDurationToMilliseconds(schedule);
66
- if (value < smallestValue) {
67
- smallestValue = value;
68
- }
69
- }
70
- catch (error) {
71
- // If parsing fails, skip this schedule
72
- console.warn(`Skipping invalid refresh schedule: ${schedule}`, error);
73
- }
74
- }
75
- // If all schedules failed to parse, return default
76
- return smallestValue === Number.MAX_SAFE_INTEGER
77
- ? defaultMonthlyMs
78
- : smallestValue;
79
- }
80
- /**
81
- * Builds structured WHERE clauses for a single branch node
82
- */
83
- function buildBranchWhere(node, attributeByName, datasetName) {
84
- if (!node || typeof node !== "object") {
85
- return null;
86
- }
87
- // Handle field nodes (leaf nodes with attributes)
88
- if ("field" in node) {
89
- const extendedNode = node;
90
- const field = extendedNode.field;
91
- const attributeName = field.attribute_name;
92
- const attribute = attributeByName.get(attributeName);
93
- if (!attribute) {
94
- return null;
95
- }
96
- const clauses = [];
97
- // Add IS NOT NULL filters for additional_required_properties
98
- if (field.additional_required_properties) {
99
- for (const path of field.additional_required_properties) {
100
- const pathStr = normalizePathValue(path);
101
- const expression = `company_data."${datasetName}"."_rosetta_stone"."${attribute.name}"."${pathStr}"`;
102
- clauses.push(`(${expression} IS NOT NULL)`);
103
- }
104
- }
105
- // Add filters
106
- if (extendedNode.filters) {
107
- for (const filter of extendedNode.filters) {
108
- const sql = filterToSql(filter, attributeByName, datasetName);
109
- clauses.push(sql);
110
- }
111
- }
112
- // If only one clause, return as string
113
- if (clauses.length === 0) {
114
- return null;
115
- }
116
- if (clauses.length === 1) {
117
- return clauses[0];
118
- }
119
- // Multiple clauses for a single field - AND them together
120
- return {
121
- operation: "AND",
122
- fragments: clauses,
123
- };
124
- }
125
- // Handle anyOf nodes
126
- if ("anyOf" in node && Array.isArray(node.anyOf)) {
127
- const satisfiedBranches = [];
128
- for (const child of node.anyOf) {
129
- if (isBranchSatisfied(child, attributeByName)) {
130
- const branchWhere = buildBranchWhere(child, attributeByName, datasetName);
131
- if (branchWhere) {
132
- satisfiedBranches.push(branchWhere);
133
- }
134
- }
135
- }
136
- if (satisfiedBranches.length === 0) {
137
- return null;
138
- }
139
- if (satisfiedBranches.length === 1) {
140
- return satisfiedBranches[0];
141
- }
142
- // Multiple satisfied anyOf branches - OR them together
143
- return {
144
- operation: "OR",
145
- fragments: satisfiedBranches,
146
- };
147
- }
148
- // Handle allOf nodes
149
- if ("allOf" in node && Array.isArray(node.allOf)) {
150
- const allBranches = [];
151
- for (const child of node.allOf) {
152
- const branchWhere = buildBranchWhere(child, attributeByName, datasetName);
153
- if (branchWhere) {
154
- allBranches.push(branchWhere);
155
- }
156
- }
157
- if (allBranches.length === 0) {
158
- return null;
159
- }
160
- if (allBranches.length === 1) {
161
- return allBranches[0];
162
- }
163
- // Multiple allOf branches - AND them together
164
- return {
165
- operation: "AND",
166
- fragments: allBranches,
167
- };
168
- }
169
- return null;
170
- }
171
- /**
172
- * Checks if a branch is satisfied (all required attributes exist)
173
- */
174
- function isBranchSatisfied(node, attributeByName) {
175
- if (!node || typeof node !== "object") {
176
- return true;
177
- }
178
- if ("field" in node) {
179
- const field = node
180
- .field;
181
- if (field.type === "attribute") {
182
- const attributeName = field.attribute_name;
183
- return attributeByName.has(attributeName);
184
- }
185
- return true;
186
- }
187
- if ("anyOf" in node && Array.isArray(node.anyOf)) {
188
- return node.anyOf.some((child) => isBranchSatisfied(child, attributeByName));
189
- }
190
- if ("allOf" in node && Array.isArray(node.allOf)) {
191
- return node.allOf.every((child) => isBranchSatisfied(child, attributeByName));
192
- }
193
- return true;
194
- }
195
- function buildPolicySqlUsingIndexes(policies, attributeByName, datasetName) {
196
- const globalRequiredAttributePaths = new Map();
197
- const policyWhereGroups = [];
198
- for (const policy of policies) {
199
- const policyRequiredAttributePaths = new Map();
200
- const policyWhereClausesSet = new Set();
201
- // Still use traversePolicy to collect required attributes for SELECT
202
- traversePolicy(policy, attributeByName, policyRequiredAttributePaths, policyWhereClausesSet, datasetName);
203
- // Build structured WHERE for this policy
204
- const policyWhere = buildBranchWhere(policy.policy.definition.structure, attributeByName, datasetName);
205
- if (policyWhere) {
206
- policyWhereGroups.push(policyWhere);
207
- }
208
- for (const [attributeName, paths] of policyRequiredAttributePaths) {
209
- const globalPaths = globalRequiredAttributePaths.get(attributeName) ?? new Set();
210
- for (const path of paths) {
211
- globalPaths.add(path);
212
- }
213
- globalRequiredAttributePaths.set(attributeName, globalPaths);
214
- }
215
- }
216
- const selectClauses = new Set();
217
- for (const [attributeName, _paths] of globalRequiredAttributePaths) {
218
- const attribute = attributeByName.get(attributeName);
219
- if (!attribute) {
220
- continue;
221
- }
222
- // Always select the root attribute (without path)
223
- const expression = resolveAttributeExpression(attribute, "", // Empty path for root attribute
224
- datasetName);
225
- const alias = buildSelectAlias(attributeName, "");
226
- selectClauses.add(`${expression} AS ${alias}`);
227
- }
228
- // Build the root AND structure
229
- // Root level is always AND (combines policies)
230
- // Each policy's branches are already OR'd/AND'd by buildBranchWhere
231
- let where;
232
- if (policyWhereGroups.length === 0) {
233
- where = [];
234
- }
235
- else {
236
- // Wrap all policies in root AND
237
- // Each policy in policyWhereGroups is already a complete policy structure
238
- where = [
239
- {
240
- fragments: policyWhereGroups,
241
- operation: "AND",
242
- },
243
- ];
244
- }
245
- return {
246
- select: Array.from(selectClauses),
247
- where,
248
- };
249
- }
250
- export function buildPolicySqlWithValidation(dataset, policies, attributes) {
251
- const attributeIndexes = buildAttributeIndexes(attributes);
252
- const validPolicies = [];
253
- const skippedPolicies = [];
254
- const warnings = [];
255
- // Validate each policy against the dataset
256
- for (const policy of policies) {
257
- const validation = validatePolicyAgainstDataset(policy, dataset, attributes);
258
- if (validation.isValid) {
259
- validPolicies.push(policy);
260
- }
261
- else {
262
- skippedPolicies.push({
263
- name: policy.display_name || policy.name,
264
- reason: "Missing required attributes or mappings",
265
- details: validation.errors,
266
- });
267
- }
268
- }
269
- // Check if we have at least one valid policy
270
- if (validPolicies.length === 0) {
271
- const errorMessage = policies.length === 0
272
- ? "No policies provided"
273
- : `No policies are compatible with dataset "${dataset.display_name || dataset.name}".`;
274
- const details = skippedPolicies.length > 0
275
- ? [`Skipped policies: ${skippedPolicies.map((p) => p.name).join(", ")}`]
276
- : [];
277
- throw new Error(`${errorMessage}\n${details.join("\n")}`);
278
- }
279
- if (skippedPolicies.length > 0) {
280
- warnings.push(`Skipped ${skippedPolicies.length} incompatible policies: ${skippedPolicies.map((p) => p.name).join(", ")}`);
281
- }
282
- // Build SQL for valid policies
283
- const sqlFragments = buildPolicySqlUsingIndexes(validPolicies, attributeIndexes.byName, dataset.name);
284
- // Calculate the smallest refresh schedule from applied policies
285
- const refreshSchedules = validPolicies
286
- .map((p) => p.policy.metadata?.refresh_schedule?.max)
287
- .filter((schedule) => schedule !== undefined);
288
- const refreshSchedule = getSmallestRefreshSchedule(refreshSchedules);
289
- return {
290
- ...sqlFragments,
291
- appliedPolicies: validPolicies.map((p) => p.name),
292
- skippedPolicies,
293
- warnings,
294
- refresh_schedule: refreshSchedule,
295
- };
296
- }
297
- /**
298
- * Categorizes collaboration policies into matching and non-matching groups based on dataset compatibility.
299
- *
300
- * This function validates each policy against the provided dataset and attributes to determine
301
- * whether the policy can be successfully applied. Policies are categorized as matching if they
302
- * have all required attributes available, or non-matching if they're missing required attributes
303
- * or mappings.
304
- *
305
- * @param policies - Array of collaboration policies to categorize
306
- * @param dataset - The dataset to validate policies against
307
- * @param attributes - Available attributes for validation
308
- * @returns Object containing matching policies, non-matching policies, and detailed skip information
309
- *
310
- * @example
311
- * ```typescript
312
- * const { matching, nonMatching, skippedDetails } = categorizePolicies(
313
- * allPolicies,
314
- * myDataset,
315
- * availableAttributes
316
- * );
317
- *
318
- * console.log(`${matching.length} policies can be applied`);
319
- * console.log(`${nonMatching.length} policies were skipped`);
320
- * skippedDetails.forEach(skip => console.log(`Skipped ${skip.name}: ${skip.reason}`));
321
- * ```
322
- */
323
- export function categorizePolicies(policies, dataset, attributes) {
324
- const matching = [];
325
- const nonMatching = [];
326
- const skippedDetails = [];
327
- for (const policy of policies) {
328
- const validation = validatePolicyAgainstDataset(policy, dataset, attributes);
329
- if (validation.isValid) {
330
- matching.push(policy);
331
- }
332
- else {
333
- nonMatching.push(policy);
334
- skippedDetails.push({
335
- name: policy.display_name || policy.name,
336
- reason: "Missing required attributes or mappings",
337
- details: validation.errors,
338
- });
339
- }
340
- }
341
- return { matching, nonMatching, skippedDetails };
342
- }
343
- export function buildPolicySql(dataset, policies, attributes) {
344
- const attributeIndexes = buildAttributeIndexes(attributes);
345
- return buildPolicySqlUsingIndexes(policies, attributeIndexes.byName, dataset.name);
346
- }
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env bun
2
- export {};
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { buildCollaborationPolicyJsonSchema } from "../types";
3
- const schema = buildCollaborationPolicyJsonSchema();
4
- console.log(JSON.stringify(schema, null, 2));