sf-plugin-permission-sets 0.0.0-dev.20 → 0.0.0-dev.21

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 (71) hide show
  1. package/README.md +19 -16
  2. package/lib/adapters/connection-org-client.d.ts +7 -3
  3. package/lib/adapters/connection-org-client.js +173 -4
  4. package/lib/adapters/connection-org-client.js.map +1 -1
  5. package/lib/commands/ps/apply.d.ts +25 -0
  6. package/lib/commands/ps/apply.js +116 -0
  7. package/lib/commands/ps/apply.js.map +1 -0
  8. package/lib/commands/ps/check.d.ts +1 -1
  9. package/lib/commands/ps/check.js +1 -1
  10. package/lib/commands/ps/check.js.map +1 -1
  11. package/lib/commands/ps/export.d.ts +17 -0
  12. package/lib/commands/ps/export.js +29 -0
  13. package/lib/commands/ps/export.js.map +1 -0
  14. package/lib/commands/ps/plan.d.ts +21 -0
  15. package/lib/commands/ps/plan.js +74 -0
  16. package/lib/commands/ps/plan.js.map +1 -0
  17. package/lib/commands/ps/validate.d.ts +1 -1
  18. package/lib/commands/ps/validate.js +1 -1
  19. package/lib/commands/ps/validate.js.map +1 -1
  20. package/lib/core/diff.d.ts +8 -0
  21. package/lib/core/diff.js +35 -0
  22. package/lib/core/diff.js.map +1 -0
  23. package/lib/core/finding.d.ts +27 -0
  24. package/lib/core/finding.js +22 -0
  25. package/lib/core/finding.js.map +1 -0
  26. package/lib/core/load.js +2 -1
  27. package/lib/core/load.js.map +1 -1
  28. package/lib/core/model.d.ts +38 -7
  29. package/lib/core/normalize.d.ts +5 -1
  30. package/lib/core/normalize.js +6 -9
  31. package/lib/core/normalize.js.map +1 -1
  32. package/lib/core/parse.d.ts +1 -1
  33. package/lib/core/parse.js +3 -8
  34. package/lib/core/parse.js.map +1 -1
  35. package/lib/core/report.d.ts +6 -8
  36. package/lib/core/report.js +45 -11
  37. package/lib/core/report.js.map +1 -1
  38. package/lib/core/resolve.d.ts +6 -1
  39. package/lib/core/resolve.js +31 -12
  40. package/lib/core/resolve.js.map +1 -1
  41. package/lib/core/schema.d.ts +1 -1
  42. package/lib/core/schema.js +2 -6
  43. package/lib/core/schema.js.map +1 -1
  44. package/lib/core/serialize.d.ts +7 -0
  45. package/lib/core/serialize.js +27 -0
  46. package/lib/core/serialize.js.map +1 -0
  47. package/lib/services/adapters/org-client.d.ts +19 -0
  48. package/lib/services/adapters/org-client.js.map +1 -0
  49. package/lib/services/apply.d.ts +40 -0
  50. package/lib/services/apply.js +115 -0
  51. package/lib/services/apply.js.map +1 -0
  52. package/lib/services/check.d.ts +2 -1
  53. package/lib/services/check.js +1 -1
  54. package/lib/services/check.js.map +1 -1
  55. package/lib/services/export.d.ts +13 -0
  56. package/lib/services/export.js +25 -0
  57. package/lib/services/export.js.map +1 -0
  58. package/lib/services/plan.d.ts +35 -0
  59. package/lib/services/plan.js +70 -0
  60. package/lib/services/plan.js.map +1 -0
  61. package/lib/services/validate.d.ts +3 -2
  62. package/lib/services/validate.js +2 -2
  63. package/lib/services/validate.js.map +1 -1
  64. package/messages/ps.apply.md +81 -0
  65. package/messages/ps.export.md +25 -0
  66. package/messages/ps.plan.md +45 -0
  67. package/oclif.manifest.json +267 -1
  68. package/package.json +10 -7
  69. package/lib/services/org-client.d.ts +0 -11
  70. package/lib/services/org-client.js.map +0 -1
  71. /package/lib/services/{org-client.js → adapters/org-client.js} +0 -0
