filegrc 0.6.3 → 0.6.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "filegrc",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "Zero-dependency Git-native GRC engine",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,8 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { scopedCollectionRecords } from "./collection-scope.js";
2
3
  import { applyResourceBatch } from "./files.js";
3
4
  import { getGitSummary } from "./git.js";
4
5
  import { loadWorkspace } from "./workspace.js";
5
- import { programComponents, resolveProgram, selectedRequirementIds } from "./program.js";
6
+ import { resolveProgram, selectedRequirementIds } from "./program.js";
6
7
 
7
8
  export function collectionRevision(loaded, resourceType, options = {}) {
8
9
  const program = resolveProgram(loaded, options.programId);
@@ -200,26 +201,6 @@ export async function applyCollectionReview(input = process.cwd(), options = {})
200
201
  };
201
202
  }
202
203
 
203
- function scopedCollectionRecords(loaded, resourceType, program) {
204
- if (String(loaded.model.modelVersion) !== "4") {
205
- return loaded.resources.filter((record) => record.type === resourceType);
206
- }
207
- const components = programComponents(loaded, program);
208
- const componentIds = new Set(components.map(({ id }) => id));
209
- const selected = {
210
- system: new Set(program.systemIds || []),
211
- component: componentIds,
212
- framework: new Set(program.frameworkIds || []),
213
- vendor: new Set(components.map(({ vendorId }) => vendorId).filter(Boolean)),
214
- asset: new Set(loaded.resources.filter((record) => (
215
- record.type === "asset" && (record.componentIds || []).some((id) => componentIds.has(id))
216
- )).map(({ id }) => id))
217
- }[resourceType];
218
- return loaded.resources.filter((record) => (
219
- record.type === resourceType && (!selected || selected.has(record.id))
220
- ));
221
- }
222
-
223
204
  function requiredType(loaded, value) {
224
205
  const resourceType = String(value || "").trim();
225
206
  if (!loaded.model.collectionReviews?.[resourceType]) {
@@ -0,0 +1,24 @@
1
+ import { programComponents } from "./program.js";
2
+
3
+ export function scopedCollectionRecords(loaded, resourceType, program) {
4
+ if (String(loaded.model.modelVersion) !== "4") {
5
+ return loaded.resources.filter((record) => record.type === resourceType);
6
+ }
7
+ if (resourceType === "vendor") {
8
+ return loaded.resources.filter((record) => record.type === "vendor");
9
+ }
10
+ const scopedProgram = program || {};
11
+ const components = programComponents(loaded, scopedProgram);
12
+ const componentIds = new Set(components.map(({ id }) => id));
13
+ const selected = {
14
+ system: new Set(scopedProgram.systemIds || []),
15
+ component: componentIds,
16
+ framework: new Set(scopedProgram.frameworkIds || []),
17
+ asset: new Set(loaded.resources.filter((record) => (
18
+ record.type === "asset" && (record.componentIds || []).some((id) => componentIds.has(id))
19
+ )).map(({ id }) => id))
20
+ }[resourceType];
21
+ return loaded.resources.filter((record) => (
22
+ record.type === resourceType && (!selected || selected.has(record.id))
23
+ ));
24
+ }
package/src/validate.js CHANGED
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { readFile, stat } from "node:fs/promises";
3
3
  import { performance } from "node:perf_hooks";
4
4
  import { getResourceDefinition } from "../model/index.js";
5
+ import { scopedCollectionRecords } from "./collection-scope.js";
5
6
  import { isSafeGitName } from "./git-name.js";
6
7
  import { isCanonicalDataPath, resolveDataPath } from "./paths.js";
7
8
  import { parseCalendarDate, validCalendarRecurrence } from "./recurrence.js";
@@ -78,7 +79,7 @@ async function validateWorkspaceUnmeasured(input) {
78
79
  if (record.type === "control") validateControlComponents(record, byId, displayPath, diagnostics);
79
80
  if (record.type === "audit") validateAuditSubservices(record, byId, displayPath, diagnostics);
80
81
  if (record.type === "collection-review") {
81
- validateCollectionReview(record, loaded.model, loaded.resources, byId, displayPath, diagnostics);
82
+ validateCollectionReview(record, loaded, byId, displayPath, diagnostics);
82
83
  }
83
84
  if (record.type === "obligation") validateObligation(record, loaded.model, byId, displayPath, diagnostics);
84
85
  if (record.type === "action-item") {
@@ -158,8 +159,9 @@ async function validateWorkspaceUnmeasured(input) {
158
159
  };
159
160
  }
160
161
 
161
- function validateCollectionReview(record, model, resources, byId, path, diagnostics) {
162
+ function validateCollectionReview(record, loaded, byId, path, diagnostics) {
162
163
  if (record.status !== "active") return;
164
+ const { model } = loaded;
163
165
  const configuration = model.collectionReviews?.[record.resourceType];
164
166
  if (!configuration) return;
165
167
  const allowedDecisions = configuration.decisions || ["complete"];
@@ -174,21 +176,7 @@ function validateCollectionReview(record, model, resources, byId, path, diagnost
174
176
  const program = String(model.modelVersion) === "4"
175
177
  ? (record.scopeResourceIds || []).map((id) => byId.get(id)).find(({ type } = {}) => type === "program")
176
178
  : null;
177
- const programSystemIds = new Set(program?.systemIds || []);
178
- const componentIds = new Set(resources.filter((candidate) => (
179
- candidate.type === "component"
180
- && (candidate.systemUses || []).some(({ systemId }) => programSystemIds.has(systemId))
181
- )).map(({ id }) => id));
182
- const selectedIds = {
183
- system: programSystemIds,
184
- component: componentIds,
185
- framework: new Set(program?.frameworkIds || []),
186
- vendor: new Set(resources.filter(({ id }) => componentIds.has(id)).map(({ vendorId }) => vendorId).filter(Boolean)),
187
- asset: new Set(resources.filter(({ type, componentIds: ids }) => type === "asset" && (ids || []).some((id) => componentIds.has(id))).map(({ id }) => id))
188
- }[record.resourceType];
189
- const recordCount = resources.filter(({ type, id }) => (
190
- type === record.resourceType && (!program || !selectedIds || selectedIds.has(id))
191
- )).length;
179
+ const recordCount = scopedCollectionRecords(loaded, record.resourceType, program).length;
192
180
  if (!recordCount && record.decision === "complete") {
193
181
  diagnostics.push(error(
194
182
  "invalid-collection-review-decision",