sf-plugin-permission-sets 0.0.0-dev.4 → 0.0.0-dev.42
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/README.md +157 -93
- package/lib/adapters/connection-org-client.d.ts +17 -0
- package/lib/adapters/connection-org-client.d.ts.map +1 -0
- package/lib/adapters/connection-org-client.js +248 -0
- package/lib/adapters/connection-org-client.js.map +1 -0
- package/lib/adapters/index.d.ts +2 -0
- package/lib/adapters/index.d.ts.map +1 -0
- package/lib/adapters/index.js +2 -0
- package/lib/adapters/index.js.map +1 -0
- package/lib/commands/ps/apply.d.ts +39 -0
- package/lib/commands/ps/apply.d.ts.map +1 -0
- package/lib/commands/ps/apply.js +173 -0
- package/lib/commands/ps/apply.js.map +1 -0
- package/lib/commands/ps/check.d.ts +21 -0
- package/lib/commands/ps/check.d.ts.map +1 -0
- package/lib/commands/ps/check.js +55 -0
- package/lib/commands/ps/check.js.map +1 -0
- package/lib/commands/ps/export.d.ts +18 -0
- package/lib/commands/ps/export.d.ts.map +1 -0
- package/lib/commands/ps/export.js +35 -0
- package/lib/commands/ps/export.js.map +1 -0
- package/lib/commands/ps/plan.d.ts +61 -0
- package/lib/commands/ps/plan.d.ts.map +1 -0
- package/lib/commands/ps/plan.js +212 -0
- package/lib/commands/ps/plan.js.map +1 -0
- package/lib/commands/ps/validate.d.ts +21 -0
- package/lib/commands/ps/validate.d.ts.map +1 -0
- package/lib/commands/ps/validate.js +56 -0
- package/lib/commands/ps/validate.js.map +1 -0
- package/lib/core/diff.d.ts +10 -0
- package/lib/core/diff.d.ts.map +1 -0
- package/lib/core/diff.js +54 -0
- package/lib/core/diff.js.map +1 -0
- package/lib/core/finding.d.ts +41 -0
- package/lib/core/finding.d.ts.map +1 -0
- package/lib/core/finding.js +68 -0
- package/lib/core/finding.js.map +1 -0
- package/lib/core/index.d.ts +8 -0
- package/lib/core/index.d.ts.map +1 -0
- package/lib/core/index.js +7 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/load.d.ts +4 -0
- package/lib/core/load.d.ts.map +1 -0
- package/lib/core/load.js +60 -0
- package/lib/core/load.js.map +1 -0
- package/lib/core/model.d.ts +73 -0
- package/lib/core/model.d.ts.map +1 -0
- package/lib/core/model.js +2 -0
- package/lib/core/model.js.map +1 -0
- package/lib/core/normalize.d.ts +15 -0
- package/lib/core/normalize.d.ts.map +1 -0
- package/lib/core/normalize.js +62 -0
- package/lib/core/normalize.js.map +1 -0
- package/lib/core/parse.d.ts +10 -0
- package/lib/core/parse.d.ts.map +1 -0
- package/lib/core/parse.js +20 -0
- package/lib/core/parse.js.map +1 -0
- package/lib/core/report.d.ts +15 -0
- package/lib/core/report.d.ts.map +1 -0
- package/lib/core/report.js +114 -0
- package/lib/core/report.js.map +1 -0
- package/lib/core/resolve.d.ts +20 -0
- package/lib/core/resolve.d.ts.map +1 -0
- package/lib/core/resolve.js +88 -0
- package/lib/core/resolve.js.map +1 -0
- package/lib/core/schema.d.ts +23 -0
- package/lib/core/schema.d.ts.map +1 -0
- package/lib/core/schema.js +35 -0
- package/lib/core/schema.js.map +1 -0
- package/lib/core/serialize.d.ts +9 -0
- package/lib/core/serialize.d.ts.map +1 -0
- package/lib/core/serialize.js +34 -0
- package/lib/core/serialize.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/services/adapters/index.d.ts +2 -0
- package/lib/services/adapters/index.d.ts.map +1 -0
- package/lib/services/adapters/index.js +2 -0
- package/lib/services/adapters/index.js.map +1 -0
- package/lib/services/adapters/org-client.d.ts +22 -0
- package/lib/services/adapters/org-client.d.ts.map +1 -0
- package/lib/services/adapters/org-client.js +2 -0
- package/lib/services/adapters/org-client.js.map +1 -0
- package/lib/services/apply.d.ts +39 -0
- package/lib/services/apply.d.ts.map +1 -0
- package/lib/services/apply.js +102 -0
- package/lib/services/apply.js.map +1 -0
- package/lib/services/check.d.ts +14 -0
- package/lib/services/check.d.ts.map +1 -0
- package/lib/services/check.js +18 -0
- package/lib/services/check.js.map +1 -0
- package/lib/services/export.d.ts +13 -0
- package/lib/services/export.d.ts.map +1 -0
- package/lib/services/export.js +23 -0
- package/lib/services/export.js.map +1 -0
- package/lib/services/index.d.ts +6 -0
- package/lib/services/index.d.ts.map +1 -0
- package/lib/services/index.js +6 -0
- package/lib/services/index.js.map +1 -0
- package/lib/services/plan.d.ts +29 -0
- package/lib/services/plan.d.ts.map +1 -0
- package/lib/services/plan.js +45 -0
- package/lib/services/plan.js.map +1 -0
- package/lib/services/resolution.d.ts +15 -0
- package/lib/services/resolution.d.ts.map +1 -0
- package/lib/services/resolution.js +37 -0
- package/lib/services/resolution.js.map +1 -0
- package/lib/services/validate.d.ts +19 -0
- package/lib/services/validate.d.ts.map +1 -0
- package/lib/services/validate.js +42 -0
- package/lib/services/validate.js.map +1 -0
- package/messages/ps.apply.md +85 -0
- package/messages/ps.check.md +33 -0
- package/messages/ps.export.md +25 -0
- package/messages/ps.plan.md +85 -0
- package/messages/ps.validate.md +29 -0
- package/package.json +112 -181
- package/lib/commands/ps/info.d.ts +0 -11
- package/lib/commands/ps/info.js +0 -17
- package/lib/commands/ps/info.js.map +0 -1
- package/messages/ps.info.md +0 -17
- package/oclif.lock +0 -7781
- package/oclif.manifest.json +0 -51
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Finding } from './finding.js';
|
|
2
|
+
export type Kind = 'permissionSet' | 'permissionSetGroup' | 'permissionSetLicense';
|
|
3
|
+
/** Which half of the reconcile a run acts on. Shared by plan, apply, and the report. */
|
|
4
|
+
export type ReconcileMode = 'additive' | 'destructive' | 'sync';
|
|
5
|
+
export type DesiredAssignment = {
|
|
6
|
+
assignee: string;
|
|
7
|
+
kind: Kind;
|
|
8
|
+
target: string;
|
|
9
|
+
/** ISO 8601 datetime the grant should expire, if any. Only permission sets and groups support it. */
|
|
10
|
+
expiration?: string;
|
|
11
|
+
};
|
|
12
|
+
/** A user as it exists in the org, in domain terms (no SObject field names). */
|
|
13
|
+
export type OrgUser = {
|
|
14
|
+
id: string;
|
|
15
|
+
username: string;
|
|
16
|
+
isActive: boolean;
|
|
17
|
+
};
|
|
18
|
+
/** A target (permission set, group, or license) as it exists in the org. */
|
|
19
|
+
export type OrgTarget = {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
};
|
|
23
|
+
/** An assignment that currently exists in the org, carrying its record id for deletion. */
|
|
24
|
+
export type ActualAssignment = {
|
|
25
|
+
recordId: string;
|
|
26
|
+
assignee: string;
|
|
27
|
+
kind: Kind;
|
|
28
|
+
target: string;
|
|
29
|
+
/** The expiration the org has on record, if any. */
|
|
30
|
+
expiration?: string;
|
|
31
|
+
};
|
|
32
|
+
/** An existing assignment whose expiration should change. `expiration` undefined clears it. */
|
|
33
|
+
export type AssignmentUpdate = {
|
|
34
|
+
recordId: string;
|
|
35
|
+
assignee: string;
|
|
36
|
+
kind: Kind;
|
|
37
|
+
target: string;
|
|
38
|
+
expiration?: string;
|
|
39
|
+
/** The expiration the org has now, before the update. Undefined means it had none. */
|
|
40
|
+
previousExpiration?: string;
|
|
41
|
+
};
|
|
42
|
+
/** A resolved managed target: its kind and the org id it resolved to. */
|
|
43
|
+
export type TargetRef = {
|
|
44
|
+
kind: Kind;
|
|
45
|
+
id: string;
|
|
46
|
+
};
|
|
47
|
+
/** A desired assignment resolved to the ids needed to insert it. */
|
|
48
|
+
export type ResolvedAddition = DesiredAssignment & {
|
|
49
|
+
assigneeId: string;
|
|
50
|
+
targetId: string;
|
|
51
|
+
};
|
|
52
|
+
/** The change set between the desired model and the org's current state. */
|
|
53
|
+
export type Diff = {
|
|
54
|
+
toAdd: DesiredAssignment[];
|
|
55
|
+
toUpdate: AssignmentUpdate[];
|
|
56
|
+
toRemove: ActualAssignment[];
|
|
57
|
+
unchanged: ActualAssignment[];
|
|
58
|
+
};
|
|
59
|
+
/** The per-record result of one add or remove, for partial-success reporting. */
|
|
60
|
+
export type AssignmentOutcome = {
|
|
61
|
+
assignee: string;
|
|
62
|
+
kind: Kind;
|
|
63
|
+
target: string;
|
|
64
|
+
operation: 'add' | 'update' | 'remove';
|
|
65
|
+
success: boolean;
|
|
66
|
+
message?: string;
|
|
67
|
+
};
|
|
68
|
+
export type LoadResult = {
|
|
69
|
+
files: string[];
|
|
70
|
+
assignments: DesiredAssignment[];
|
|
71
|
+
findings: Finding[];
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/core/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,MAAM,IAAI,GAAG,eAAe,GAAG,oBAAoB,GAAG,sBAAsB,CAAC;AAEnF,wFAAwF;AACxF,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,aAAa,GAAG,MAAM,CAAC;AAEhE,MAAM,MAAM,iBAAiB,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,qGAAqG;IACrG,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,OAAO,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,2FAA2F;AAC3F,MAAM,MAAM,gBAAgB,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,+FAA+F;AAC/F,MAAM,MAAM,gBAAgB,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sFAAsF;IACtF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,GAAG;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,IAAI,GAAG;IACf,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,SAAS,EAAE,gBAAgB,EAAE,CAAC;CACjC,CAAC;AAEF,iFAAiF;AACjF,MAAM,MAAM,iBAAiB,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,QAAQ,EAAE,OAAO,EAAE,CAAC;CACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/core/model.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FileShape } from './schema.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]>;
|
|
7
|
+
/**
|
|
8
|
+
* Turn a validated file into canonical (assignee, kind, target) tuples, and
|
|
9
|
+
* emit the structural findings: duplicate targets, empty lists, empty users.
|
|
10
|
+
*/
|
|
11
|
+
export declare function normalize(data: FileShape, file: string): {
|
|
12
|
+
assignments: DesiredAssignment[];
|
|
13
|
+
findings: Finding[];
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/core/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,OAAO,EAAwD,MAAM,cAAc,CAAC;AAE7F,MAAM,MAAM,QAAQ,GAAG,gBAAgB,GAAG,qBAAqB,GAAG,uBAAuB,CAAC;AAE1F,qFAAqF;AACrF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAI5C,CAAC;AA8DF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAWlH"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { emptyListWarning, dupTargetWarning, emptyUserWarning } from './finding.js';
|
|
2
|
+
/** The (kind, file scope key) pairing, in canonical order. Shared with serialize. */
|
|
3
|
+
export const kindKeys = [
|
|
4
|
+
['permissionSet', 'permissionSets'],
|
|
5
|
+
['permissionSetGroup', 'permissionSetGroups'],
|
|
6
|
+
['permissionSetLicense', 'permissionSetLicenses'],
|
|
7
|
+
];
|
|
8
|
+
function normalizeScope(username, kind, key, list, file) {
|
|
9
|
+
const items = list.map((item) => ({
|
|
10
|
+
target: typeof item === 'string' ? item : item.name,
|
|
11
|
+
expiration: typeof item === 'string' ? undefined : item.expiration,
|
|
12
|
+
}));
|
|
13
|
+
const assignments = [];
|
|
14
|
+
const findings = [];
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
for (const { target, expiration } of items) {
|
|
17
|
+
if (seen.has(target)) {
|
|
18
|
+
findings.push(dupTargetWarning(username, target, key, file));
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
seen.add(target);
|
|
22
|
+
assignments.push({ assignee: username, kind, target, ...(expiration ? { expiration } : {}) });
|
|
23
|
+
}
|
|
24
|
+
return { assignments, findings };
|
|
25
|
+
}
|
|
26
|
+
function normalizeUser(username, entry, file) {
|
|
27
|
+
const assignments = [];
|
|
28
|
+
const findings = [];
|
|
29
|
+
let scopeCount = 0;
|
|
30
|
+
for (const [kind, key] of kindKeys) {
|
|
31
|
+
const list = entry[key];
|
|
32
|
+
if (!list)
|
|
33
|
+
continue;
|
|
34
|
+
if (list.length === 0) {
|
|
35
|
+
findings.push(emptyListWarning(username, key, file));
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
scopeCount += 1;
|
|
39
|
+
const scope = normalizeScope(username, kind, key, list, file);
|
|
40
|
+
assignments.push(...scope.assignments);
|
|
41
|
+
findings.push(...scope.findings);
|
|
42
|
+
}
|
|
43
|
+
if (scopeCount === 0) {
|
|
44
|
+
findings.push(emptyUserWarning(username, file));
|
|
45
|
+
}
|
|
46
|
+
return { assignments, findings };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Turn a validated file into canonical (assignee, kind, target) tuples, and
|
|
50
|
+
* emit the structural findings: duplicate targets, empty lists, empty users.
|
|
51
|
+
*/
|
|
52
|
+
export function normalize(data, file) {
|
|
53
|
+
const assignments = [];
|
|
54
|
+
const findings = [];
|
|
55
|
+
for (const [username, entry] of Object.entries(data.users)) {
|
|
56
|
+
const user = normalizeUser(username, entry, file);
|
|
57
|
+
assignments.push(...user.assignments);
|
|
58
|
+
findings.push(...user.findings);
|
|
59
|
+
}
|
|
60
|
+
return { assignments, findings };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/core/normalize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Finding } from './finding.js';
|
|
2
|
+
/**
|
|
3
|
+
* Read one file's text into a plain object. Reports invalid YAML and duplicate
|
|
4
|
+
* keys (uniqueKeys), and treats an empty document as a warning.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseFile(text: string, file: string): {
|
|
7
|
+
data?: unknown;
|
|
8
|
+
findings: Finding[];
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/core/parse.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAA+B,MAAM,cAAc,CAAC;AAEpE;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAe7F"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { parseDocument } from 'yaml';
|
|
2
|
+
import { yamlError, emptyFileWarning } from './finding.js';
|
|
3
|
+
/**
|
|
4
|
+
* Read one file's text into a plain object. Reports invalid YAML and duplicate
|
|
5
|
+
* keys (uniqueKeys), and treats an empty document as a warning.
|
|
6
|
+
*/
|
|
7
|
+
export function parseFile(text, file) {
|
|
8
|
+
const doc = parseDocument(text, { uniqueKeys: true });
|
|
9
|
+
if (doc.errors.length > 0) {
|
|
10
|
+
return {
|
|
11
|
+
findings: doc.errors.map((err) => yamlError(err.message, file, err.linePos?.[0]?.line)),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const data = doc.toJS();
|
|
15
|
+
if (data == null) {
|
|
16
|
+
return { findings: [emptyFileWarning(file)] };
|
|
17
|
+
}
|
|
18
|
+
return { data, findings: [] };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEpE;;;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,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;SAC1F,CAAC;IACN,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAa,CAAC;IACnC,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;QACf,OAAO,EAAE,QAAQ,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;IAClD,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Diff, ReconcileMode } from './model.js';
|
|
2
|
+
/** What the report shows: the mode selects which operations, plus whether to list unchanged. */
|
|
3
|
+
type ReportOptions = {
|
|
4
|
+
mode: ReconcileMode;
|
|
5
|
+
showUnchanged: boolean;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Render a diff as a plan body, grouped by kind then target, with `+` adds, `~` expiration
|
|
9
|
+
* updates, `-` removes, and `=` unchanged. The mode scopes which operations appear (additive
|
|
10
|
+
* hides removes, destructive hides adds and updates), unchanged lines appear only when asked,
|
|
11
|
+
* and targets with nothing to show are omitted. Shared by plan and apply.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatDiff(diff: Diff, options: ReportOptions): string[];
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAQ,aAAa,EAAE,MAAM,YAAY,CAAC;AAiBvD,gGAAgG;AAChG,KAAK,aAAa,GAAG;IACjB,IAAI,EAAE,aAAa,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;CAC1B,CAAC;AA2FF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,EAAE,CAoBvE"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { kindKeys } from './normalize.js';
|
|
2
|
+
/** Human labels for the section headers, so the plan reads as prose, not YAML keys. */
|
|
3
|
+
const kindLabels = {
|
|
4
|
+
permissionSet: 'Permission Sets',
|
|
5
|
+
permissionSetGroup: 'Permission Set Groups',
|
|
6
|
+
permissionSetLicense: 'Permission Set Licenses',
|
|
7
|
+
};
|
|
8
|
+
function bucketFor(byKind, kind, target) {
|
|
9
|
+
let byTarget = byKind.get(kind);
|
|
10
|
+
if (!byTarget) {
|
|
11
|
+
byTarget = new Map();
|
|
12
|
+
byKind.set(kind, byTarget);
|
|
13
|
+
}
|
|
14
|
+
let bucket = byTarget.get(target);
|
|
15
|
+
if (!bucket) {
|
|
16
|
+
bucket = { adds: new Map(), updates: new Map(), removes: new Set(), unchanged: new Map() };
|
|
17
|
+
byTarget.set(target, bucket);
|
|
18
|
+
}
|
|
19
|
+
return bucket;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A canonical, readable form of an expiration instant, so values from the org and from the
|
|
23
|
+
* files display identically side by side. Falls back to the raw value if it cannot be parsed.
|
|
24
|
+
*/
|
|
25
|
+
function canonicalExpiration(value) {
|
|
26
|
+
const parsed = Date.parse(value);
|
|
27
|
+
if (Number.isNaN(parsed))
|
|
28
|
+
return value;
|
|
29
|
+
const instant = new Date(parsed);
|
|
30
|
+
return instant.toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
31
|
+
}
|
|
32
|
+
/** An assignee line suffixed with its expiration when there is one. */
|
|
33
|
+
function withExpiry(assignee, expiration) {
|
|
34
|
+
return expiration ? `${assignee} expires ${canonicalExpiration(expiration)}` : assignee;
|
|
35
|
+
}
|
|
36
|
+
/** An update line showing the expiration transition, with `never` standing in for no expiration. */
|
|
37
|
+
function withTransition(assignee, previous, next) {
|
|
38
|
+
const from = previous ? canonicalExpiration(previous) : 'never';
|
|
39
|
+
const to = next ? canonicalExpiration(next) : 'never';
|
|
40
|
+
return `${assignee} expires ${from} → ${to}`;
|
|
41
|
+
}
|
|
42
|
+
/** Group a diff into per-kind, per-target buckets, keeping only the operations the mode shows. */
|
|
43
|
+
function collectBuckets(diff, options) {
|
|
44
|
+
const showAdditive = options.mode !== 'destructive';
|
|
45
|
+
const showDestructive = options.mode !== 'additive';
|
|
46
|
+
const byKind = new Map();
|
|
47
|
+
if (showAdditive) {
|
|
48
|
+
for (const assignment of diff.toAdd) {
|
|
49
|
+
bucketFor(byKind, assignment.kind, assignment.target).adds.set(assignment.assignee, assignment.expiration);
|
|
50
|
+
}
|
|
51
|
+
for (const update of diff.toUpdate) {
|
|
52
|
+
bucketFor(byKind, update.kind, update.target).updates.set(update.assignee, {
|
|
53
|
+
previous: update.previousExpiration,
|
|
54
|
+
next: update.expiration,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (showDestructive) {
|
|
59
|
+
for (const assignment of diff.toRemove) {
|
|
60
|
+
bucketFor(byKind, assignment.kind, assignment.target).removes.add(assignment.assignee);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (options.showUnchanged) {
|
|
64
|
+
for (const assignment of diff.unchanged) {
|
|
65
|
+
bucketFor(byKind, assignment.kind, assignment.target).unchanged.set(assignment.assignee, assignment.expiration);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return byKind;
|
|
69
|
+
}
|
|
70
|
+
/** The `+`/`~`/`-`/`=` lines for one target, each group sorted by assignee. Empty when nothing shows. */
|
|
71
|
+
function renderBucket(bucket) {
|
|
72
|
+
const entries = [];
|
|
73
|
+
for (const assignee of [...bucket.adds.keys()].sort()) {
|
|
74
|
+
entries.push(` + ${withExpiry(assignee, bucket.adds.get(assignee))}`);
|
|
75
|
+
}
|
|
76
|
+
for (const assignee of [...bucket.updates.keys()].sort()) {
|
|
77
|
+
const change = bucket.updates.get(assignee);
|
|
78
|
+
entries.push(` ~ ${withTransition(assignee, change.previous, change.next)}`);
|
|
79
|
+
}
|
|
80
|
+
for (const assignee of [...bucket.removes].sort())
|
|
81
|
+
entries.push(` - ${assignee}`);
|
|
82
|
+
for (const assignee of [...bucket.unchanged.keys()].sort()) {
|
|
83
|
+
entries.push(` = ${withExpiry(assignee, bucket.unchanged.get(assignee))}`);
|
|
84
|
+
}
|
|
85
|
+
return entries;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Render a diff as a plan body, grouped by kind then target, with `+` adds, `~` expiration
|
|
89
|
+
* updates, `-` removes, and `=` unchanged. The mode scopes which operations appear (additive
|
|
90
|
+
* hides removes, destructive hides adds and updates), unchanged lines appear only when asked,
|
|
91
|
+
* and targets with nothing to show are omitted. Shared by plan and apply.
|
|
92
|
+
*/
|
|
93
|
+
export function formatDiff(diff, options) {
|
|
94
|
+
const byKind = collectBuckets(diff, options);
|
|
95
|
+
const lines = [];
|
|
96
|
+
for (const [kind] of kindKeys) {
|
|
97
|
+
const byTarget = byKind.get(kind);
|
|
98
|
+
if (!byTarget)
|
|
99
|
+
continue;
|
|
100
|
+
const sorted = [...byTarget].sort((left, right) => left[0].localeCompare(right[0]));
|
|
101
|
+
const targetLines = [];
|
|
102
|
+
for (const [target, bucket] of sorted) {
|
|
103
|
+
const entries = renderBucket(bucket);
|
|
104
|
+
if (entries.length === 0)
|
|
105
|
+
continue;
|
|
106
|
+
targetLines.push(` ${target}`, ...entries);
|
|
107
|
+
}
|
|
108
|
+
if (targetLines.length === 0)
|
|
109
|
+
continue;
|
|
110
|
+
lines.push(kindLabels[kind], ...targetLines);
|
|
111
|
+
}
|
|
112
|
+
return lines;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DesiredAssignment, Kind, OrgTarget, OrgUser } from './model.js';
|
|
2
|
+
import { Finding } from './finding.js';
|
|
3
|
+
export declare const kinds: Kind[];
|
|
4
|
+
/** The distinct usernames assigned across all assignments. */
|
|
5
|
+
export declare function distinctAssignees(assignments: DesiredAssignment[]): string[];
|
|
6
|
+
/** The distinct targets of one kind across all assignments. */
|
|
7
|
+
export declare function distinctTargets(assignments: DesiredAssignment[], kind: Kind): string[];
|
|
8
|
+
/** Every declared user must exist in the org and be active. */
|
|
9
|
+
export declare function evaluateUsers(declared: string[], found: OrgUser[]): Finding[];
|
|
10
|
+
/**
|
|
11
|
+
* Every declared target of one kind must resolve to exactly one record in the
|
|
12
|
+
* org. `found` is the list of matching identifiers the org returned; matching is
|
|
13
|
+
* case-insensitive, mirroring how the org compares them.
|
|
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>;
|
|
20
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,OAAO,EAAmF,MAAM,cAAc,CAAC;AASxH,eAAO,MAAM,KAAK,EAA8B,IAAI,EAAE,CAAC;AAMvD,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,iBAAiB,EAAE,GAAG,MAAM,EAAE,CAE5E;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,WAAW,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAItF;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAgB7E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAmB1F;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAQpE;AAED,iGAAiG;AACjG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAexE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { userNotFoundError, userInactiveError, targetNotFoundError, targetAmbiguousError } from './finding.js';
|
|
2
|
+
/** Human label per kind, used in findings. Domain wording, not SObject names. */
|
|
3
|
+
const kindLabels = {
|
|
4
|
+
permissionSet: 'permission set',
|
|
5
|
+
permissionSetGroup: 'permission set group',
|
|
6
|
+
permissionSetLicense: 'permission set license',
|
|
7
|
+
};
|
|
8
|
+
export const kinds = Object.keys(kindLabels);
|
|
9
|
+
function distinct(values) {
|
|
10
|
+
return [...new Set(values)];
|
|
11
|
+
}
|
|
12
|
+
/** The distinct usernames assigned across all assignments. */
|
|
13
|
+
export function distinctAssignees(assignments) {
|
|
14
|
+
return distinct(assignments.map((assignment) => assignment.assignee));
|
|
15
|
+
}
|
|
16
|
+
/** The distinct targets of one kind across all assignments. */
|
|
17
|
+
export function distinctTargets(assignments, kind) {
|
|
18
|
+
return distinct(assignments.filter((assignment) => assignment.kind === kind).map((assignment) => assignment.target));
|
|
19
|
+
}
|
|
20
|
+
/** Every declared user must exist in the org and be active. */
|
|
21
|
+
export function evaluateUsers(declared, found) {
|
|
22
|
+
const byName = new Map();
|
|
23
|
+
for (const user of found) {
|
|
24
|
+
byName.set(user.username.toLowerCase(), user);
|
|
25
|
+
}
|
|
26
|
+
const findings = [];
|
|
27
|
+
for (const username of declared) {
|
|
28
|
+
const user = byName.get(username.toLowerCase());
|
|
29
|
+
if (!user) {
|
|
30
|
+
findings.push(userNotFoundError(username));
|
|
31
|
+
}
|
|
32
|
+
else if (!user.isActive) {
|
|
33
|
+
findings.push(userInactiveError(username));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return findings;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Every declared target of one kind must resolve to exactly one record in the
|
|
40
|
+
* org. `found` is the list of matching identifiers the org returned; matching is
|
|
41
|
+
* case-insensitive, mirroring how the org compares them.
|
|
42
|
+
*/
|
|
43
|
+
export function evaluateTargets(kind, declared, found) {
|
|
44
|
+
const label = kindLabels[kind];
|
|
45
|
+
const counts = new Map();
|
|
46
|
+
for (const name of found) {
|
|
47
|
+
const key = name.toLowerCase();
|
|
48
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
49
|
+
}
|
|
50
|
+
const findings = [];
|
|
51
|
+
for (const target of declared) {
|
|
52
|
+
const count = counts.get(target.toLowerCase()) ?? 0;
|
|
53
|
+
if (count === 0) {
|
|
54
|
+
findings.push(targetNotFoundError(target, label));
|
|
55
|
+
}
|
|
56
|
+
else if (count > 1) {
|
|
57
|
+
findings.push(targetAmbiguousError(target, label));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return findings;
|
|
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
|
+
}
|
|
88
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/core/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Finding } from './finding.js';
|
|
3
|
+
declare const fileSchema: z.ZodObject<{
|
|
4
|
+
users: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
5
|
+
permissionSets: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
expiration: z.ZodISODateTime;
|
|
8
|
+
}, z.core.$strict>]>>>;
|
|
9
|
+
permissionSetGroups: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
10
|
+
name: z.ZodString;
|
|
11
|
+
expiration: z.ZodISODateTime;
|
|
12
|
+
}, z.core.$strict>]>>>;
|
|
13
|
+
permissionSetLicenses: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
14
|
+
}, z.core.$strict>>;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
export type FileShape = z.infer<typeof fileSchema>;
|
|
17
|
+
/** Validate a parsed object against the file contract, turning issues into findings. */
|
|
18
|
+
export declare function validateFile(data: unknown, file: string): {
|
|
19
|
+
data?: FileShape;
|
|
20
|
+
findings: Finding[];
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAe,MAAM,cAAc,CAAC;AA4BpD,QAAA,MAAM,UAAU;;;;;;;;;;;;kBAEd,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEnD,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CAUnG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { schemaError } from './finding.js';
|
|
3
|
+
// The permission set name
|
|
4
|
+
const name = z.string().min(1);
|
|
5
|
+
// The permission set expiration date
|
|
6
|
+
const expiration = z.iso.datetime({ offset: true });
|
|
7
|
+
/** An entry is either a bare target name or a name with an expiration. */
|
|
8
|
+
const expiringList = z.array(z.union([
|
|
9
|
+
name,
|
|
10
|
+
z.strictObject({
|
|
11
|
+
name,
|
|
12
|
+
expiration,
|
|
13
|
+
}),
|
|
14
|
+
]));
|
|
15
|
+
/** Licenses cannot expire (PermissionSetLicenseAssign has no ExpirationDate), so names only. */
|
|
16
|
+
const plainList = z.array(name);
|
|
17
|
+
const userEntrySchema = z.strictObject({
|
|
18
|
+
permissionSets: expiringList.optional(),
|
|
19
|
+
permissionSetGroups: expiringList.optional(),
|
|
20
|
+
permissionSetLicenses: plainList.optional(),
|
|
21
|
+
});
|
|
22
|
+
const fileSchema = z.strictObject({
|
|
23
|
+
users: z.record(z.string().min(1), userEntrySchema),
|
|
24
|
+
});
|
|
25
|
+
/** Validate a parsed object against the file contract, turning issues into findings. */
|
|
26
|
+
export function validateFile(data, file) {
|
|
27
|
+
const parsed = fileSchema.safeParse(data);
|
|
28
|
+
if (parsed.success) {
|
|
29
|
+
return { data: parsed.data, findings: [] };
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
findings: parsed.error.issues.map((issue) => schemaError(issue.path.join('.') || '(root)', issue.message, file)),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAW,WAAW,EAAE,MAAM,cAAc,CAAC;AAEpD,0BAA0B;AAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAE/B,qCAAqC;AACrC,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAEpD,0EAA0E;AAC1E,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CACxB,CAAC,CAAC,KAAK,CAAC;IACJ,IAAI;IACJ,CAAC,CAAC,YAAY,CAAC;QACX,IAAI;QACJ,UAAU;KACb,CAAC;CACL,CAAC,CACL,CAAC;AAEF,gGAAgG;AAChG,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAEhC,MAAM,eAAe,GAAG,CAAC,CAAC,YAAY,CAAC;IACnC,cAAc,EAAE,YAAY,CAAC,QAAQ,EAAE;IACvC,mBAAmB,EAAE,YAAY,CAAC,QAAQ,EAAE;IAC5C,qBAAqB,EAAE,SAAS,CAAC,QAAQ,EAAE;CAC9C,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,CAAC,CAAC,YAAY,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC;CACtD,CAAC,CAAC;AAIH,wFAAwF;AACxF,MAAM,UAAU,YAAY,CAAC,IAAa,EAAE,IAAY;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO;QACH,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACxC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CACrE;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DesiredAssignment } from './model.js';
|
|
2
|
+
/**
|
|
3
|
+
* Emit canonical assignments back to a user-keyed YAML document: the inverse of
|
|
4
|
+
* normalize. Usernames and targets are sorted and de-duplicated so the output is
|
|
5
|
+
* deterministic, empty scopes are omitted, and an assignment with an expiration
|
|
6
|
+
* is written as the object form so it round-trips through the schema.
|
|
7
|
+
*/
|
|
8
|
+
export declare function serializeAssignments(assignments: DesiredAssignment[]): string;
|
|
9
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../src/core/serialize.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAS/C;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAiC7E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { stringify } from 'yaml';
|
|
2
|
+
import { kindKeys } from './normalize.js';
|
|
3
|
+
/**
|
|
4
|
+
* Emit canonical assignments back to a user-keyed YAML document: the inverse of
|
|
5
|
+
* normalize. Usernames and targets are sorted and de-duplicated so the output is
|
|
6
|
+
* deterministic, empty scopes are omitted, and an assignment with an expiration
|
|
7
|
+
* is written as the object form so it round-trips through the schema.
|
|
8
|
+
*/
|
|
9
|
+
export function serializeAssignments(assignments) {
|
|
10
|
+
const usernames = [...new Set(assignments.map((assignment) => assignment.assignee))].sort();
|
|
11
|
+
const users = {};
|
|
12
|
+
for (const username of usernames) {
|
|
13
|
+
const entry = {};
|
|
14
|
+
for (const [kind, key] of kindKeys) {
|
|
15
|
+
const matching = assignments.filter((assignment) => assignment.assignee === username && assignment.kind === kind);
|
|
16
|
+
const expirationByTarget = new Map();
|
|
17
|
+
for (const assignment of matching) {
|
|
18
|
+
if (!expirationByTarget.has(assignment.target)) {
|
|
19
|
+
expirationByTarget.set(assignment.target, assignment.expiration);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const entries = [...expirationByTarget.keys()].sort().map((target) => {
|
|
23
|
+
const expiration = expirationByTarget.get(target);
|
|
24
|
+
return expiration ? { name: target, expiration } : target;
|
|
25
|
+
});
|
|
26
|
+
if (entries.length > 0) {
|
|
27
|
+
entry[key] = entries;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
users[username] = entry;
|
|
31
|
+
}
|
|
32
|
+
return stringify({ users });
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/core/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,EAAE,QAAQ,EAAY,MAAM,gBAAgB,CAAC;AAQpD;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAgC;IACjE,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5F,MAAM,KAAK,GAAwB,EAAE,CAAC;IAEtC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAgC,EAAE,CAAC;QAE9C,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAC/B,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,KAAK,IAAI,CAC/E,CAAC;YAEF,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAA8B,CAAC;YACjE,KAAK,MAAM,UAAU,IAAI,QAAQ,EAAE,CAAC;gBAChC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC7C,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;gBACrE,CAAC;YACL,CAAC;YAED,MAAM,OAAO,GAAsB,CAAC,GAAG,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;gBACpF,MAAM,UAAU,GAAG,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAClD,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YAC9D,CAAC,CAAC,CAAC;YAEH,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;YACzB,CAAC;QACL,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED,OAAO,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAChC,CAAC"}
|
package/lib/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,wBAAkB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/adapters/index.ts"],"names":[],"mappings":""}
|