@@ -0,0 +1,74 @@
1
+ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
2
+ import { Messages } from '@salesforce/core';
3
+ import { ConnectionOrgClient } from '../../adapters/connection-org-client.js';
4
+ import { PlanService } from '../../services/plan.js';
5
+ import { formatDiff } from '../../core/report.js';
6
+ import { formatFindings } from '../../core/finding.js';
7
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
8
+ const messages = Messages.loadMessages('sf-plugin-permission-sets', 'ps.plan');
9
+ export default class Plan extends SfCommand {
10
+ static summary = messages.getMessage('summary');
11
+ static description = messages.getMessage('description');
12
+ static examples = messages.getMessages('examples');
13
+ static flags = {
14
+ 'target-org': Flags.requiredOrg(),
15
+ 'api-version': Flags.orgApiVersion(),
16
+ file: Flags.string({
17
+ char: 'f',
18
+ summary: messages.getMessage('flags.file.summary'),
19
+ required: true,
20
+ multiple: true,
21
+ }),
22
+ mode: Flags.option({
23
+ summary: messages.getMessage('flags.mode.summary'),
24
+ options: ['additive', 'destructive', 'sync'],
25
+ default: 'additive',
26
+ })(),
27
+ };
28
+ async run() {
29
+ const { flags } = await this.parse(Plan);
30
+ const connection = flags['target-org'].getConnection(flags['api-version']);
31
+ const orgClient = new ConnectionOrgClient(connection);
32
+ const service = new PlanService(orgClient, flags.file, { mode: flags.mode });
33
+ const result = await service.run();
34
+ for (const line of formatFindings(result.findings)) {
35
+ this.log(line);
36
+ }
37
+ const summary = {
38
+ status: result.status,
39
+ toAdd: result.diff.toAdd.length,
40
+ toRemove: result.diff.toRemove.length,
41
+ unchanged: result.diff.unchanged.length,
42
+ drift: result.drift.adds + result.drift.removes,
43
+ };
44
+ if (result.status === 'invalid') {
45
+ process.exitCode = 1;
46
+ if (!this.jsonEnabled())
47
+ this.error(messages.getMessage('error.invalid'), { exit: 1 });
48
+ return summary;
49
+ }
50
+ this.log('');
51
+ for (const line of formatDiff(result.diff)) {
52
+ this.log(line);
53
+ }
54
+ this.log('');
55
+ this.reportDrift(result.drift, flags.mode);
56
+ this.log(messages.getMessage('summary.counts', [
57
+ String(summary.toAdd),
58
+ String(summary.toRemove),
59
+ String(summary.unchanged),
60
+ ]));
61
+ const pending = summary.toAdd + summary.toRemove;
62
+ if (pending > 0) {
63
+ this.log(messages.getMessage('summary.next', [flags.mode]));
64
+ }
65
+ return summary;
66
+ }
67
+ reportDrift(drift, mode) {
68
+ if (drift.adds > 0)
69
+ this.log(messages.getMessage('drift.note', [String(drift.adds), mode]));
70
+ if (drift.removes > 0)
71
+ this.log(messages.getMessage('drift.note', [String(drift.removes), mode]));
72
+ }
73
+ }
74
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/commands/ps/plan.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { SfCommand } from '@salesforce/sf-plugins-core';
2
- import { Finding } from '../../core/model.js';
2
+ import { Finding } from '../../core/finding.js';
3
3
  export type PsValidateResult = {
4
4
  files: number;
5
5
  users: number;
@@ -2,7 +2,7 @@ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
2
2
  import { Messages } from '@salesforce/core';
3
3
  import { ConnectionOrgClient } from '../../adapters/connection-org-client.js';
4
4
  import { ValidateService } from '../../services/validate.js';
5
- import { formatFindings } from '../../core/report.js';
5
+ import { formatFindings } from '../../core/finding.js';
6
6
  Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
7
  const messages = Messages.loadMessages('sf-plugin-permission-sets', 'ps.validate');
8
8
  export default class Validate extends SfCommand {
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/ps/validate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/ps/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { ActualAssignment, DesiredAssignment, Diff } from './model.js';
2
+ /**
3
+ * Compare the desired assignments against the org's current memberships of the
4
+ * managed targets. `actual` must hold only assignments for targets that appear
5
+ * in `desired` (the managed set), so any actual row not in `desired` is an
6
+ * undeclared assignment eligible for removal.
7
+ */
8
+ export declare function diffAssignments(desired: DesiredAssignment[], actual: ActualAssignment[]): Diff;
@@ -0,0 +1,35 @@
1
+ /** Case-insensitive key for an (assignee, kind, target) tuple, matching how the org compares them. */
2
+ function assignmentKey(assignee, kind, target) {
3
+ return `${assignee.toLowerCase()} ${kind} ${target.toLowerCase()}`;
4
+ }
5
+ /**
6
+ * Compare the desired assignments against the org's current memberships of the
7
+ * managed targets. `actual` must hold only assignments for targets that appear
8
+ * in `desired` (the managed set), so any actual row not in `desired` is an
9
+ * undeclared assignment eligible for removal.
10
+ */
11
+ export function diffAssignments(desired, actual) {
12
+ const actualByKey = new Map();
13
+ for (const assignment of actual) {
14
+ actualByKey.set(assignmentKey(assignment.assignee, assignment.kind, assignment.target), assignment);
15
+ }
16
+ const desiredKeys = new Set();
17
+ const toAdd = [];
18
+ const unchanged = [];
19
+ for (const assignment of desired) {
20
+ const key = assignmentKey(assignment.assignee, assignment.kind, assignment.target);
21
+ if (desiredKeys.has(key))
22
+ continue;
23
+ desiredKeys.add(key);
24
+ const existing = actualByKey.get(key);
25
+ if (existing) {
26
+ unchanged.push(existing);
27
+ }
28
+ else {
29
+ toAdd.push(assignment);
30
+ }
31
+ }
32
+ const toRemove = actual.filter((assignment) => !desiredKeys.has(assignmentKey(assignment.assignee, assignment.kind, assignment.target)));
33
+ return { toAdd, toRemove, unchanged };
34
+ }
35
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/core/diff.ts"],"names":[],"mappings":"AAEA,sGAAsG;AACtG,SAAS,aAAa,CAAC,QAAgB,EAAE,IAAU,EAAE,MAAc;IAC/D,OAAO,GAAG,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;AACvE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAA4B,EAAE,MAA0B;IACpF,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4B,CAAC;IACxD,KAAK,MAAM,UAAU,IAAI,MAAM,EAAE,CAAC;QAC9B,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IACtC,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,MAAM,SAAS,GAAuB,EAAE,CAAC;IAEzC,KAAK,MAAM,UAAU,IAAI,OAAO,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QACnF,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACnC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAErB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,QAAQ,EAAE,CAAC;YACX,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACJ,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAC1B,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAC3G,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,27 @@
1
+ export type FindingLevel = 'error' | 'warning';
2
+ /** The closed vocabulary of finding codes. Adding one here is required to emit it. */
3
+ export type FindingCode = 'YAML' | 'EMPTY_FILE' | 'SCHEMA' | 'EMPTY_LIST' | 'DUP_TARGET' | 'EMPTY_USER' | 'NO_FILES' | 'USER_NOT_FOUND' | 'USER_INACTIVE' | 'TARGET_NOT_FOUND' | 'TARGET_AMBIGUOUS';
4
+ export type Finding = {
5
+ level: FindingLevel;
6
+ code: FindingCode;
7
+ message: string;
8
+ file?: string;
9
+ line?: number;
10
+ };
11
+ /** Where a finding was raised. Both optional: org-side findings have no file or line. */
12
+ type Where = {
13
+ file?: string;
14
+ line?: number;
15
+ };
16
+ /** Construct an error-level finding. */
17
+ export declare function error(code: FindingCode, message: string, where?: Where): Finding;
18
+ /** Construct a warning-level finding. */
19
+ export declare function warning(code: FindingCode, message: string, where?: Where): Finding;
20
+ /** Render findings as human-readable lines. Shared by check, validate, and apply. */
21
+ export declare function formatFindings(findings: Finding[]): string[];
22
+ /** Count findings by level. */
23
+ export declare function countFindings(findings: Finding[]): {
24
+ errors: number;
25
+ warnings: number;
26
+ };
27
+ export {};
@@ -0,0 +1,22 @@
1
+ /** Construct an error-level finding. */
2
+ export function error(code, message, where = {}) {
3
+ return { level: 'error', code, message, ...where };
4
+ }
5
+ /** Construct a warning-level finding. */
6
+ export function warning(code, message, where = {}) {
7
+ return { level: 'warning', code, message, ...where };
8
+ }
9
+ /** Render findings as human-readable lines. Shared by check, validate, and apply. */
10
+ export function formatFindings(findings) {
11
+ return findings.map((finding) => {
12
+ const where = finding.file ? `${finding.file}${finding.line ? `:${finding.line}` : ''} ` : '';
13
+ return `${finding.level}: ${where}${finding.message}`;
14
+ });
15
+ }
16
+ /** Count findings by level. */
17
+ export function countFindings(findings) {
18
+ const errors = findings.filter((finding) => finding.level === 'error');
19
+ const warnings = findings.filter((finding) => finding.level === 'warning');
20
+ return { errors: errors.length, warnings: warnings.length };
21
+ }
22
+ //# sourceMappingURL=finding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding.js","sourceRoot":"","sources":["../../src/core/finding.ts"],"names":[],"mappings":"AA2BA,wCAAwC;AACxC,MAAM,UAAU,KAAK,CAAC,IAAiB,EAAE,OAAe,EAAE,QAAe,EAAE;IACvE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;AACvD,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,OAAO,CAAC,IAAiB,EAAE,OAAe,EAAE,QAAe,EAAE;IACzE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;AACzD,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,cAAc,CAAC,QAAmB;IAC9C,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,OAAO,GAAG,OAAO,CAAC,KAAK,KAAK,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;AACP,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,aAAa,CAAC,QAAmB;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACvE,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAE3E,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AAChE,CAAC"}
package/lib/core/load.js CHANGED
@@ -3,6 +3,7 @@ import { globby } from 'globby';
3
3
  import { parseFile } from './parse.js';
4
4
  import { validateFile } from './schema.js';
5
5
  import { normalize } from './normalize.js';
6
+ import { error } from './finding.js';
6
7
  /** Process one file's text through parse, validate, and normalize. Pure, no disk. */
7
8
  function checkContent(text, file) {
8
9
  const parsed = parseFile(text, file);
@@ -26,7 +27,7 @@ export async function loadFiles(patterns) {
26
27
  return {
27
28
  files,
28
29
  assignments: [],
29
- findings: [{ level: 'error', code: 'NO_FILES', message: `no files matched: ${patterns.join(', ')}` }],
30
+ findings: [error('NO_FILES', `no files matched: ${patterns.join(', ')}`)],
30
31
  };
31
32
  }
32
33
  const findings = [];
@@ -1 +1 @@
1
- {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/core/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,qFAAqF;AACrF,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY;IAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtF,CAAC;IAED,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,OAAO;QACH,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC;KAChF,CAAC;AACN,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAkB;IAC9C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO;YACH,KAAK;YACL,WAAW,EAAE,EAAE;YACf,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;SACxG,CAAC;IACN,CAAC;IAED,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAwB,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,4CAA4C;QAC5C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/B,SAAS,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,WAAW,GAAwB,EAAE,CAAC;IAE5C,KAAK,MAAM,UAAU,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,GAAG,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACnF,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,SAAS;QAClC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpB,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AAC5C,CAAC"}
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/core/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAW,KAAK,EAAE,MAAM,cAAc,CAAC;AAE9C,qFAAqF;AACrF,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY;IAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;IACtF,CAAC;IAED,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,OAAO;QACH,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC;KAChF,CAAC;AACN,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAkB;IAC9C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO;YACH,KAAK;YACL,WAAW,EAAE,EAAE;YACf,QAAQ,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,qBAAqB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SAC5E,CAAC;IACN,CAAC;IAED,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAwB,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,4CAA4C;QAC5C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/B,SAAS,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,WAAW,GAAwB,EAAE,CAAC;IAE5C,KAAK,MAAM,UAAU,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,GAAG,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACnF,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,SAAS;QAClC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpB,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AAC5C,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { Finding } from './finding.js';
1
2
  export type Kind = 'permissionSet' | 'permissionSetGroup' | 'permissionSetLicense';
2
3
  export type DesiredAssignment = {
3
4
  assignee: string;
@@ -6,16 +7,46 @@ export type DesiredAssignment = {
6
7
  };
7
8
  /** A user as it exists in the org, in domain terms (no SObject field names). */
8
9
  export type OrgUser = {
10
+ id: string;
9
11
  username: string;
10
12
  isActive: boolean;
11
13
  };
12
- export type FindingLevel = 'error' | 'warning';
13
- export type Finding = {
14
- level: FindingLevel;
15
- code: string;
16
- message: string;
17
- file?: string;
18
- line?: number;
14
+ /** A target (permission set, group, or license) as it exists in the org. */
15
+ export type OrgTarget = {
16
+ id: string;
17
+ name: string;
18
+ };
19
+ /** An assignment that currently exists in the org, carrying its record id for deletion. */
20
+ export type ActualAssignment = {
21
+ recordId: string;
22
+ assignee: string;
23
+ kind: Kind;
24
+ target: string;
25
+ };
26
+ /** A resolved managed target: its kind and the org id it resolved to. */
27
+ export type TargetRef = {
28
+ kind: Kind;
29
+ id: string;
30
+ };
31
+ /** A desired assignment resolved to the ids needed to insert it. */
32
+ export type ResolvedAddition = DesiredAssignment & {
33
+ assigneeId: string;
34
+ targetId: string;
35
+ };
36
+ /** The change set between the desired model and the org's current state. */
37
+ export type Diff = {
38
+ toAdd: DesiredAssignment[];
39
+ toRemove: ActualAssignment[];
40
+ unchanged: ActualAssignment[];
41
+ };
42
+ /** The per-record result of one add or remove, for partial-success reporting. */
43
+ export type AssignmentOutcome = {
44
+ assignee: string;
45
+ kind: Kind;
46
+ target: string;
47
+ operation: 'add' | 'remove';
48
+ success: boolean;
49
+ message?: string;
19
50
  };
20
51
  export type LoadResult = {
21
52
  files: string[];
@@ -1,5 +1,9 @@
1
1
  import { FileShape } from './schema.js';
2
- import { DesiredAssignment, Finding } from './model.js';
2
+ import { DesiredAssignment, Kind } from './model.js';
3
+ import { Finding } from './finding.js';
4
+ export type ScopeKey = 'permissionSets' | 'permissionSetGroups' | 'permissionSetLicenses';
5
+ /** The (kind, file scope key) pairing, in canonical order. Shared with serialize. */
6
+ export declare const kindKeys: Array<[Kind, ScopeKey]>;
3
7
  /**
4
8
  * Turn a validated file into canonical (assignee, kind, target) tuples, and
5
9
  * emit the structural findings: duplicate targets, empty lists, empty users.
@@ -1,4 +1,6 @@
1
- const kindKeys = [
1
+ import { warning } from './finding.js';
2
+ /** The (kind, file scope key) pairing, in canonical order. Shared with serialize. */
3
+ export const kindKeys = [
2
4
  ['permissionSet', 'permissionSets'],
3
5
  ['permissionSetGroup', 'permissionSetGroups'],
4
6
  ['permissionSetLicense', 'permissionSetLicenses'],
@@ -17,19 +19,14 @@ export function normalize(data, file) {
17
19
  if (list === undefined)
18
20
  continue;
19
21
  if (list.length === 0) {
20
- findings.push({ level: 'warning', code: 'EMPTY_LIST', message: `${username}: ${key} is empty`, file });
22
+ findings.push(warning('EMPTY_LIST', `${username}: ${key} is empty`, { file }));
21
23
  continue;
22
24
  }
23
25
  scopeCount += 1;
24
26
  const seen = new Set();
25
27
  for (const target of list) {
26
28
  if (seen.has(target)) {
27
- findings.push({
28
- level: 'warning',
29
- code: 'DUP_TARGET',
30
- message: `${username}: ${target} is listed twice under ${key}`,
31
- file,
32
- });
29
+ findings.push(warning('DUP_TARGET', `${username}: ${target} is listed twice under ${key}`, { file }));
33
30
  continue;
34
31
  }
35
32
  seen.add(target);
@@ -37,7 +34,7 @@ export function normalize(data, file) {
37
34
  }
38
35
  }
39
36
  if (scopeCount === 0) {
40
- findings.push({ level: 'warning', code: 'EMPTY_USER', message: `${username}: no scopes declared`, file });
37
+ findings.push(warning('EMPTY_USER', `${username}: no scopes declared`, { file }));
41
38
  }
42
39
  }
43
40
  return { assignments, findings };
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/core/normalize.ts"],"names":[],"mappings":"AAKA,MAAM,QAAQ,GAA4B;IACtC,CAAC,eAAe,EAAE,gBAAgB,CAAC;IACnC,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;IAC7C,CAAC,sBAAsB,EAAE,uBAAuB,CAAC;CACpD,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAe,EAAE,IAAY;IACnD,MAAM,WAAW,GAAwB,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACxB,IAAI,IAAI,KAAK,SAAS;gBAAE,SAAS;YACjC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,QAAQ,KAAK,GAAG,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvG,SAAS;YACb,CAAC;YAED,UAAU,IAAI,CAAC,CAAC;YAChB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;YAC/B,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;gBACxB,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBACnB,QAAQ,CAAC,IAAI,CAAC;wBACV,KAAK,EAAE,SAAS;wBAChB,IAAI,EAAE,YAAY;wBAClB,OAAO,EAAE,GAAG,QAAQ,KAAK,MAAM,0BAA0B,GAAG,EAAE;wBAC9D,IAAI;qBACP,CAAC,CAAC;oBACH,SAAS;gBACb,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACjB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3D,CAAC;QACL,CAAC;QAED,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,QAAQ,sBAAsB,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9G,CAAC;IACL,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/core/normalize.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,OAAO,EAAE,MAAM,cAAc,CAAC;AAIhD,qFAAqF;AACrF,MAAM,CAAC,MAAM,QAAQ,GAA4B;IAC7C,CAAC,eAAe,EAAE,gBAAgB,CAAC;IACnC,CAAC,oBAAoB,EAAE,qBAAqB,CAAC;IAC7C,CAAC,sBAAsB,EAAE,uBAAuB,CAAC;CACpD,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAe,EAAE,IAAY;IACnD,MAAM,WAAW,GAAwB,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACxB,IAAI,IAAI,KAAK,SAAS;gBAAE,SAAS;YACjC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,QAAQ,KAAK,GAAG,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC/E,SAAS;YACb,CAAC;YAED,UAAU,IAAI,CAAC,CAAC;YAChB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;YAC/B,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;gBACxB,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBACnB,QAAQ,CAAC,IAAI,CACT,OAAO,CAAC,YAAY,EAAE,GAAG,QAAQ,KAAK,MAAM,0BAA0B,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CACzF,CAAC;oBACF,SAAS;gBACb,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACjB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3D,CAAC;QACL,CAAC;QAED,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,QAAQ,sBAAsB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACtF,CAAC;IACL,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACrC,CAAC"}
@@ -1,4 +1,4 @@
1
- import { Finding } from './model.js';
1
+ import { Finding } from './finding.js';
2
2
  /**
3
3
  * Read one file's text into a plain object. Reports invalid YAML and duplicate
4
4
  * keys (uniqueKeys), and treats an empty document as a warning.
package/lib/core/parse.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { parseDocument } from 'yaml';
2
+ import { error, warning } from './finding.js';
2
3
  /**
3
4
  * Read one file's text into a plain object. Reports invalid YAML and duplicate
4
5
  * keys (uniqueKeys), and treats an empty document as a warning.
@@ -7,18 +8,12 @@ export function parseFile(text, file) {
7
8
  const doc = parseDocument(text, { uniqueKeys: true });
8
9
  if (doc.errors.length > 0) {
9
10
  return {
10
- findings: doc.errors.map((err) => ({
11
- level: 'error',
12
- code: 'YAML',
13
- message: err.message,
14
- file,
15
- line: err.linePos?.[0]?.line,
16
- })),
11
+ findings: doc.errors.map((err) => error('YAML', err.message, { file, line: err.linePos?.[0]?.line })),
17
12
  };
18
13
  }
19
14
  const data = doc.toJS();
20
15
  if (data === null || data === undefined) {
21
- return { findings: [{ level: 'warning', code: 'EMPTY_FILE', message: 'file is empty', file }] };
16
+ return { findings: [warning('EMPTY_FILE', 'file is empty', { file })] };
22
17
  }
23
18
  return { data, findings: [] };
24
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/core/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAGrC;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAY;IAChD,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtD,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO;YACH,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC/B,KAAK,EAAE,OAAO;gBACd,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,IAAI;gBACJ,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI;aAC/B,CAAC,CAAC;SACN,CAAC;IACN,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAa,CAAC;IACnC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACpG,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/core/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAW,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvD;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAY;IAChD,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtD,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO;YACH,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;SACxG,CAAC;IACN,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAa,CAAC;IACnC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IAC5E,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAClC,CAAC"}
@@ -1,8 +1,6 @@
1
- import { Finding } from './model.js';
2
- /** Render findings as human-readable lines. Shared by check, validate, and plan. */
3
- export declare function formatFindings(findings: Finding[]): string[];
4
- /** Count findings by level. */
5
- export declare function countFindings(findings: Finding[]): {
6
- errors: number;
7
- warnings: number;
8
- };
1
+ import { Diff } from './model.js';
2
+ /**
3
+ * Render a diff as a plan, grouped by kind then target, with `+` adds, `-` removes,
4
+ * and `=` unchanged. Shared by plan and apply.
5
+ */
6
+ export declare function formatDiff(diff: Diff): string[];
@@ -1,14 +1,48 @@
1
- /** Render findings as human-readable lines. Shared by check, validate, and plan. */
2
- export function formatFindings(findings) {
3
- return findings.map((finding) => {
4
- const where = finding.file ? `${finding.file}${finding.line ? `:${finding.line}` : ''} ` : '';
5
- return `${finding.level}: ${where}${finding.message}`;
6
- });
1
+ import { kindKeys } from './normalize.js';
2
+ function bucketFor(byKind, kind, target) {
3
+ let byTarget = byKind.get(kind);
4
+ if (!byTarget) {
5
+ byTarget = new Map();
6
+ byKind.set(kind, byTarget);
7
+ }
8
+ let bucket = byTarget.get(target);
9
+ if (!bucket) {
10
+ bucket = { adds: new Set(), removes: new Set(), unchanged: new Set() };
11
+ byTarget.set(target, bucket);
12
+ }
13
+ return bucket;
7
14
  }
8
- /** Count findings by level. */
9
- export function countFindings(findings) {
10
- const errors = findings.filter((finding) => finding.level === 'error');
11
- const warnings = findings.filter((finding) => finding.level === 'warning');
12
- return { errors: errors.length, warnings: warnings.length };
15
+ /**
16
+ * Render a diff as a plan, grouped by kind then target, with `+` adds, `-` removes,
17
+ * and `=` unchanged. Shared by plan and apply.
18
+ */
19
+ export function formatDiff(diff) {
20
+ const byKind = new Map();
21
+ for (const assignment of diff.toAdd) {
22
+ bucketFor(byKind, assignment.kind, assignment.target).adds.add(assignment.assignee);
23
+ }
24
+ for (const assignment of diff.toRemove) {
25
+ bucketFor(byKind, assignment.kind, assignment.target).removes.add(assignment.assignee);
26
+ }
27
+ for (const assignment of diff.unchanged) {
28
+ bucketFor(byKind, assignment.kind, assignment.target).unchanged.add(assignment.assignee);
29
+ }
30
+ const lines = [];
31
+ for (const [kind, scopeKey] of kindKeys) {
32
+ const byTarget = byKind.get(kind);
33
+ if (!byTarget)
34
+ continue;
35
+ lines.push(`${scopeKey}:`);
36
+ for (const [target, bucket] of [...byTarget].sort((left, right) => left[0].localeCompare(right[0]))) {
37
+ lines.push(` ${target}`);
38
+ for (const assignee of [...bucket.adds].sort())
39
+ lines.push(` + ${assignee}`);
40
+ for (const assignee of [...bucket.removes].sort())
41
+ lines.push(` - ${assignee}`);
42
+ for (const assignee of [...bucket.unchanged].sort())
43
+ lines.push(` = ${assignee}`);
44
+ }
45
+ }
46
+ return lines;
13
47
  }
14
48
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"AAEA,oFAAoF;AACpF,MAAM,UAAU,cAAc,CAAC,QAAmB;IAC9C,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,OAAO,GAAG,OAAO,CAAC,KAAK,KAAK,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;AACP,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,aAAa,CAAC,QAAmB;IAC7C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACvE,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IAE3E,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import { DesiredAssignment, Finding, Kind, OrgUser } from './model.js';
1
+ import { DesiredAssignment, Kind, OrgTarget, OrgUser } from './model.js';
2
+ import { Finding } from './finding.js';
2
3
  export declare const kinds: Kind[];
3
4
  /** The distinct usernames assigned across all assignments. */
4
5
  export declare function distinctAssignees(assignments: DesiredAssignment[]): string[];
@@ -12,3 +13,7 @@ export declare function evaluateUsers(declared: string[], found: OrgUser[]): Fin
12
13
  * case-insensitive, mirroring how the org compares them.
13
14
  */
14
15
  export declare function evaluateTargets(kind: Kind, declared: string[], found: string[]): Finding[];
16
+ /** Index active users by lowercased username to their org id, for building assignments. */
17
+ export declare function indexUsersById(found: OrgUser[]): Map<string, string>;
18
+ /** Index targets by lowercased name to their org id, skipping names that resolve ambiguously. */
19
+ export declare function indexTargetsById(found: OrgTarget[]): Map<string, string>;
@@ -1,3 +1,4 @@
1
+ import { error } from './finding.js';
1
2
  /** Human label per kind, used in findings. Domain wording, not SObject names. */
2
3
  const kindLabels = {
3
4
  permissionSet: 'permission set',
@@ -26,10 +27,10 @@ export function evaluateUsers(declared, found) {
26
27
  for (const username of declared) {
27
28
  const user = byName.get(username.toLowerCase());
28
29
  if (!user) {
29
- findings.push({ level: 'error', code: 'USER_NOT_FOUND', message: `${username}: user not found in org` });
30
+ findings.push(error('USER_NOT_FOUND', `${username}: user not found in org`));
30
31
  }
31
32
  else if (!user.isActive) {
32
- findings.push({ level: 'error', code: 'USER_INACTIVE', message: `${username}: user is inactive` });
33
+ findings.push(error('USER_INACTIVE', `${username}: user is inactive`));
33
34
  }
34
35
  }
35
36
  return findings;
@@ -50,20 +51,38 @@ export function evaluateTargets(kind, declared, found) {
50
51
  for (const target of declared) {
51
52
  const count = counts.get(target.toLowerCase()) ?? 0;
52
53
  if (count === 0) {
53
- findings.push({
54
- level: 'error',
55
- code: 'TARGET_NOT_FOUND',
56
- message: `${target}: ${label} not found in org`,
57
- });
54
+ findings.push(error('TARGET_NOT_FOUND', `${target}: ${label} not found in org`));
58
55
  }
59
56
  else if (count > 1) {
60
- findings.push({
61
- level: 'error',
62
- code: 'TARGET_AMBIGUOUS',
63
- message: `${target}: ${label} is not unique in org`,
64
- });
57
+ findings.push(error('TARGET_AMBIGUOUS', `${target}: ${label} is not unique in org`));
65
58
  }
66
59
  }
67
60
  return findings;
68
61
  }
62
+ /** Index active users by lowercased username to their org id, for building assignments. */
63
+ export function indexUsersById(found) {
64
+ const byName = new Map();
65
+ for (const user of found) {
66
+ if (user.isActive) {
67
+ byName.set(user.username.toLowerCase(), user.id);
68
+ }
69
+ }
70
+ return byName;
71
+ }
72
+ /** Index targets by lowercased name to their org id, skipping names that resolve ambiguously. */
73
+ export function indexTargetsById(found) {
74
+ const counts = new Map();
75
+ for (const target of found) {
76
+ const key = target.name.toLowerCase();
77
+ counts.set(key, (counts.get(key) ?? 0) + 1);
78
+ }
79
+ const byName = new Map();
80
+ for (const target of found) {
81
+ const key = target.name.toLowerCase();
82
+ if (counts.get(key) === 1) {
83
+ byName.set(key, target.id);
84
+ }
85
+ }
86
+ return byName;
87
+ }
69
88
  //# sourceMappingURL=resolve.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { Finding } from './model.js';
2
+ import { Finding } from './finding.js';
3
3
  export declare const userEntrySchema: z.ZodObject<{
4
4
  permissionSets: z.ZodOptional<z.ZodArray<z.ZodString>>;
5
5
  permissionSetGroups: z.ZodOptional<z.ZodArray<z.ZodString>>;