@aglyn/aglyn 1.0.0-beta.254 → 1.0.0-beta.255
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 +11 -11
- package/src/lib/app-utils/business-profile-values.d.ts +83 -0
- package/src/lib/app-utils/business-profile-values.js +160 -0
- package/src/lib/app-utils/business-profile-values.js.map +1 -0
- package/src/lib/app-utils/business-profile.d.ts +7 -60
- package/src/lib/app-utils/business-profile.js +2 -172
- package/src/lib/app-utils/business-profile.js.map +1 -1
- package/src/lib/app-utils/docs-help-sections.generated.js +8 -5
- package/src/lib/app-utils/docs-help-sections.generated.js.map +1 -1
- package/src/lib/app-utils/docs-help.generated.d.ts +13 -7
- package/src/lib/app-utils/docs-help.generated.js +53 -16
- package/src/lib/app-utils/docs-help.generated.js.map +1 -1
- package/src/lib/app-utils/docs-index.generated.js +233 -2
- package/src/lib/app-utils/docs-index.generated.js.map +1 -1
- package/src/lib/app-utils/lockdown.d.ts +6 -0
- package/src/lib/app-utils/lockdown.js +20 -0
- package/src/lib/app-utils/lockdown.js.map +1 -1
- package/src/lib/app-utils/native-app-association.d.ts +129 -0
- package/src/lib/app-utils/native-app-association.js +248 -0
- package/src/lib/app-utils/native-app-association.js.map +1 -0
- package/src/lib/app-utils/sso-enforcement.d.ts +69 -0
- package/src/lib/app-utils/sso-enforcement.js +66 -0
- package/src/lib/app-utils/sso-enforcement.js.map +1 -0
- package/src/lib/app-utils/time-zone-choices.d.ts +46 -0
- package/src/lib/app-utils/time-zone-choices.js +469 -0
- package/src/lib/app-utils/time-zone-choices.js.map +1 -0
- package/src/lib/data-transfer/site-package-diff.d.ts +108 -0
- package/src/lib/data-transfer/site-package-diff.js +268 -0
- package/src/lib/data-transfer/site-package-diff.js.map +1 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /*==========================================
|
|
17
|
+
* WHAT AN IMPORTED ITEM CHANGES — the two comparisons the site package
|
|
18
|
+
* import shows (AGL-3534), pure so the console, the kit and the native apps
|
|
19
|
+
* read one definition:
|
|
20
|
+
*
|
|
21
|
+
* - {@link packageJsonDiff}: every leaf that differs between the site's
|
|
22
|
+
* item and the file's, as before → after rows;
|
|
23
|
+
* - {@link packageMergeKeys}: the top-level keys of a merged item that
|
|
24
|
+
* differ, each with what a merge would keep;
|
|
25
|
+
* - {@link packageRecordDiff} and {@link packageItemChanges}: an item that
|
|
26
|
+
* holds records (a dataset's rows) compared record by record, and the
|
|
27
|
+
* whole item's changes with the records set apart.
|
|
28
|
+
*
|
|
29
|
+
* Nothing here imports anything: both are about plain JSON.
|
|
30
|
+
*=========================================*/ /** Whose value one key of a merged item takes. */ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
31
|
+
const isPlain = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
32
|
+
const same = (a, b)=>JSON.stringify(a) === JSON.stringify(b);
|
|
33
|
+
/** A path as a person reads it: `version › nodes › text › props`. */ function pathLabel(path) {
|
|
34
|
+
return path.length ? path.join(' › ') : 'Whole item';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Every leaf that differs between the site's item and the file's, as
|
|
38
|
+
* before → after rows: objects are walked key by key, a list or a value is
|
|
39
|
+
* compared whole. At most `limit` rows; `more` counts the rest.
|
|
40
|
+
*/ export function packageJsonDiff(before, after, limit = 200) {
|
|
41
|
+
const changes = [];
|
|
42
|
+
let more = 0;
|
|
43
|
+
const walk = (left, right, path)=>{
|
|
44
|
+
if (same(left, right)) return;
|
|
45
|
+
if (isPlain(left) && isPlain(right)) {
|
|
46
|
+
const keys = [
|
|
47
|
+
...new Set([
|
|
48
|
+
...Object.keys(left),
|
|
49
|
+
...Object.keys(right)
|
|
50
|
+
])
|
|
51
|
+
].sort();
|
|
52
|
+
for (const key of keys)walk(left[key], right[key], [
|
|
53
|
+
...path,
|
|
54
|
+
key
|
|
55
|
+
]);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (changes.length >= limit) {
|
|
59
|
+
more += 1;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
changes.push({
|
|
63
|
+
key: path.join('/') || '$',
|
|
64
|
+
label: pathLabel(path),
|
|
65
|
+
before: left,
|
|
66
|
+
after: right
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
walk(before, after, []);
|
|
70
|
+
return {
|
|
71
|
+
changes,
|
|
72
|
+
more
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const blank = (value)=>value === undefined || value === null || value === '';
|
|
76
|
+
/** The keys of a merged item that differ, each with what a merge would keep. */ export function packageMergeKeys(site, file) {
|
|
77
|
+
const left = isPlain(site) ? site : {};
|
|
78
|
+
const right = isPlain(file) ? file : {};
|
|
79
|
+
return Object.keys(right).sort().filter((key)=>right[key] !== undefined && !same(left[key], right[key])).map((key)=>({
|
|
80
|
+
key,
|
|
81
|
+
site: left[key],
|
|
82
|
+
file: right[key],
|
|
83
|
+
merged: blank(left[key]) ? 'package' : 'site'
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
const isRecord = (value)=>isPlain(value) && typeof value['$id'] === 'string' && value['$id'] !== '';
|
|
87
|
+
/**
|
|
88
|
+
* The key of an item that holds its records — a dataset's `records`, a
|
|
89
|
+
* collection's `entries` — found by shape rather than by kind, so nothing
|
|
90
|
+
* here names a kind a plugin declares: the one list, on either side, whose
|
|
91
|
+
* every element is a document with its own `$id`. The other side holds a
|
|
92
|
+
* list there too, or nothing. `null` when no key qualifies, or when more
|
|
93
|
+
* than one does and neither can be read as the item's records.
|
|
94
|
+
*/ export function packageRecordField(...contents) {
|
|
95
|
+
const docs = contents.filter(isPlain);
|
|
96
|
+
const found = new Set();
|
|
97
|
+
for (const doc of docs){
|
|
98
|
+
for (const [key, value] of Object.entries(doc)){
|
|
99
|
+
if (Array.isArray(value) && value.length > 0 && value.every(isRecord)) found.add(key);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const fields = [
|
|
103
|
+
...found
|
|
104
|
+
].filter((key)=>docs.every((doc)=>{
|
|
105
|
+
const value = doc[key];
|
|
106
|
+
return value === undefined || value === null || Array.isArray(value) && value.every(isRecord);
|
|
107
|
+
}));
|
|
108
|
+
return fields.length === 1 ? fields[0] : null;
|
|
109
|
+
}
|
|
110
|
+
const recordsOf = (value)=>Array.isArray(value) ? value.filter(isRecord) : [];
|
|
111
|
+
/**
|
|
112
|
+
* Two lists of records, matched by `$id`: what the file adds, what it no
|
|
113
|
+
* longer holds, and, for a record on both sides, each field whose value
|
|
114
|
+
* differs. A record the import would leave as it is counts as `same` and
|
|
115
|
+
* has no row.
|
|
116
|
+
*/ export function packageRecordDiff(site, file) {
|
|
117
|
+
const theirs = new Map(recordsOf(site).map((record)=>[
|
|
118
|
+
record.$id,
|
|
119
|
+
record
|
|
120
|
+
]));
|
|
121
|
+
const ours = recordsOf(file);
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
const rows = [];
|
|
124
|
+
const counts = {
|
|
125
|
+
added: 0,
|
|
126
|
+
removed: 0,
|
|
127
|
+
changed: 0,
|
|
128
|
+
same: 0
|
|
129
|
+
};
|
|
130
|
+
for (const record of ours){
|
|
131
|
+
if (seen.has(record.$id)) continue;
|
|
132
|
+
seen.add(record.$id);
|
|
133
|
+
const existing = theirs.get(record.$id);
|
|
134
|
+
if (!existing) {
|
|
135
|
+
counts.added += 1;
|
|
136
|
+
rows.push({
|
|
137
|
+
id: record.$id,
|
|
138
|
+
status: 'added',
|
|
139
|
+
site: null,
|
|
140
|
+
file: record,
|
|
141
|
+
changed: []
|
|
142
|
+
});
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const keys = [
|
|
146
|
+
...new Set([
|
|
147
|
+
...Object.keys(existing),
|
|
148
|
+
...Object.keys(record)
|
|
149
|
+
])
|
|
150
|
+
].filter((key)=>key !== '$id');
|
|
151
|
+
const changed = keys.filter((key)=>!same(existing[key], record[key])).sort();
|
|
152
|
+
if (!changed.length) {
|
|
153
|
+
counts.same += 1;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
counts.changed += 1;
|
|
157
|
+
rows.push({
|
|
158
|
+
id: record.$id,
|
|
159
|
+
status: 'changed',
|
|
160
|
+
site: existing,
|
|
161
|
+
file: record,
|
|
162
|
+
changed
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
for (const [id, record] of theirs){
|
|
166
|
+
if (seen.has(id)) continue;
|
|
167
|
+
counts.removed += 1;
|
|
168
|
+
rows.push({
|
|
169
|
+
id,
|
|
170
|
+
status: 'removed',
|
|
171
|
+
site: record,
|
|
172
|
+
file: null,
|
|
173
|
+
changed: []
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const fields = [];
|
|
177
|
+
const listed = new Set([
|
|
178
|
+
'$id'
|
|
179
|
+
]);
|
|
180
|
+
for (const row of rows){
|
|
181
|
+
for (const record of [
|
|
182
|
+
row.file,
|
|
183
|
+
row.site
|
|
184
|
+
]){
|
|
185
|
+
for (const key of Object.keys(record != null ? record : {})){
|
|
186
|
+
if (listed.has(key)) continue;
|
|
187
|
+
listed.add(key);
|
|
188
|
+
fields.push(key);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
rows,
|
|
194
|
+
fields,
|
|
195
|
+
counts
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const withoutRecords = (content, field)=>{
|
|
199
|
+
if (!field || typeof content !== 'object' || content === null || Array.isArray(content)) return content;
|
|
200
|
+
const rest = _extends({}, content);
|
|
201
|
+
delete rest[field];
|
|
202
|
+
return rest;
|
|
203
|
+
};
|
|
204
|
+
const countOf = (count, singular, plural = `${singular}s`)=>`${count.toLocaleString('en-US')} ${count === 1 ? singular : plural}`;
|
|
205
|
+
/**
|
|
206
|
+
* What importing an item changes: the leaf-by-leaf diff of everything but
|
|
207
|
+
* its records, and, for an item that holds records, a row per value that
|
|
208
|
+
* differs (a whole record for one only a side holds). At most `limit` rows
|
|
209
|
+
* of each; `more` counts the rest.
|
|
210
|
+
*/ export function packageItemChanges(before, incoming, limit = 200) {
|
|
211
|
+
const existing = before != null ? before : {};
|
|
212
|
+
const recordField = packageRecordField(existing, incoming);
|
|
213
|
+
const values = packageJsonDiff(withoutRecords(existing, recordField), withoutRecords(incoming, recordField), limit);
|
|
214
|
+
if (!recordField) return _extends({
|
|
215
|
+
recordField
|
|
216
|
+
}, values, {
|
|
217
|
+
records: null
|
|
218
|
+
});
|
|
219
|
+
const recordsIn = (content)=>typeof content === 'object' && content !== null ? content[recordField] : undefined;
|
|
220
|
+
const diff = packageRecordDiff(recordsIn(existing), recordsIn(incoming));
|
|
221
|
+
const changes = [];
|
|
222
|
+
let more = 0;
|
|
223
|
+
const add = (change)=>{
|
|
224
|
+
if (changes.length >= limit) more += 1;
|
|
225
|
+
else changes.push(change);
|
|
226
|
+
};
|
|
227
|
+
for (const row of diff.rows){
|
|
228
|
+
if (row.status === 'changed') {
|
|
229
|
+
for (const field of row.changed){
|
|
230
|
+
var _row_site, _row_file;
|
|
231
|
+
add({
|
|
232
|
+
key: `${row.id}/${field}`,
|
|
233
|
+
label: `${row.id} › ${field}`,
|
|
234
|
+
status: 'changed',
|
|
235
|
+
before: (_row_site = row.site) == null ? void 0 : _row_site[field],
|
|
236
|
+
after: (_row_file = row.file) == null ? void 0 : _row_file[field]
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
var _row_site1, _row_file1;
|
|
241
|
+
add({
|
|
242
|
+
key: row.id,
|
|
243
|
+
label: row.id,
|
|
244
|
+
status: row.status,
|
|
245
|
+
before: (_row_site1 = row.site) != null ? _row_site1 : undefined,
|
|
246
|
+
after: (_row_file1 = row.file) != null ? _row_file1 : undefined
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const { added, removed, changed, same: unchanged } = diff.counts;
|
|
251
|
+
const summary = [
|
|
252
|
+
countOf(added, 'new record'),
|
|
253
|
+
countOf(changed, 'changed record'),
|
|
254
|
+
`${countOf(removed, 'record')} not in the file`,
|
|
255
|
+
`${unchanged.toLocaleString('en-US')} unchanged`
|
|
256
|
+
].join(' · ');
|
|
257
|
+
return _extends({
|
|
258
|
+
recordField
|
|
259
|
+
}, values, {
|
|
260
|
+
records: {
|
|
261
|
+
summary,
|
|
262
|
+
changes,
|
|
263
|
+
more
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
//# sourceMappingURL=site-package-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/aglyn/src/lib/data-transfer/site-package-diff.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * WHAT AN IMPORTED ITEM CHANGES — the two comparisons the site package\n * import shows (AGL-3534), pure so the console, the kit and the native apps\n * read one definition:\n *\n * - {@link packageJsonDiff}: every leaf that differs between the site's\n * item and the file's, as before → after rows;\n * - {@link packageMergeKeys}: the top-level keys of a merged item that\n * differ, each with what a merge would keep;\n * - {@link packageRecordDiff} and {@link packageItemChanges}: an item that\n * holds records (a dataset's rows) compared record by record, and the\n * whole item's changes with the records set apart.\n *\n * Nothing here imports anything: both are about plain JSON.\n *=========================================*/\n\n/** Whose value one key of a merged item takes. */\nexport type SitePackageMergeSide = 'site' | 'package'\n\n/** One leaf that differs: where it is, and the two values. */\nexport interface PackageJsonChange {\n key: string\n label: string\n before: unknown\n after: unknown\n}\n\nconst isPlain = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype\n\nconst same = (a: unknown, b: unknown) => JSON.stringify(a) === JSON.stringify(b)\n\n/** A path as a person reads it: `version › nodes › text › props`. */\nfunction pathLabel(path: readonly string[]): string {\n return path.length ? path.join(' › ') : 'Whole item'\n}\n\n/**\n * Every leaf that differs between the site's item and the file's, as\n * before → after rows: objects are walked key by key, a list or a value is\n * compared whole. At most `limit` rows; `more` counts the rest.\n */\nexport function packageJsonDiff(\n before: unknown,\n after: unknown,\n limit = 200,\n): { changes: PackageJsonChange[]; more: number } {\n const changes: PackageJsonChange[] = []\n let more = 0\n const walk = (left: unknown, right: unknown, path: string[]) => {\n if (same(left, right)) return\n if (isPlain(left) && isPlain(right)) {\n const keys = [...new Set([...Object.keys(left), ...Object.keys(right)])].sort()\n for (const key of keys) walk(left[key], right[key], [...path, key])\n return\n }\n if (changes.length >= limit) {\n more += 1\n return\n }\n changes.push({ key: path.join('/') || '$', label: pathLabel(path), before: left, after: right })\n }\n walk(before, after, [])\n return { changes, more }\n}\n\n/** One top-level key of a merged item: both values and the default. */\nexport interface PackageMergeKey {\n key: string\n site: unknown\n file: unknown\n /** What a merge does when the person does not say: the site's value wins when it has one. */\n merged: SitePackageMergeSide\n}\n\nconst blank = (value: unknown) => value === undefined || value === null || value === ''\n\n/** The keys of a merged item that differ, each with what a merge would keep. */\nexport function packageMergeKeys(site: unknown, file: unknown): PackageMergeKey[] {\n const left = isPlain(site) ? site : {}\n const right = isPlain(file) ? file : {}\n return Object.keys(right)\n .sort()\n .filter((key) => right[key] !== undefined && !same(left[key], right[key]))\n .map((key) => ({\n key,\n site: left[key],\n file: right[key],\n merged: blank(left[key]) ? 'package' : 'site',\n }))\n}\n\n/*==========================================\n * RECORDS\n *=========================================*/\n\n/** One record of an item's list: a document with its own `$id`. */\nexport type PackageRecord = Record<string, unknown> & { $id: string }\n\nconst isRecord = (value: unknown): value is PackageRecord =>\n isPlain(value) && typeof value['$id'] === 'string' && value['$id'] !== ''\n\n/**\n * The key of an item that holds its records — a dataset's `records`, a\n * collection's `entries` — found by shape rather than by kind, so nothing\n * here names a kind a plugin declares: the one list, on either side, whose\n * every element is a document with its own `$id`. The other side holds a\n * list there too, or nothing. `null` when no key qualifies, or when more\n * than one does and neither can be read as the item's records.\n */\nexport function packageRecordField(...contents: readonly unknown[]): string | null {\n const docs = contents.filter(isPlain)\n const found = new Set<string>()\n for (const doc of docs) {\n for (const [key, value] of Object.entries(doc)) {\n if (Array.isArray(value) && value.length > 0 && value.every(isRecord)) found.add(key)\n }\n }\n const fields = [...found].filter((key) =>\n docs.every((doc) => {\n const value = doc[key]\n return value === undefined || value === null || (Array.isArray(value) && value.every(isRecord))\n }),\n )\n return fields.length === 1 ? (fields[0] as string) : null\n}\n\nexport type PackageRecordStatus = 'added' | 'removed' | 'changed'\n\n/** One record that differs between the site and the file. */\nexport interface PackageRecordRow {\n id: string\n status: PackageRecordStatus\n /** The site's copy; `null` for a record only the file holds. */\n site: PackageRecord | null\n /** The file's copy; `null` for a record only the site holds. */\n file: PackageRecord | null\n /** The fields whose values differ, for a changed record. */\n changed: readonly string[]\n}\n\nexport interface PackageRecordDiff {\n /** The file's added and changed records in its order, then the site's removed ones. */\n rows: PackageRecordRow[]\n /** Every field the rows hold, `$id` aside, in the order they first appear. */\n fields: string[]\n counts: Record<PackageRecordStatus | 'same', number>\n}\n\nconst recordsOf = (value: unknown): PackageRecord[] => (Array.isArray(value) ? value.filter(isRecord) : [])\n\n/**\n * Two lists of records, matched by `$id`: what the file adds, what it no\n * longer holds, and, for a record on both sides, each field whose value\n * differs. A record the import would leave as it is counts as `same` and\n * has no row.\n */\nexport function packageRecordDiff(site: unknown, file: unknown): PackageRecordDiff {\n const theirs = new Map(recordsOf(site).map((record) => [record.$id, record]))\n const ours = recordsOf(file)\n const seen = new Set<string>()\n const rows: PackageRecordRow[] = []\n const counts = { added: 0, removed: 0, changed: 0, same: 0 }\n for (const record of ours) {\n if (seen.has(record.$id)) continue\n seen.add(record.$id)\n const existing = theirs.get(record.$id)\n if (!existing) {\n counts.added += 1\n rows.push({ id: record.$id, status: 'added', site: null, file: record, changed: [] })\n continue\n }\n const keys = [...new Set([...Object.keys(existing), ...Object.keys(record)])].filter((key) => key !== '$id')\n const changed = keys.filter((key) => !same(existing[key], record[key])).sort()\n if (!changed.length) {\n counts.same += 1\n continue\n }\n counts.changed += 1\n rows.push({ id: record.$id, status: 'changed', site: existing, file: record, changed })\n }\n for (const [id, record] of theirs) {\n if (seen.has(id)) continue\n counts.removed += 1\n rows.push({ id, status: 'removed', site: record, file: null, changed: [] })\n }\n const fields: string[] = []\n const listed = new Set<string>(['$id'])\n for (const row of rows) {\n for (const record of [row.file, row.site]) {\n for (const key of Object.keys(record ?? {})) {\n if (listed.has(key)) continue\n listed.add(key)\n fields.push(key)\n }\n }\n }\n return { rows, fields, counts }\n}\n\n/** One value of one record that differs, in the shape of {@link PackageJsonChange}. */\nexport interface PackageRecordChange extends PackageJsonChange {\n status: PackageRecordStatus\n}\n\n/** An item's changes: its values, and its records set apart when it holds them. */\nexport interface PackageItemChanges {\n /** The key that holds the records, when the item has them. */\n recordField: string | null\n /** Every value that differs, the records aside. */\n changes: PackageJsonChange[]\n more: number\n /** The records that differ, a value of a changed record to a row; `null` when the item holds none. */\n records: { summary: string; changes: PackageRecordChange[]; more: number } | null\n}\n\nconst withoutRecords = (content: unknown, field: string | null): unknown => {\n if (!field || typeof content !== 'object' || content === null || Array.isArray(content)) return content\n const rest = { ...(content as Record<string, unknown>) }\n delete rest[field]\n return rest\n}\n\nconst countOf = (count: number, singular: string, plural = `${singular}s`) =>\n `${count.toLocaleString('en-US')} ${count === 1 ? singular : plural}`\n\n/**\n * What importing an item changes: the leaf-by-leaf diff of everything but\n * its records, and, for an item that holds records, a row per value that\n * differs (a whole record for one only a side holds). At most `limit` rows\n * of each; `more` counts the rest.\n */\nexport function packageItemChanges(before: unknown, incoming: unknown, limit = 200): PackageItemChanges {\n const existing = before ?? {}\n const recordField = packageRecordField(existing, incoming)\n const values = packageJsonDiff(withoutRecords(existing, recordField), withoutRecords(incoming, recordField), limit)\n if (!recordField) return { recordField, ...values, records: null }\n const recordsIn = (content: unknown) =>\n typeof content === 'object' && content !== null ? (content as Record<string, unknown>)[recordField] : undefined\n const diff = packageRecordDiff(recordsIn(existing), recordsIn(incoming))\n const changes: PackageRecordChange[] = []\n let more = 0\n const add = (change: PackageRecordChange) => {\n if (changes.length >= limit) more += 1\n else changes.push(change)\n }\n for (const row of diff.rows) {\n if (row.status === 'changed') {\n for (const field of row.changed) {\n add({\n key: `${row.id}/${field}`,\n label: `${row.id} › ${field}`,\n status: 'changed',\n before: row.site?.[field],\n after: row.file?.[field],\n })\n }\n } else {\n add({ key: row.id, label: row.id, status: row.status, before: row.site ?? undefined, after: row.file ?? undefined })\n }\n }\n const { added, removed, changed, same: unchanged } = diff.counts\n const summary = [\n countOf(added, 'new record'),\n countOf(changed, 'changed record'),\n `${countOf(removed, 'record')} not in the file`,\n `${unchanged.toLocaleString('en-US')} unchanged`,\n ].join(' · ')\n return { recordField, ...values, records: { summary, changes, more } }\n}\n"],"names":["isPlain","value","Array","isArray","Object","getPrototypeOf","prototype","same","a","b","JSON","stringify","pathLabel","path","length","join","packageJsonDiff","before","after","limit","changes","more","walk","left","right","keys","Set","sort","key","push","label","blank","undefined","packageMergeKeys","site","file","filter","map","merged","isRecord","packageRecordField","contents","docs","found","doc","entries","every","add","fields","recordsOf","packageRecordDiff","theirs","Map","record","$id","ours","seen","rows","counts","added","removed","changed","has","existing","get","id","status","listed","row","withoutRecords","content","field","rest","countOf","count","singular","plural","toLocaleString","packageItemChanges","incoming","recordField","values","records","recordsIn","diff","change","unchanged","summary"],"mappings":"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"}
|