ngx-dynamic-entity 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/fesm2022/ngx-dynamic-entity.mjs +228 -150
- package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
- package/package.json +6 -7
- package/types/ngx-dynamic-entity.d.ts +1719 -0
- package/esm2022/lib/field-types/array-field.component.mjs +0 -168
- package/esm2022/lib/field-types/boolean-field.component.mjs +0 -101
- package/esm2022/lib/field-types/checkbox-field.component.mjs +0 -82
- package/esm2022/lib/field-types/currency-field.component.mjs +0 -102
- package/esm2022/lib/field-types/date-field.component.mjs +0 -91
- package/esm2022/lib/field-types/date-time-field.component.mjs +0 -138
- package/esm2022/lib/field-types/dropdown-field.component.mjs +0 -176
- package/esm2022/lib/field-types/email-field.component.mjs +0 -102
- package/esm2022/lib/field-types/entity-ref-field.component.mjs +0 -195
- package/esm2022/lib/field-types/field-component.contract.mjs +0 -2
- package/esm2022/lib/field-types/file-field.component.mjs +0 -157
- package/esm2022/lib/field-types/group-field.component.mjs +0 -89
- package/esm2022/lib/field-types/image-field.component.mjs +0 -169
- package/esm2022/lib/field-types/month-year-field.component.mjs +0 -152
- package/esm2022/lib/field-types/multi-select-field.component.mjs +0 -146
- package/esm2022/lib/field-types/number-field.component.mjs +0 -112
- package/esm2022/lib/field-types/password-field.component.mjs +0 -110
- package/esm2022/lib/field-types/radio-field.component.mjs +0 -153
- package/esm2022/lib/field-types/text-field.component.mjs +0 -121
- package/esm2022/lib/field-types/textarea-field.component.mjs +0 -85
- package/esm2022/lib/field-types/time-field.component.mjs +0 -96
- package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +0 -152
- package/esm2022/lib/form/dynamic-form.component.mjs +0 -899
- package/esm2022/lib/form/dynamic-record-form.component.mjs +0 -531
- package/esm2022/lib/providers/provide-field-types.mjs +0 -75
- package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +0 -27
- package/esm2022/lib/services/cascade-data.service.mjs +0 -129
- package/esm2022/lib/services/config-source.service.mjs +0 -67
- package/esm2022/lib/services/entity-ref-cache.mjs +0 -20
- package/esm2022/lib/services/entity-ref-registry.service.mjs +0 -31
- package/esm2022/lib/services/entity-ref-selection.service.mjs +0 -27
- package/esm2022/lib/services/entity-reference.service.mjs +0 -168
- package/esm2022/lib/services/field-registry.service.mjs +0 -55
- package/esm2022/lib/services/file-upload.service.mjs +0 -89
- package/esm2022/lib/services/hook-registry.service.mjs +0 -26
- package/esm2022/lib/services/lookup-registry.service.mjs +0 -246
- package/esm2022/lib/services/rbac.service.mjs +0 -46
- package/esm2022/lib/services/rules-evaluation.service.mjs +0 -27
- package/esm2022/lib/services/validation-messages.service.mjs +0 -56
- package/esm2022/lib/services/validator-registry.service.mjs +0 -99
- package/esm2022/lib/tokens/injection-tokens.mjs +0 -126
- package/esm2022/ngx-dynamic-entity.mjs +0 -5
- package/esm2022/public-api.mjs +0 -58
- package/index.d.ts +0 -5
- package/lib/field-types/array-field.component.d.ts +0 -28
- package/lib/field-types/boolean-field.component.d.ts +0 -18
- package/lib/field-types/checkbox-field.component.d.ts +0 -13
- package/lib/field-types/currency-field.component.d.ts +0 -17
- package/lib/field-types/date-field.component.d.ts +0 -15
- package/lib/field-types/date-time-field.component.d.ts +0 -30
- package/lib/field-types/dropdown-field.component.d.ts +0 -34
- package/lib/field-types/email-field.component.d.ts +0 -15
- package/lib/field-types/entity-ref-field.component.d.ts +0 -49
- package/lib/field-types/field-component.contract.d.ts +0 -49
- package/lib/field-types/file-field.component.d.ts +0 -25
- package/lib/field-types/group-field.component.d.ts +0 -17
- package/lib/field-types/image-field.component.d.ts +0 -30
- package/lib/field-types/month-year-field.component.d.ts +0 -28
- package/lib/field-types/multi-select-field.component.d.ts +0 -27
- package/lib/field-types/number-field.component.d.ts +0 -16
- package/lib/field-types/password-field.component.d.ts +0 -17
- package/lib/field-types/radio-field.component.d.ts +0 -33
- package/lib/field-types/text-field.component.d.ts +0 -23
- package/lib/field-types/textarea-field.component.d.ts +0 -14
- package/lib/field-types/time-field.component.d.ts +0 -27
- package/lib/form/dynamic-field/dynamic-field.component.d.ts +0 -78
- package/lib/form/dynamic-form.component.d.ts +0 -293
- package/lib/form/dynamic-record-form.component.d.ts +0 -199
- package/lib/providers/provide-field-types.d.ts +0 -24
- package/lib/providers/provide-ngx-dynamic-entity.d.ts +0 -56
- package/lib/services/cascade-data.service.d.ts +0 -45
- package/lib/services/config-source.service.d.ts +0 -14
- package/lib/services/entity-ref-cache.d.ts +0 -27
- package/lib/services/entity-ref-registry.service.d.ts +0 -21
- package/lib/services/entity-ref-selection.service.d.ts +0 -24
- package/lib/services/entity-reference.service.d.ts +0 -49
- package/lib/services/field-registry.service.d.ts +0 -32
- package/lib/services/file-upload.service.d.ts +0 -27
- package/lib/services/hook-registry.service.d.ts +0 -12
- package/lib/services/lookup-registry.service.d.ts +0 -94
- package/lib/services/rbac.service.d.ts +0 -27
- package/lib/services/rules-evaluation.service.d.ts +0 -17
- package/lib/services/validation-messages.service.d.ts +0 -43
- package/lib/services/validator-registry.service.d.ts +0 -32
- package/lib/tokens/injection-tokens.d.ts +0 -134
- package/public-api.d.ts +0 -42
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { lookupValuesToOptions, normalizeLookupValues, resolveLabel } from '@dynamic-entity/core';
|
|
3
|
-
import { LOOKUP_REGISTRY } from '../tokens/injection-tokens';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
/** Cache-key field separator. Kept out of template literals so it stays visible in source. */
|
|
6
|
-
const SEP = '|';
|
|
7
|
-
/**
|
|
8
|
-
* LookupRegistryService — the cache in front of consumer-registered master lists.
|
|
9
|
-
*
|
|
10
|
-
* Three layers, deliberately the same shape as `EntityReferenceService`, because the problem is
|
|
11
|
-
* the same: one list is typically used by many fields across many entities.
|
|
12
|
-
* 1. **options** — resolved `DropdownOption[]` per (list name, lang).
|
|
13
|
-
* 2. **in-flight** — the pending Promise, so N fields on one list trigger one load, not N.
|
|
14
|
-
* 3. **labels** — synchronous value → text (parity plan §6.2). This is not a nicety: since
|
|
15
|
-
* `viewMode` defaults to true a record opens read-only, so rendering a stored value as
|
|
16
|
-
* text is the *first* thing a `listName` field has to do. An async-only registry would
|
|
17
|
-
* paint the raw stored value and then flip, on every record open.
|
|
18
|
-
*
|
|
19
|
-
* A failed load rejects and caches nothing, so one transient error does not serve an empty
|
|
20
|
-
* list forever — the same fix made for entity references in phase 5.
|
|
21
|
-
*/
|
|
22
|
-
export class LookupRegistryService {
|
|
23
|
-
registry = inject(LOOKUP_REGISTRY, { optional: true }) ?? new Map();
|
|
24
|
-
/** `listName|lang` -> resolved options. */
|
|
25
|
-
options = new Map();
|
|
26
|
-
/** `listName|lang` -> normalised values, so a consumer can reach `code` / `isSystemDefined`. */
|
|
27
|
-
values = new Map();
|
|
28
|
-
/** Loads in progress, keyed as above. */
|
|
29
|
-
inFlight = new Map();
|
|
30
|
-
/** `listName|lang|text` -> display text, for the synchronous read-only path. */
|
|
31
|
-
labels = new Map();
|
|
32
|
-
has(listName) {
|
|
33
|
-
return this.registry.has(listName);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Options for a named list, from cache when present.
|
|
37
|
-
* Concurrent callers with the same key share one load.
|
|
38
|
-
*/
|
|
39
|
-
async load(listName, lang = 'en') {
|
|
40
|
-
const key = this.cacheKey(listName, lang);
|
|
41
|
-
const cached = this.options.get(key);
|
|
42
|
-
if (cached)
|
|
43
|
-
return cached;
|
|
44
|
-
const pending = this.inFlight.get(key);
|
|
45
|
-
if (pending)
|
|
46
|
-
return pending;
|
|
47
|
-
const source = this.registry.get(listName);
|
|
48
|
-
if (source === undefined)
|
|
49
|
-
return [];
|
|
50
|
-
const load = this.invoke(source, lang).then(raw => {
|
|
51
|
-
const values = normalizeLookupValues(raw);
|
|
52
|
-
const options = lookupValuesToOptions(values);
|
|
53
|
-
this.values.set(key, values);
|
|
54
|
-
this.options.set(key, options);
|
|
55
|
-
this.rememberLabels(listName, lang, options);
|
|
56
|
-
return options;
|
|
57
|
-
});
|
|
58
|
-
// Only the `.then` above writes to the cache, and a rejection skips it: the caller still
|
|
59
|
-
// gets an empty list, but the next call retries instead of reading a poisoned entry.
|
|
60
|
-
const guarded = load
|
|
61
|
-
.catch(() => [])
|
|
62
|
-
.finally(() => this.inFlight.delete(key));
|
|
63
|
-
this.inFlight.set(key, guarded);
|
|
64
|
-
return guarded;
|
|
65
|
-
}
|
|
66
|
-
/** Cached options without triggering a load. `undefined` when not loaded. */
|
|
67
|
-
peek(listName, lang = 'en') {
|
|
68
|
-
return this.options.get(this.cacheKey(listName, lang));
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Cached list values, carrying `_id`, `code`, `isSystemDefined` and `from`.
|
|
72
|
-
* The library never reads those; this is the seam for a consumer that needs them.
|
|
73
|
-
*/
|
|
74
|
-
valuesFor(listName, lang = 'en') {
|
|
75
|
-
return this.values.get(this.cacheKey(listName, lang));
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Display text for a stored value, synchronously. `undefined` when the list has not loaded
|
|
79
|
-
* or holds no matching value — the caller keeps its own fallback, which is the stored text.
|
|
80
|
-
*
|
|
81
|
-
* Every language of an option is indexed, so a record saved under one language renders in
|
|
82
|
-
* another: a value stored as `'Aktiv'` resolves to `'Active'` under `lang: 'en'`.
|
|
83
|
-
*/
|
|
84
|
-
labelFor(listName, value, lang = 'en') {
|
|
85
|
-
if (!listName || value === null || value === undefined || value === '')
|
|
86
|
-
return undefined;
|
|
87
|
-
for (const text of this.candidateTexts(value, lang)) {
|
|
88
|
-
const hit = this.labels.get(this.labelKey(listName, lang, text));
|
|
89
|
-
if (hit)
|
|
90
|
-
return hit;
|
|
91
|
-
}
|
|
92
|
-
return undefined;
|
|
93
|
-
}
|
|
94
|
-
// ─── Field-level resolution — inline options win, else `listName` ────────────
|
|
95
|
-
/** True when this field's options have to come from the registry. */
|
|
96
|
-
needsResolve(field) {
|
|
97
|
-
return !!field?.listName && !field.options?.length;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* The options to render right now, without awaiting: inline options, else whatever the
|
|
101
|
-
* registry already holds. Empty on a cold miss — pair with `resolveOptions`.
|
|
102
|
-
*/
|
|
103
|
-
optionsFor(field, lang = 'en') {
|
|
104
|
-
if (!field)
|
|
105
|
-
return [];
|
|
106
|
-
if (field.options?.length)
|
|
107
|
-
return field.options;
|
|
108
|
-
if (!field.listName)
|
|
109
|
-
return [];
|
|
110
|
-
return this.peek(field.listName, lang) ?? [];
|
|
111
|
-
}
|
|
112
|
-
/** The options for a field, loading the named list if needed. */
|
|
113
|
-
resolveOptions(field, lang = 'en') {
|
|
114
|
-
if (!this.needsResolve(field))
|
|
115
|
-
return Promise.resolve(this.optionsFor(field, lang));
|
|
116
|
-
return this.load(field.listName, lang);
|
|
117
|
-
}
|
|
118
|
-
/** Drop everything cached for one list, leaving other lists intact. */
|
|
119
|
-
invalidate(listName) {
|
|
120
|
-
const prefix = `${listName}${SEP}`;
|
|
121
|
-
for (const map of [this.options, this.values, this.inFlight]) {
|
|
122
|
-
for (const key of [...map.keys()]) {
|
|
123
|
-
if (key.startsWith(prefix))
|
|
124
|
-
map.delete(key);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
for (const key of [...this.labels.keys()]) {
|
|
128
|
-
if (key.startsWith(prefix))
|
|
129
|
-
this.labels.delete(key);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
clear() {
|
|
133
|
-
this.options.clear();
|
|
134
|
-
this.values.clear();
|
|
135
|
-
this.inFlight.clear();
|
|
136
|
-
this.labels.clear();
|
|
137
|
-
}
|
|
138
|
-
// ─── Internals ──────────────────────────────────────────────────────────────
|
|
139
|
-
cacheKey(listName, lang) {
|
|
140
|
-
return [listName, lang].join(SEP);
|
|
141
|
-
}
|
|
142
|
-
labelKey(listName, lang, text) {
|
|
143
|
-
return [listName, lang, text].join(SEP);
|
|
144
|
-
}
|
|
145
|
-
/** Index an option under every language it carries, so any stored spelling finds it. */
|
|
146
|
-
rememberLabels(listName, lang, options) {
|
|
147
|
-
for (const option of options) {
|
|
148
|
-
const display = resolveLabel(option, lang);
|
|
149
|
-
if (!display)
|
|
150
|
-
continue;
|
|
151
|
-
for (const text of Object.values(option)) {
|
|
152
|
-
if (typeof text === 'string' && text !== '') {
|
|
153
|
-
this.labels.set(this.labelKey(listName, lang, text), display);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/** The texts a stored value could have been indexed under. */
|
|
159
|
-
candidateTexts(value, lang) {
|
|
160
|
-
if (typeof value === 'object') {
|
|
161
|
-
const texts = Object.values(value).filter((v) => typeof v === 'string' && v !== '');
|
|
162
|
-
const resolved = resolveLabel(value, lang);
|
|
163
|
-
return resolved ? [resolved, ...texts] : texts;
|
|
164
|
-
}
|
|
165
|
-
return [String(value)];
|
|
166
|
-
}
|
|
167
|
-
// ─── Source coercion (values | loader, array | Promise | Observable) ─────────
|
|
168
|
-
invoke(source, lang) {
|
|
169
|
-
let result;
|
|
170
|
-
try {
|
|
171
|
-
result = typeof source === 'function' ? source({ lang }) : source;
|
|
172
|
-
}
|
|
173
|
-
catch (err) {
|
|
174
|
-
// Reject rather than resolve empty: `load` must be able to tell failure from an empty
|
|
175
|
-
// list, or it would cache the failure.
|
|
176
|
-
return Promise.reject(err);
|
|
177
|
-
}
|
|
178
|
-
return this.toPromise(result);
|
|
179
|
-
}
|
|
180
|
-
toPromise(result) {
|
|
181
|
-
if (Array.isArray(result))
|
|
182
|
-
return Promise.resolve(result);
|
|
183
|
-
if (this.isSubscribable(result)) {
|
|
184
|
-
// First emission wins, so a stream that stays open still resolves the load.
|
|
185
|
-
return new Promise((resolve, reject) => {
|
|
186
|
-
let settled = false;
|
|
187
|
-
const settle = (fn) => {
|
|
188
|
-
if (settled)
|
|
189
|
-
return;
|
|
190
|
-
settled = true;
|
|
191
|
-
fn();
|
|
192
|
-
};
|
|
193
|
-
result.subscribe({
|
|
194
|
-
next: value => settle(() => resolve(value ?? [])),
|
|
195
|
-
error: err => settle(() => reject(err)),
|
|
196
|
-
// Completing without emitting is a legitimate empty list, and is cached.
|
|
197
|
-
complete: () => settle(() => resolve([])),
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
return Promise.resolve(result);
|
|
202
|
-
}
|
|
203
|
-
isSubscribable(value) {
|
|
204
|
-
return (typeof value === 'object' &&
|
|
205
|
-
value !== null &&
|
|
206
|
-
typeof value.subscribe === 'function');
|
|
207
|
-
}
|
|
208
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookupRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
209
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookupRegistryService, providedIn: 'root' });
|
|
210
|
-
}
|
|
211
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookupRegistryService, decorators: [{
|
|
212
|
-
type: Injectable,
|
|
213
|
-
args: [{ providedIn: 'root' }]
|
|
214
|
-
}] });
|
|
215
|
-
const hostLastConfig = new WeakMap();
|
|
216
|
-
/**
|
|
217
|
-
* Point a choice component's `options` signal at the right source (parity plan §6.3).
|
|
218
|
-
*
|
|
219
|
-
* Called from the `field` / `language` input setters of `dropdown`, `radio` and `multiSelect` —
|
|
220
|
-
* the wiring is theirs, the decision is the service's, which is what keeps the field
|
|
221
|
-
* five-input contract intact: options are never pushed in as a sixth input.
|
|
222
|
-
*
|
|
223
|
-
* Setters rather than `ngOnChanges` on purpose. `ngOnChanges` only fires for inputs Angular
|
|
224
|
-
* itself sets, so a component whose `field` is assigned directly — which the field specs do,
|
|
225
|
-
* and any consumer holding a `ComponentRef` may do — would render no options at all.
|
|
226
|
-
*
|
|
227
|
-
* Paints synchronously first (inline options, or a warm list), then fills in when a cold list
|
|
228
|
-
* lands. The late result is dropped if the field or language changed while it was in flight.
|
|
229
|
-
*/
|
|
230
|
-
export function refreshChoiceOptions(host, lookups) {
|
|
231
|
-
const last = hostLastConfig.get(host);
|
|
232
|
-
if (last && last.field === host.field && last.lang === host.language) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
hostLastConfig.set(host, { field: host.field, lang: host.language });
|
|
236
|
-
host.options.set(lookups.optionsFor(host.field, host.language));
|
|
237
|
-
if (!lookups.needsResolve(host.field))
|
|
238
|
-
return;
|
|
239
|
-
const listName = host.field?.listName;
|
|
240
|
-
const lang = host.language;
|
|
241
|
-
void lookups.resolveOptions(host.field, host.language).then(options => {
|
|
242
|
-
if (host.field?.listName === listName && host.language === lang)
|
|
243
|
-
host.options.set(options);
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9va3VwLXJlZ2lzdHJ5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2xvb2t1cC1yZWdpc3RyeS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUF1QixNQUFNLGVBQWUsQ0FBQztBQVd4RSxPQUFPLEVBQUUscUJBQXFCLEVBQUUscUJBQXFCLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEcsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDOztBQUU3RCw4RkFBOEY7QUFDOUYsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDO0FBRWhCOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBRUgsTUFBTSxPQUFPLHFCQUFxQjtJQUNmLFFBQVEsR0FDdkIsTUFBTSxDQUFDLGVBQWUsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxJQUFJLElBQUksR0FBRyxFQUE0QixDQUFDO0lBRXJGLDJDQUEyQztJQUMxQixPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQTRCLENBQUM7SUFDL0QsZ0dBQWdHO0lBQy9FLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBNkIsQ0FBQztJQUMvRCx5Q0FBeUM7SUFDeEIsUUFBUSxHQUFHLElBQUksR0FBRyxFQUFxQyxDQUFDO0lBQ3pFLGdGQUFnRjtJQUMvRCxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7SUFFcEQsR0FBRyxDQUFDLFFBQWdCO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBZ0IsRUFBRSxJQUFJLEdBQUcsSUFBSTtRQUN0QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEs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QUFPO0lBRTlDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3RDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDM0IsS0FBSyxPQUFPLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRTtRQUNwRSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsUUFBUSxLQUFLLElBQUk7WUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM3RixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QsIHR5cGUgV3JpdGFibGVTaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHtcbiAgRHJvcGRvd25PcHRpb24sXG4gIExvb2t1cExpc3RMb2FkZXIsXG4gIExvb2t1cExpc3RSZXN1bHQsXG4gIExvb2t1cExpc3RTb3VyY2UsXG4gIExvb2t1cExpc3RWYWx1ZSxcbiAgTmVzdGVkRmllbGRDb25maWcsXG4gIFJhd0xvb2t1cExpc3RWYWx1ZSxcbiAgU3Vic2NyaWJhYmxlLFxufSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBsb29rdXBWYWx1ZXNUb09wdGlvbnMsIG5vcm1hbGl6ZUxvb2t1cFZhbHVlcywgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgTE9PS1VQX1JFR0lTVFJZIH0gZnJvbSAnLi4vdG9rZW5zL2luamVjdGlvbi10b2tlbnMnO1xuXG4vKiogQ2FjaGUta2V5IGZpZWxkIHNlcGFyYXRvci4gS2VwdCBvdXQgb2YgdGVtcGxhdGUgbGl0ZXJhbHMgc28gaXQgc3RheXMgdmlzaWJsZSBpbiBzb3VyY2UuICovXG5jb25zdCBTRVAgPSAnfCc7XG5cbi8qKlxuICogTG9va3VwUmVnaXN0cnlTZXJ2aWNlIOKAlCB0aGUgY2FjaGUgaW4gZnJvbnQgb2YgY29uc3VtZXItcmVnaXN0ZXJlZCBtYXN0ZXIgbGlzdHMuXG4gKlxuICogVGhyZWUgbGF5ZXJzLCBkZWxpYmVyYXRlbHkgdGhlIHNhbWUgc2hhcGUgYXMgYEVudGl0eVJlZmVyZW5jZVNlcnZpY2VgLCBiZWNhdXNlIHRoZSBwcm9ibGVtIGlzXG4gKiB0aGUgc2FtZTogb25lIGxpc3QgaXMgdHlwaWNhbGx5IHVzZWQgYnkgbWFueSBmaWVsZHMgYWNyb3NzIG1hbnkgZW50aXRpZXMuXG4gKiAgMS4gKipvcHRpb25zKiog4oCUIHJlc29sdmVkIGBEcm9wZG93bk9wdGlvbltdYCBwZXIgKGxpc3QgbmFtZSwgbGFuZykuXG4gKiAgMi4gKippbi1mbGlnaHQqKiDigJQgdGhlIHBlbmRpbmcgUHJvbWlzZSwgc28gTiBmaWVsZHMgb24gb25lIGxpc3QgdHJpZ2dlciBvbmUgbG9hZCwgbm90IE4uXG4gKiAgMy4gKipsYWJlbHMqKiDigJQgc3luY2hyb25vdXMgdmFsdWUg4oaSIHRleHQgKHBhcml0eSBwbGFuIMKnNi4yKS4gVGhpcyBpcyBub3QgYSBuaWNldHk6IHNpbmNlXG4gKiAgICAgYHZpZXdNb2RlYCBkZWZhdWx0cyB0byB0cnVlIGEgcmVjb3JkIG9wZW5zIHJlYWQtb25seSwgc28gcmVuZGVyaW5nIGEgc3RvcmVkIHZhbHVlIGFzXG4gKiAgICAgdGV4dCBpcyB0aGUgKmZpcnN0KiB0aGluZyBhIGBsaXN0TmFtZWAgZmllbGQgaGFzIHRvIGRvLiBBbiBhc3luYy1vbmx5IHJlZ2lzdHJ5IHdvdWxkXG4gKiAgICAgcGFpbnQgdGhlIHJhdyBzdG9yZWQgdmFsdWUgYW5kIHRoZW4gZmxpcCwgb24gZXZlcnkgcmVjb3JkIG9wZW4uXG4gKlxuICogQSBmYWlsZWQgbG9hZCByZWplY3RzIGFuZCBjYWNoZXMgbm90aGluZywgc28gb25lIHRyYW5zaWVudCBlcnJvciBkb2VzIG5vdCBzZXJ2ZSBhbiBlbXB0eVxuICogbGlzdCBmb3JldmVyIOKAlCB0aGUgc2FtZSBmaXggbWFkZSBmb3IgZW50aXR5IHJlZmVyZW5jZXMgaW4gcGhhc2UgNS5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBMb29rdXBSZWdpc3RyeVNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lzdHJ5ID1cbiAgICBpbmplY3QoTE9PS1VQX1JFR0lTVFJZLCB7IG9wdGlvbmFsOiB0cnVlIH0pID8/IG5ldyBNYXA8c3RyaW5nLCBMb29rdXBMaXN0U291cmNlPigpO1xuXG4gIC8qKiBgbGlzdE5hbWV8bGFuZ2AgLT4gcmVzb2x2ZWQgb3B0aW9ucy4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zID0gbmV3IE1hcDxzdHJpbmcsIERyb3Bkb3duT3B0aW9uW10+KCk7XG4gIC8qKiBgbGlzdE5hbWV8bGFuZ2AgLT4gbm9ybWFsaXNlZCB2YWx1ZXMsIHNvIGEgY29uc3VtZXIgY2FuIHJlYWNoIGBjb2RlYCAvIGBpc1N5c3RlbURlZmluZWRgLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHZhbHVlcyA9IG5ldyBNYXA8c3RyaW5nLCBMb29rdXBMaXN0VmFsdWVbXT4oKTtcbiAgLyoqIExvYWRzIGluIHByb2dyZXNzLCBrZXllZCBhcyBhYm92ZS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpbkZsaWdodCA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPERyb3Bkb3duT3B0aW9uW10+PigpO1xuICAvKiogYGxpc3ROYW1lfGxhbmd8dGV4dGAgLT4gZGlzcGxheSB0ZXh0LCBmb3IgdGhlIHN5bmNocm9ub3VzIHJlYWQtb25seSBwYXRoLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGxhYmVscyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG5cbiAgaGFzKGxpc3ROYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5yZWdpc3RyeS5oYXMobGlzdE5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIGEgbmFtZWQgbGlzdCwgZnJvbSBjYWNoZSB3aGVuIHByZXNlbnQuXG4gICAqIENvbmN1cnJlbnQgY2FsbGVycyB3aXRoIHRoZSBzYW1lIGtleSBzaGFyZSBvbmUgbG9hZC5cbiAgICovXG4gIGFzeW5jIGxvYWQobGlzdE5hbWU6IHN0cmluZywgbGFuZyA9ICdlbicpOiBQcm9taXNlPERyb3Bkb3duT3B0aW9uW10+IHtcbiAgICBjb25zdCBrZXkgPSB0aGlzLmNhY2hlS2V5KGxpc3ROYW1lLCBsYW5nKTtcblxuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMub3B0aW9ucy5nZXQoa2V5KTtcbiAgICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuXG4gICAgY29uc3QgcGVuZGluZyA9IHRoaXMuaW5GbGlnaHQuZ2V0KGtleSk7XG4gICAgaWYgKHBlbmRpbmcpIHJldHVybiBwZW5kaW5nO1xuXG4gICAgY29uc3Qgc291cmNlID0gdGhpcy5yZWdpc3RyeS5nZXQobGlzdE5hbWUpO1xuICAgIGlmIChzb3VyY2UgPT09IHVuZGVmaW5lZCkgcmV0dXJuIFtdO1xuXG4gICAgY29uc3QgbG9hZCA9IHRoaXMuaW52b2tlKHNvdXJjZSwgbGFuZykudGhlbihyYXcgPT4ge1xuICAgICAgY29uc3QgdmFsdWVzID0gbm9ybWFsaXplTG9va3VwVmFsdWVzKHJhdyk7XG4gICAgICBjb25zdCBvcHRpb25zID0gbG9va3VwVmFsdWVzVG9PcHRpb25zKHZhbHVlcyk7XG4gICAgICB0aGlzLnZhbHVlcy5zZXQoa2V5LCB2YWx1ZXMpO1xuICAgICAgdGhpcy5vcHRpb25zLnNldChrZXksIG9wdGlvbnMpO1xuICAgICAgdGhpcy5yZW1lbWJlckxhYmVscyhsaXN0TmFtZSwgbGFuZywgb3B0aW9ucyk7XG4gICAgICByZXR1cm4gb3B0aW9ucztcbiAgICB9KTtcblxuICAgIC8vIE9ubHkgdGhlIGAudGhlbmAgYWJvdmUgd3JpdGVzIHRvIHRoZSBjYWNoZSwgYW5kIGEgcmVqZWN0aW9uIHNraXBzIGl0OiB0aGUgY2FsbGVyIHN0aWxsXG4gICAgLy8gZ2V0cyBhbiBlbXB0eSBsaXN0LCBidXQgdGhlIG5leHQgY2FsbCByZXRyaWVzIGluc3RlYWQgb2YgcmVhZGluZyBhIHBvaXNvbmVkIGVudHJ5LlxuICAgIGNvbnN0IGd1YXJkZWQgPSBsb2FkXG4gICAgICAuY2F0Y2goKCkgPT4gW10gYXMgRHJvcGRvd25PcHRpb25bXSlcbiAgICAgIC5maW5hbGx5KCgpID0+IHRoaXMuaW5GbGlnaHQuZGVsZXRlKGtleSkpO1xuXG4gICAgdGhpcy5pbkZsaWdodC5zZXQoa2V5LCBndWFyZGVkKTtcbiAgICByZXR1cm4gZ3VhcmRlZDtcbiAgfVxuXG4gIC8qKiBDYWNoZWQgb3B0aW9ucyB3aXRob3V0IHRyaWdnZXJpbmcgYSBsb2FkLiBgdW5kZWZpbmVkYCB3aGVuIG5vdCBsb2FkZWQuICovXG4gIHBlZWsobGlzdE5hbWU6IHN0cmluZywgbGFuZyA9ICdlbicpOiBEcm9wZG93bk9wdGlvbltdIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLmdldCh0aGlzLmNhY2hlS2V5KGxpc3ROYW1lLCBsYW5nKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FjaGVkIGxpc3QgdmFsdWVzLCBjYXJyeWluZyBgX2lkYCwgYGNvZGVgLCBgaXNTeXN0ZW1EZWZpbmVkYCBhbmQgYGZyb21gLlxuICAgKiBUaGUgbGlicmFyeSBuZXZlciByZWFkcyB0aG9zZTsgdGhpcyBpcyB0aGUgc2VhbSBmb3IgYSBjb25zdW1lciB0aGF0IG5lZWRzIHRoZW0uXG4gICAqL1xuICB2YWx1ZXNGb3IobGlzdE5hbWU6IHN0cmluZywgbGFuZyA9ICdlbicpOiBMb29rdXBMaXN0VmFsdWVbXSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMudmFsdWVzLmdldCh0aGlzLmNhY2hlS2V5KGxpc3ROYW1lLCBsYW5nKSk7XG4gIH1cblxuICAvKipcbiAgICogRGlzcGxheSB0ZXh0IGZvciBhIHN0b3JlZCB2YWx1ZSwgc3luY2hyb25vdXNseS4gYHVuZGVmaW5lZGAgd2hlbiB0aGUgbGlzdCBoYXMgbm90IGxvYWRlZFxuICAgKiBvciBob2xkcyBubyBtYXRjaGluZyB2YWx1ZSDigJQgdGhlIGNhbGxlciBrZWVwcyBpdHMgb3duIGZhbGxiYWNrLCB3aGljaCBpcyB0aGUgc3RvcmVkIHRleHQuXG4gICAqXG4gICAqIEV2ZXJ5IGxhbmd1YWdlIG9mIGFuIG9wdGlvbiBpcyBpbmRleGVkLCBzbyBhIHJlY29yZCBzYXZlZCB1bmRlciBvbmUgbGFuZ3VhZ2UgcmVuZGVycyBpblxuICAgKiBhbm90aGVyOiBhIHZhbHVlIHN0b3JlZCBhcyBgJ0FrdGl2J2AgcmVzb2x2ZXMgdG8gYCdBY3RpdmUnYCB1bmRlciBgbGFuZzogJ2VuJ2AuXG4gICAqL1xuICBsYWJlbEZvcihsaXN0TmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLCB2YWx1ZTogdW5rbm93biwgbGFuZyA9ICdlbicpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghbGlzdE5hbWUgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gJycpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgZm9yIChjb25zdCB0ZXh0IG9mIHRoaXMuY2FuZGlkYXRlVGV4dHModmFsdWUsIGxhbmcpKSB7XG4gICAgICBjb25zdCBoaXQgPSB0aGlzLmxhYmVscy5nZXQodGhpcy5sYWJlbEtleShsaXN0TmFtZSwgbGFuZywgdGV4dCkpO1xuICAgICAgaWYgKGhpdCkgcmV0dXJuIGhpdDtcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBGaWVsZC1sZXZlbCByZXNvbHV0aW9uIOKAlCBpbmxpbmUgb3B0aW9ucyB3aW4sIGVsc2UgYGxpc3ROYW1lYCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogVHJ1ZSB3aGVuIHRoaXMgZmllbGQncyBvcHRpb25zIGhhdmUgdG8gY29tZSBmcm9tIHRoZSByZWdpc3RyeS4gKi9cbiAgbmVlZHNSZXNvbHZlKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIWZpZWxkPy5saXN0TmFtZSAmJiAhZmllbGQub3B0aW9ucz8ubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBvcHRpb25zIHRvIHJlbmRlciByaWdodCBub3csIHdpdGhvdXQgYXdhaXRpbmc6IGlubGluZSBvcHRpb25zLCBlbHNlIHdoYXRldmVyIHRoZVxuICAgKiByZWdpc3RyeSBhbHJlYWR5IGhvbGRzLiBFbXB0eSBvbiBhIGNvbGQgbWlzcyDigJQgcGFpciB3aXRoIGByZXNvbHZlT3B0aW9uc2AuXG4gICAqL1xuICBvcHRpb25zRm9yKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyB8IHVuZGVmaW5lZCwgbGFuZyA9ICdlbicpOiBEcm9wZG93bk9wdGlvbltdIHtcbiAgICBpZiAoIWZpZWxkKSByZXR1cm4gW107XG4gICAgaWYgKGZpZWxkLm9wdGlvbnM/Lmxlbmd0aCkgcmV0dXJuIGZpZWxkLm9wdGlvbnM7XG4gICAgaWYgKCFmaWVsZC5saXN0TmFtZSkgcmV0dXJuIFtdO1xuICAgIHJldHVybiB0aGlzLnBlZWsoZmllbGQubGlzdE5hbWUsIGxhbmcpID8/IFtdO1xuICB9XG5cbiAgLyoqIFRoZSBvcHRpb25zIGZvciBhIGZpZWxkLCBsb2FkaW5nIHRoZSBuYW1lZCBsaXN0IGlmIG5lZWRlZC4gKi9cbiAgcmVzb2x2ZU9wdGlvbnMoZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnIHwgdW5kZWZpbmVkLCBsYW5nID0gJ2VuJyk6IFByb21pc2U8RHJvcGRvd25PcHRpb25bXT4ge1xuICAgIGlmICghdGhpcy5uZWVkc1Jlc29sdmUoZmllbGQpKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMub3B0aW9uc0ZvcihmaWVsZCwgbGFuZykpO1xuICAgIHJldHVybiB0aGlzLmxvYWQoZmllbGQhLmxpc3ROYW1lISwgbGFuZyk7XG4gIH1cblxuICAvKiogRHJvcCBldmVyeXRoaW5nIGNhY2hlZCBmb3Igb25lIGxpc3QsIGxlYXZpbmcgb3RoZXIgbGlzdHMgaW50YWN0LiAqL1xuICBpbnZhbGlkYXRlKGxpc3ROYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBwcmVmaXggPSBgJHtsaXN0TmFtZX0ke1NFUH1gO1xuICAgIGZvciAoY29uc3QgbWFwIG9mIFt0aGlzLm9wdGlvbnMsIHRoaXMudmFsdWVzLCB0aGlzLmluRmxpZ2h0XSkge1xuICAgICAgZm9yIChjb25zdCBrZXkgb2YgWy4uLm1hcC5rZXlzKCldKSB7XG4gICAgICAgIGlmIChrZXkuc3RhcnRzV2l0aChwcmVmaXgpKSBtYXAuZGVsZXRlKGtleSk7XG4gICAgICB9XG4gICAgfVxuICAgIGZvciAoY29uc3Qga2V5IG9mIFsuLi50aGlzLmxhYmVscy5rZXlzKCldKSB7XG4gICAgICBpZiAoa2V5LnN0YXJ0c1dpdGgocHJlZml4KSkgdGhpcy5sYWJlbHMuZGVsZXRlKGtleSk7XG4gICAgfVxuICB9XG5cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5vcHRpb25zLmNsZWFyKCk7XG4gICAgdGhpcy52YWx1ZXMuY2xlYXIoKTtcbiAgICB0aGlzLmluRmxpZ2h0LmNsZWFyKCk7XG4gICAgdGhpcy5sYWJlbHMuY2xlYXIoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBJbnRlcm5hbHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBjYWNoZUtleShsaXN0TmFtZTogc3RyaW5nLCBsYW5nOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBbbGlzdE5hbWUsIGxhbmddLmpvaW4oU0VQKTtcbiAgfVxuXG4gIHByaXZhdGUgbGFiZWxLZXkobGlzdE5hbWU6IHN0cmluZywgbGFuZzogc3RyaW5nLCB0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBbbGlzdE5hbWUsIGxhbmcsIHRleHRdLmpvaW4oU0VQKTtcbiAgfVxuXG4gIC8qKiBJbmRleCBhbiBvcHRpb24gdW5kZXIgZXZlcnkgbGFuZ3VhZ2UgaXQgY2Fycmllcywgc28gYW55IHN0b3JlZCBzcGVsbGluZyBmaW5kcyBpdC4gKi9cbiAgcHJpdmF0ZSByZW1lbWJlckxhYmVscyhsaXN0TmFtZTogc3RyaW5nLCBsYW5nOiBzdHJpbmcsIG9wdGlvbnM6IERyb3Bkb3duT3B0aW9uW10pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IG9wdGlvbiBvZiBvcHRpb25zKSB7XG4gICAgICBjb25zdCBkaXNwbGF5ID0gcmVzb2x2ZUxhYmVsKG9wdGlvbiwgbGFuZyk7XG4gICAgICBpZiAoIWRpc3BsYXkpIGNvbnRpbnVlO1xuICAgICAgZm9yIChjb25zdCB0ZXh0IG9mIE9iamVjdC52YWx1ZXMob3B0aW9uKSkge1xuICAgICAgICBpZiAodHlwZW9mIHRleHQgPT09ICdzdHJpbmcnICYmIHRleHQgIT09ICcnKSB7XG4gICAgICAgICAgdGhpcy5sYWJlbHMuc2V0KHRoaXMubGFiZWxLZXkobGlzdE5hbWUsIGxhbmcsIHRleHQpLCBkaXNwbGF5KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBUaGUgdGV4dHMgYSBzdG9yZWQgdmFsdWUgY291bGQgaGF2ZSBiZWVuIGluZGV4ZWQgdW5kZXIuICovXG4gIHByaXZhdGUgY2FuZGlkYXRlVGV4dHModmFsdWU6IHVua25vd24sIGxhbmc6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnb2JqZWN0Jykge1xuICAgICAgY29uc3QgdGV4dHMgPSBPYmplY3QudmFsdWVzKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5maWx0ZXIoXG4gICAgICAgICh2KTogdiBpcyBzdHJpbmcgPT4gdHlwZW9mIHYgPT09ICdzdHJpbmcnICYmIHYgIT09ICcnLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZUxhYmVsKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHN0cmluZz4sIGxhbmcpO1xuICAgICAgcmV0dXJuIHJlc29sdmVkID8gW3Jlc29sdmVkLCAuLi50ZXh0c10gOiB0ZXh0cztcbiAgICB9XG4gICAgcmV0dXJuIFtTdHJpbmcodmFsdWUpXTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBTb3VyY2UgY29lcmNpb24gKHZhbHVlcyB8IGxvYWRlciwgYXJyYXkgfCBQcm9taXNlIHwgT2JzZXJ2YWJsZSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBpbnZva2Uoc291cmNlOiBMb29rdXBMaXN0U291cmNlLCBsYW5nOiBzdHJpbmcpOiBQcm9taXNlPFJhd0xvb2t1cExpc3RWYWx1ZVtdPiB7XG4gICAgbGV0IHJlc3VsdDogTG9va3VwTGlzdFJlc3VsdDtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gdHlwZW9mIHNvdXJjZSA9PT0gJ2Z1bmN0aW9uJyA/IChzb3VyY2UgYXMgTG9va3VwTGlzdExvYWRlcikoeyBsYW5nIH0pIDogc291cmNlO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gUmVqZWN0IHJhdGhlciB0aGFuIHJlc29sdmUgZW1wdHk6IGBsb2FkYCBtdXN0IGJlIGFibGUgdG8gdGVsbCBmYWlsdXJlIGZyb20gYW4gZW1wdHlcbiAgICAgIC8vIGxpc3QsIG9yIGl0IHdvdWxkIGNhY2hlIHRoZSBmYWlsdXJlLlxuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGVycik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnRvUHJvbWlzZShyZXN1bHQpO1xuICB9XG5cbiAgcHJpdmF0ZSB0b1Byb21pc2UocmVzdWx0OiBMb29rdXBMaXN0UmVzdWx0KTogUHJvbWlzZTxSYXdMb29rdXBMaXN0VmFsdWVbXT4ge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHJlc3VsdCkpIHJldHVybiBQcm9taXNlLnJlc29sdmUocmVzdWx0KTtcbiAgICBpZiAodGhpcy5pc1N1YnNjcmliYWJsZShyZXN1bHQpKSB7XG4gICAgICAvLyBGaXJzdCBlbWlzc2lvbiB3aW5zLCBzbyBhIHN0cmVhbSB0aGF0IHN0YXlzIG9wZW4gc3RpbGwgcmVzb2x2ZXMgdGhlIGxvYWQuXG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8UmF3TG9va3VwTGlzdFZhbHVlW10+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgbGV0IHNldHRsZWQgPSBmYWxzZTtcbiAgICAgICAgY29uc3Qgc2V0dGxlID0gKGZuOiAoKSA9PiB2b2lkKSA9PiB7XG4gICAgICAgICAgaWYgKHNldHRsZWQpIHJldHVybjtcbiAgICAgICAgICBzZXR0bGVkID0gdHJ1ZTtcbiAgICAgICAgICBmbigpO1xuICAgICAgICB9O1xuICAgICAgICByZXN1bHQuc3Vic2NyaWJlKHtcbiAgICAgICAgICBuZXh0OiB2YWx1ZSA9PiBzZXR0bGUoKCkgPT4gcmVzb2x2ZSh2YWx1ZSA/PyBbXSkpLFxuICAgICAgICAgIGVycm9yOiBlcnIgPT4gc2V0dGxlKCgpID0+IHJlamVjdChlcnIpKSxcbiAgICAgICAgICAvLyBDb21wbGV0aW5nIHdpdGhvdXQgZW1pdHRpbmcgaXMgYSBsZWdpdGltYXRlIGVtcHR5IGxpc3QsIGFuZCBpcyBjYWNoZWQuXG4gICAgICAgICAgY29tcGxldGU6ICgpID0+IHNldHRsZSgoKSA9PiByZXNvbHZlKFtdKSksXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUocmVzdWx0IGFzIFByb21pc2U8UmF3TG9va3VwTGlzdFZhbHVlW10+KTtcbiAgfVxuXG4gIHByaXZhdGUgaXNTdWJzY3JpYmFibGUodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBTdWJzY3JpYmFibGU8UmF3TG9va3VwTGlzdFZhbHVlW10+IHtcbiAgICByZXR1cm4gKFxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJlxuICAgICAgdmFsdWUgIT09IG51bGwgJiZcbiAgICAgIHR5cGVvZiAodmFsdWUgYXMgU3Vic2NyaWJhYmxlPFJhd0xvb2t1cExpc3RWYWx1ZVtdPikuc3Vic2NyaWJlID09PSAnZnVuY3Rpb24nXG4gICAgKTtcbiAgfVxufVxuXG4vKiogQSBjaG9pY2UgZmllbGQgY29tcG9uZW50LCBhcyBmYXIgYXMgb3B0aW9uIHJlc29sdXRpb24gaXMgY29uY2VybmVkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBDaG9pY2VPcHRpb25Ib3N0IHtcbiAgcmVhZG9ubHkgZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnIHwgdW5kZWZpbmVkO1xuICByZWFkb25seSBsYW5ndWFnZTogc3RyaW5nO1xuICByZWFkb25seSBvcHRpb25zOiBXcml0YWJsZVNpZ25hbDxEcm9wZG93bk9wdGlvbltdPjtcbn1cblxuY29uc3QgaG9zdExhc3RDb25maWcgPSBuZXcgV2Vha01hcDxDaG9pY2VPcHRpb25Ib3N0LCB7IGZpZWxkPzogTmVzdGVkRmllbGRDb25maWc7IGxhbmc/OiBzdHJpbmcgfT4oKTtcblxuLyoqXG4gKiBQb2ludCBhIGNob2ljZSBjb21wb25lbnQncyBgb3B0aW9uc2Agc2lnbmFsIGF0IHRoZSByaWdodCBzb3VyY2UgKHBhcml0eSBwbGFuIMKnNi4zKS5cbiAqXG4gKiBDYWxsZWQgZnJvbSB0aGUgYGZpZWxkYCAvIGBsYW5ndWFnZWAgaW5wdXQgc2V0dGVycyBvZiBgZHJvcGRvd25gLCBgcmFkaW9gIGFuZCBgbXVsdGlTZWxlY3RgIOKAlFxuICogdGhlIHdpcmluZyBpcyB0aGVpcnMsIHRoZSBkZWNpc2lvbiBpcyB0aGUgc2VydmljZSdzLCB3aGljaCBpcyB3aGF0IGtlZXBzIHRoZSBmaWVsZFxuICogZml2ZS1pbnB1dCBjb250cmFjdCBpbnRhY3Q6IG9wdGlvbnMgYXJlIG5ldmVyIHB1c2hlZCBpbiBhcyBhIHNpeHRoIGlucHV0LlxuICpcbiAqIFNldHRlcnMgcmF0aGVyIHRoYW4gYG5nT25DaGFuZ2VzYCBvbiBwdXJwb3NlLiBgbmdPbkNoYW5nZXNgIG9ubHkgZmlyZXMgZm9yIGlucHV0cyBBbmd1bGFyXG4gKiBpdHNlbGYgc2V0cywgc28gYSBjb21wb25lbnQgd2hvc2UgYGZpZWxkYCBpcyBhc3NpZ25lZCBkaXJlY3RseSDigJQgd2hpY2ggdGhlIGZpZWxkIHNwZWNzIGRvLFxuICogYW5kIGFueSBjb25zdW1lciBob2xkaW5nIGEgYENvbXBvbmVudFJlZmAgbWF5IGRvIOKAlCB3b3VsZCByZW5kZXIgbm8gb3B0aW9ucyBhdCBhbGwuXG4gKlxuICogUGFpbnRzIHN5bmNocm9ub3VzbHkgZmlyc3QgKGlubGluZSBvcHRpb25zLCBvciBhIHdhcm0gbGlzdCksIHRoZW4gZmlsbHMgaW4gd2hlbiBhIGNvbGQgbGlzdFxuICogbGFuZHMuIFRoZSBsYXRlIHJlc3VsdCBpcyBkcm9wcGVkIGlmIHRoZSBmaWVsZCBvciBsYW5ndWFnZSBjaGFuZ2VkIHdoaWxlIGl0IHdhcyBpbiBmbGlnaHQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWZyZXNoQ2hvaWNlT3B0aW9ucyhob3N0OiBDaG9pY2VPcHRpb25Ib3N0LCBsb29rdXBzOiBMb29rdXBSZWdpc3RyeVNlcnZpY2UpOiB2b2lkIHtcbiAgY29uc3QgbGFzdCA9IGhvc3RMYXN0Q29uZmlnLmdldChob3N0KTtcbiAgaWYgKGxhc3QgJiYgbGFzdC5maWVsZCA9PT0gaG9zdC5maWVsZCAmJiBsYXN0LmxhbmcgPT09IGhvc3QubGFuZ3VhZ2UpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgaG9zdExhc3RDb25maWcuc2V0KGhvc3QsIHsgZmllbGQ6IGhvc3QuZmllbGQsIGxhbmc6IGhvc3QubGFuZ3VhZ2UgfSk7XG5cbiAgaG9zdC5vcHRpb25zLnNldChsb29rdXBzLm9wdGlvbnNGb3IoaG9zdC5maWVsZCwgaG9zdC5sYW5ndWFnZSkpO1xuICBpZiAoIWxvb2t1cHMubmVlZHNSZXNvbHZlKGhvc3QuZmllbGQpKSByZXR1cm47XG5cbiAgY29uc3QgbGlzdE5hbWUgPSBob3N0LmZpZWxkPy5saXN0TmFtZTtcbiAgY29uc3QgbGFuZyA9IGhvc3QubGFuZ3VhZ2U7XG4gIHZvaWQgbG9va3Vwcy5yZXNvbHZlT3B0aW9ucyhob3N0LmZpZWxkLCBob3N0Lmxhbmd1YWdlKS50aGVuKG9wdGlvbnMgPT4ge1xuICAgIGlmIChob3N0LmZpZWxkPy5saXN0TmFtZSA9PT0gbGlzdE5hbWUgJiYgaG9zdC5sYW5ndWFnZSA9PT0gbGFuZykgaG9zdC5vcHRpb25zLnNldChvcHRpb25zKTtcbiAgfSk7XG59XG4iXX0=
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { shouldMaskField as coreShouldMaskField, resolveEffectiveMask as coreResolveEffectiveMask } from '@dynamic-entity/core';
|
|
3
|
-
import { MASKED_ROLES } from '../tokens/injection-tokens';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
/**
|
|
6
|
-
* RbacService — ALL permission checks and masking logic live here.
|
|
7
|
-
*/
|
|
8
|
-
export class RbacService {
|
|
9
|
-
maskedRoles = inject(MASKED_ROLES, { optional: true }) ?? [];
|
|
10
|
-
/**
|
|
11
|
-
* Check if any of the user's roles satisfy the required roles.
|
|
12
|
-
* hasPermission(roles, undefined) → true (no restriction).
|
|
13
|
-
*/
|
|
14
|
-
hasPermission(userRoles, requiredRoles) {
|
|
15
|
-
if (!requiredRoles?.length)
|
|
16
|
-
return true;
|
|
17
|
-
return userRoles.some(r => requiredRoles.includes(r));
|
|
18
|
-
}
|
|
19
|
-
/** 3-level OR resolution */
|
|
20
|
-
resolveEffectiveMask(formMask, tabMask, fieldMask) {
|
|
21
|
-
return coreResolveEffectiveMask(formMask, tabMask, fieldMask);
|
|
22
|
-
}
|
|
23
|
-
/** Check if the user's roles include any masked role */
|
|
24
|
-
isUserMaskedRole(userRoles) {
|
|
25
|
-
return this.maskedRoles.some(r => userRoles.includes(r));
|
|
26
|
-
}
|
|
27
|
-
/** Determine if a specific field should be masked for this user */
|
|
28
|
-
shouldMaskField(field, tab, config, userRoles) {
|
|
29
|
-
return coreShouldMaskField(field, tab, config, userRoles, this.maskedRoles);
|
|
30
|
-
}
|
|
31
|
-
/** Get view/edit/delete permissions for a config */
|
|
32
|
-
getPermissions(config, userRoles) {
|
|
33
|
-
return {
|
|
34
|
-
canView: this.hasPermission(userRoles, config.permissions?.view),
|
|
35
|
-
canEdit: this.hasPermission(userRoles, config.permissions?.edit),
|
|
36
|
-
canDelete: this.hasPermission(userRoles, config.permissions?.delete),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RbacService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
40
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RbacService, providedIn: 'root' });
|
|
41
|
-
}
|
|
42
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RbacService, decorators: [{
|
|
43
|
-
type: Injectable,
|
|
44
|
-
args: [{ providedIn: 'root' }]
|
|
45
|
-
}] });
|
|
46
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmJhYy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9yYmFjLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFbkQsT0FBTyxFQUFFLGVBQWUsSUFBSSxtQkFBbUIsRUFBRSxvQkFBb0IsSUFBSSx3QkFBd0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2hJLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7QUFFMUQ7O0dBRUc7QUFFSCxNQUFNLE9BQU8sV0FBVztJQUNMLFdBQVcsR0FBRyxNQUFNLENBQUMsWUFBWSxFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDO0lBRTlFOzs7T0FHRztJQUNILGFBQWEsQ0FBQyxTQUFtQixFQUFFLGFBQXdCO1FBQ3pELElBQUksQ0FBQyxhQUFhLEVBQUUsTUFBTTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3hDLE9BQU8sU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsNEJBQTRCO0lBQzVCLG9CQUFvQixDQUFDLFFBQWtCLEVBQUUsT0FBaUIsRUFBRSxTQUFtQjtRQUM3RSxPQUFPLHdCQUF3QixDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVELHdEQUF3RDtJQUN4RCxnQkFBZ0IsQ0FBQyxTQUFtQjtRQUNsQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFFRCxtRUFBbUU7SUFDbkUsZUFBZSxDQUFDLEtBQXdCLEVBQUUsR0FBZ0MsRUFBRSxNQUF3QixFQUFFLFNBQW1CO1FBQ3ZILE9BQU8sbUJBQW1CLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBRUQsb0RBQW9EO0lBQ3BELGNBQWMsQ0FBQyxNQUF3QixFQUFFLFNBQW1CO1FBQzFELE9BQU87WUFDTCxPQUFPLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUM7WUFDaEUsT0FBTyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDO1lBQ2hFLFNBQVMsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQztTQUNyRSxDQUFDO0lBQ0osQ0FBQzt3R0FsQ1UsV0FBVzs0R0FBWCxXQUFXLGNBREUsTUFBTTs7NEZBQ25CLFdBQVc7a0JBRHZCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IEVudGl0eUZvcm1Db25maWcsIE5lc3RlZEZpZWxkQ29uZmlnLCBOZXN0ZWRUYWJDb25maWcgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBzaG91bGRNYXNrRmllbGQgYXMgY29yZVNob3VsZE1hc2tGaWVsZCwgcmVzb2x2ZUVmZmVjdGl2ZU1hc2sgYXMgY29yZVJlc29sdmVFZmZlY3RpdmVNYXNrIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgTUFTS0VEX1JPTEVTIH0gZnJvbSAnLi4vdG9rZW5zL2luamVjdGlvbi10b2tlbnMnO1xuXG4vKipcbiAqIFJiYWNTZXJ2aWNlIOKAlCBBTEwgcGVybWlzc2lvbiBjaGVja3MgYW5kIG1hc2tpbmcgbG9naWMgbGl2ZSBoZXJlLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFJiYWNTZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBtYXNrZWRSb2xlcyA9IGluamVjdChNQVNLRURfUk9MRVMsIHsgb3B0aW9uYWw6IHRydWUgfSkgPz8gW107XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGFueSBvZiB0aGUgdXNlcidzIHJvbGVzIHNhdGlzZnkgdGhlIHJlcXVpcmVkIHJvbGVzLlxuICAgKiBoYXNQZXJtaXNzaW9uKHJvbGVzLCB1bmRlZmluZWQpIOKGkiB0cnVlIChubyByZXN0cmljdGlvbikuXG4gICAqL1xuICBoYXNQZXJtaXNzaW9uKHVzZXJSb2xlczogc3RyaW5nW10sIHJlcXVpcmVkUm9sZXM/OiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGlmICghcmVxdWlyZWRSb2xlcz8ubGVuZ3RoKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gdXNlclJvbGVzLnNvbWUociA9PiByZXF1aXJlZFJvbGVzLmluY2x1ZGVzKHIpKTtcbiAgfVxuXG4gIC8qKiAzLWxldmVsIE9SIHJlc29sdXRpb24gKi9cbiAgcmVzb2x2ZUVmZmVjdGl2ZU1hc2soZm9ybU1hc2s/OiBib29sZWFuLCB0YWJNYXNrPzogYm9vbGVhbiwgZmllbGRNYXNrPzogYm9vbGVhbik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBjb3JlUmVzb2x2ZUVmZmVjdGl2ZU1hc2soZm9ybU1hc2ssIHRhYk1hc2ssIGZpZWxkTWFzayk7XG4gIH1cblxuICAvKiogQ2hlY2sgaWYgdGhlIHVzZXIncyByb2xlcyBpbmNsdWRlIGFueSBtYXNrZWQgcm9sZSAqL1xuICBpc1VzZXJNYXNrZWRSb2xlKHVzZXJSb2xlczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5tYXNrZWRSb2xlcy5zb21lKHIgPT4gdXNlclJvbGVzLmluY2x1ZGVzKHIpKTtcbiAgfVxuXG4gIC8qKiBEZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBmaWVsZCBzaG91bGQgYmUgbWFza2VkIGZvciB0aGlzIHVzZXIgKi9cbiAgc2hvdWxkTWFza0ZpZWxkKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZywgdGFiOiBOZXN0ZWRUYWJDb25maWcgfCB1bmRlZmluZWQsIGNvbmZpZzogRW50aXR5Rm9ybUNvbmZpZywgdXNlclJvbGVzOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBjb3JlU2hvdWxkTWFza0ZpZWxkKGZpZWxkLCB0YWIsIGNvbmZpZywgdXNlclJvbGVzLCB0aGlzLm1hc2tlZFJvbGVzKTtcbiAgfVxuXG4gIC8qKiBHZXQgdmlldy9lZGl0L2RlbGV0ZSBwZXJtaXNzaW9ucyBmb3IgYSBjb25maWcgKi9cbiAgZ2V0UGVybWlzc2lvbnMoY29uZmlnOiBFbnRpdHlGb3JtQ29uZmlnLCB1c2VyUm9sZXM6IHN0cmluZ1tdKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNhblZpZXc6IHRoaXMuaGFzUGVybWlzc2lvbih1c2VyUm9sZXMsIGNvbmZpZy5wZXJtaXNzaW9ucz8udmlldyksXG4gICAgICBjYW5FZGl0OiB0aGlzLmhhc1Blcm1pc3Npb24odXNlclJvbGVzLCBjb25maWcucGVybWlzc2lvbnM/LmVkaXQpLFxuICAgICAgY2FuRGVsZXRlOiB0aGlzLmhhc1Blcm1pc3Npb24odXNlclJvbGVzLCBjb25maWcucGVybWlzc2lvbnM/LmRlbGV0ZSksXG4gICAgfTtcbiAgfVxufVxuIl19
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
2
|
-
import { evaluateFormRules, filterRulesForTab } from '@dynamic-entity/core';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/**
|
|
5
|
-
* RulesEvaluationService — evaluates dynamic form rules against active reactive form state.
|
|
6
|
-
*/
|
|
7
|
-
export class RulesEvaluationService {
|
|
8
|
-
/**
|
|
9
|
-
* Evaluate rules against form values and optional original baseline values.
|
|
10
|
-
*/
|
|
11
|
-
evaluate(rules, values, originalValues) {
|
|
12
|
-
return evaluateFormRules(rules, values, originalValues);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Filter rules pertinent to a single tab.
|
|
16
|
-
*/
|
|
17
|
-
filterForTab(rules, tabId, config) {
|
|
18
|
-
return filterRulesForTab(rules, tabId, config);
|
|
19
|
-
}
|
|
20
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RulesEvaluationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
21
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RulesEvaluationService, providedIn: 'root' });
|
|
22
|
-
}
|
|
23
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RulesEvaluationService, decorators: [{
|
|
24
|
-
type: Injectable,
|
|
25
|
-
args: [{ providedIn: 'root' }]
|
|
26
|
-
}] });
|
|
27
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVsZXMtZXZhbHVhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9ydWxlcy1ldmFsdWF0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7QUFFNUU7O0dBRUc7QUFFSCxNQUFNLE9BQU8sc0JBQXNCO0lBQ2pDOztPQUVHO0lBQ0gsUUFBUSxDQUNOLEtBQW9DLEVBQ3BDLE1BQStCLEVBQy9CLGNBQXdDO1FBRXhDLE9BQU8saUJBQWlCLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxZQUFZLENBQUMsS0FBb0MsRUFBRSxLQUFhLEVBQUUsTUFBd0I7UUFDeEYsT0FBTyxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2pELENBQUM7d0dBakJVLHNCQUFzQjs0R0FBdEIsc0JBQXNCLGNBRFQsTUFBTTs7NEZBQ25CLHNCQUFzQjtrQkFEbEMsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IEVudGl0eUZvcm1Db25maWcsIEZvcm1SdWxlLCBSdWxlRXZhbHVhdGlvblJlc3VsdCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IGV2YWx1YXRlRm9ybVJ1bGVzLCBmaWx0ZXJSdWxlc0ZvclRhYiB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcblxuLyoqXG4gKiBSdWxlc0V2YWx1YXRpb25TZXJ2aWNlIOKAlCBldmFsdWF0ZXMgZHluYW1pYyBmb3JtIHJ1bGVzIGFnYWluc3QgYWN0aXZlIHJlYWN0aXZlIGZvcm0gc3RhdGUuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgUnVsZXNFdmFsdWF0aW9uU2VydmljZSB7XG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBydWxlcyBhZ2FpbnN0IGZvcm0gdmFsdWVzIGFuZCBvcHRpb25hbCBvcmlnaW5hbCBiYXNlbGluZSB2YWx1ZXMuXG4gICAqL1xuICBldmFsdWF0ZShcbiAgICBydWxlczogRm9ybVJ1bGVbXSB8IHVuZGVmaW5lZCB8IG51bGwsXG4gICAgdmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBvcmlnaW5hbFZhbHVlcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICApOiBSdWxlRXZhbHVhdGlvblJlc3VsdCB7XG4gICAgcmV0dXJuIGV2YWx1YXRlRm9ybVJ1bGVzKHJ1bGVzLCB2YWx1ZXMsIG9yaWdpbmFsVmFsdWVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaWx0ZXIgcnVsZXMgcGVydGluZW50IHRvIGEgc2luZ2xlIHRhYi5cbiAgICovXG4gIGZpbHRlckZvclRhYihydWxlczogRm9ybVJ1bGVbXSB8IHVuZGVmaW5lZCB8IG51bGwsIHRhYklkOiBzdHJpbmcsIGNvbmZpZzogRW50aXR5Rm9ybUNvbmZpZyk6IEZvcm1SdWxlW10ge1xuICAgIHJldHVybiBmaWx0ZXJSdWxlc0ZvclRhYihydWxlcywgdGFiSWQsIGNvbmZpZyk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { VALIDATION_MESSAGES } from '../tokens/injection-tokens';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/** The built-in English messages. Every key here can be overridden individually. */
|
|
5
|
-
export const DEFAULT_VALIDATION_MESSAGES = {
|
|
6
|
-
required: 'This field is required.',
|
|
7
|
-
requiredSelection: 'Please select an option.',
|
|
8
|
-
email: 'Please enter a valid email address.',
|
|
9
|
-
pattern: 'Invalid format.',
|
|
10
|
-
minlength: (_lang, err) => `Minimum ${err?.requiredLength} characters required.`,
|
|
11
|
-
maxlength: (_lang, err) => `Maximum ${err?.requiredLength} characters allowed.`,
|
|
12
|
-
min: (_lang, err) => `Value must be at least ${err?.min}.`,
|
|
13
|
-
max: (_lang, err) => `Value must not exceed ${err?.max}.`,
|
|
14
|
-
invalid: 'Invalid value.',
|
|
15
|
-
invalidNumber: 'Invalid number.',
|
|
16
|
-
invalidSelection: 'Invalid selection.',
|
|
17
|
-
};
|
|
18
|
-
export class ValidationMessagesService {
|
|
19
|
-
overrides = inject(VALIDATION_MESSAGES, { optional: true }) ?? {};
|
|
20
|
-
/**
|
|
21
|
-
* The message for the first error present, in the order the caller lists.
|
|
22
|
-
*
|
|
23
|
-
* Order is the caller's because it is field-specific: a dropdown wants
|
|
24
|
-
* `requiredSelection` where a text input wants `required`, and the first match wins so the
|
|
25
|
-
* most specific message is the one shown.
|
|
26
|
-
*/
|
|
27
|
-
resolve(errors, language, order, fallbackKey = 'invalid') {
|
|
28
|
-
if (!errors)
|
|
29
|
-
return '';
|
|
30
|
-
for (const entry of order) {
|
|
31
|
-
// A tuple maps an Angular error key to a different message key: a dropdown raises the
|
|
32
|
-
// standard `required` error but reads better as "Please select an option", and both
|
|
33
|
-
// messages stay independently overridable.
|
|
34
|
-
const [errorKey, messageKey] = typeof entry === 'string' ? [entry, entry] : entry;
|
|
35
|
-
// `errors[errorKey]` is usually an object of detail, but `required` is simply `true`.
|
|
36
|
-
if (errors[errorKey] === undefined)
|
|
37
|
-
continue;
|
|
38
|
-
return this.messageFor(messageKey, language, errors[errorKey]);
|
|
39
|
-
}
|
|
40
|
-
return this.messageFor(fallbackKey, language, null);
|
|
41
|
-
}
|
|
42
|
-
/** One message by key, honouring an override before the default. */
|
|
43
|
-
messageFor(key, language, error) {
|
|
44
|
-
const message = this.overrides[key] ?? DEFAULT_VALIDATION_MESSAGES[key];
|
|
45
|
-
if (message === undefined)
|
|
46
|
-
return '';
|
|
47
|
-
return typeof message === 'function' ? message(language, error) : message;
|
|
48
|
-
}
|
|
49
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidationMessagesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
50
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidationMessagesService, providedIn: 'root' });
|
|
51
|
-
}
|
|
52
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidationMessagesService, decorators: [{
|
|
53
|
-
type: Injectable,
|
|
54
|
-
args: [{ providedIn: 'root' }]
|
|
55
|
-
}] });
|
|
56
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGlvbi1tZXNzYWdlcy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy92YWxpZGF0aW9uLW1lc3NhZ2VzLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFbkQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7O0FBMkJqRSxvRkFBb0Y7QUFDcEYsTUFBTSxDQUFDLE1BQU0sMkJBQTJCLEdBQXNDO0lBQzVFLFFBQVEsRUFBRSx5QkFBeUI7SUFDbkMsaUJBQWlCLEVBQUUsMEJBQTBCO0lBQzdDLEtBQUssRUFBRSxxQ0FBcUM7SUFDNUMsT0FBTyxFQUFFLGlCQUFpQjtJQUMxQixTQUFTLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxXQUFXLEdBQUcsRUFBRSxjQUFjLHVCQUF1QjtJQUNoRixTQUFTLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxXQUFXLEdBQUcsRUFBRSxjQUFjLHNCQUFzQjtJQUMvRSxHQUFHLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQywwQkFBMEIsR0FBRyxFQUFFLEdBQUcsR0FBRztJQUMxRCxHQUFHLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyx5QkFBeUIsR0FBRyxFQUFFLEdBQUcsR0FBRztJQUN6RCxPQUFPLEVBQUUsZ0JBQWdCO0lBQ3pCLGFBQWEsRUFBRSxpQkFBaUI7SUFDaEMsZ0JBQWdCLEVBQUUsb0JBQW9CO0NBQ3ZDLENBQUM7QUFHRixNQUFNLE9BQU8seUJBQXlCO0lBQ25CLFNBQVMsR0FBRyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7SUFFbkY7Ozs7OztPQU1HO0lBQ0gsT0FBTyxDQUNMLE1BQTJDLEVBQzNDLFFBQWdCLEVBQ2hCLEtBQTRFLEVBQzVFLFdBQVcsR0FBRyxTQUFTO1FBRXZCLElBQUksQ0FBQyxNQUFNO1lBQUUsT0FBTyxFQUFFLENBQUM7UUFFdkIsS0FBSyxNQUFNLEtBQUssSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUMxQixzRkFBc0Y7WUFDdEYsb0ZBQW9GO1lBQ3BGLDJDQUEyQztZQUMzQyxNQUFNLENBQUMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxHQUFHLE9BQU8sS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztZQUNsRixzRkFBc0Y7WUFDdEYsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssU0FBUztnQkFBRSxTQUFTO1lBQzdDLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1FBQ2pFLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQsb0VBQW9FO0lBQ3BFLFVBQVUsQ0FBQyxHQUFXLEVBQUUsUUFBZ0IsRUFBRSxLQUFjO1FBQ3RELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksMkJBQTJCLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEUsSUFBSSxPQUFPLEtBQUssU0FBUztZQUFFLE9BQU8sRUFBRSxDQUFDO1FBQ3JDLE9BQU8sT0FBTyxPQUFPLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7SUFDNUUsQ0FBQzt3R0FuQ1UseUJBQXlCOzRHQUF6Qix5QkFBeUIsY0FEWixNQUFNOzs0RkFDbkIseUJBQXlCO2tCQURyQyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHR5cGUgeyBWYWxpZGF0aW9uRXJyb3JzIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgVkFMSURBVElPTl9NRVNTQUdFUyB9IGZyb20gJy4uL3Rva2Vucy9pbmplY3Rpb24tdG9rZW5zJztcblxuLyoqXG4gKiBSZXNvbHZlcyBhbiBBbmd1bGFyIGBWYWxpZGF0aW9uRXJyb3JzYCBvYmplY3QgdG8gdGhlIG1lc3NhZ2Ugc2hvd24gdW5kZXIgYSBmaWVsZC5cbiAqXG4gKiBUaGVzZSBzdHJpbmdzIHVzZWQgdG8gYmUgaGFyZGNvZGVkIEVuZ2xpc2ggbGl0ZXJhbHMgaW5zaWRlIGVhY2ggZmllbGQgY29tcG9uZW50LCBzbyBhXG4gKiBHZXJtYW4gZm9ybSBtZWFudCByZS1pbXBsZW1lbnRpbmcgZXZlcnkgZmllbGQgdHlwZSDigJQgdGhlIGxhYmVscyBob25vdXJlZCBgbGFuZ3VhZ2VgIHdoaWxlXG4gKiB0aGUgZXJyb3JzIHVuZGVybmVhdGggdGhlbSBkaWQgbm90LlxuICpcbiAqIEEgbWVzc2FnZSBpcyBhIHBsYWluIHN0cmluZywgb3IgYSBmdW5jdGlvbiB3aGVuIGl0IG5lZWRzIHRoZSBlcnJvcidzIG93biBkZXRhaWxcbiAqIChgbWlubGVuZ3RoLnJlcXVpcmVkTGVuZ3RoYCwgYG1pbi5taW5gLCBhbmQgc28gb24pLiBUaGUgYWN0aXZlIGBsYW5ndWFnZWAgaXMgcGFzc2VkXG4gKiB0aHJvdWdoLCBzbyBvbmUgcmVnaXN0cmF0aW9uIGNhbiBzZXJ2ZSBldmVyeSBsb2NhbGU6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogcHJvdmlkZU5neER5bmFtaWNFbnRpdHkoe1xuICogICB2YWxpZGF0aW9uTWVzc2FnZXM6IHtcbiAqICAgICByZXF1aXJlZDogbGFuZyA9PiAobGFuZyA9PT0gJ2RlJyA/ICdQZmxpY2h0ZmVsZC4nIDogJ1RoaXMgZmllbGQgaXMgcmVxdWlyZWQuJyksXG4gKiAgICAgbWlubGVuZ3RoOiAobGFuZywgZXJyKSA9PiBgTWluZGVzdGVucyAke2VyclsncmVxdWlyZWRMZW5ndGgnXX0gWmVpY2hlbi5gLFxuICogICB9LFxuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBVbnJlZ2lzdGVyZWQga2V5cyBmYWxsIGJhY2sgdG8gdGhlIGRlZmF1bHRzIGJlbG93LCBzbyBvdmVycmlkaW5nIG9uZSBtZXNzYWdlIGRvZXMgbm90XG4gKiBtZWFuIHN1cHBseWluZyB0aGVtIGFsbC5cbiAqL1xuZXhwb3J0IHR5cGUgVmFsaWRhdGlvbk1lc3NhZ2UgPSBzdHJpbmcgfCAoKGxhbmd1YWdlOiBzdHJpbmcsIGVycm9yOiBhbnkpID0+IHN0cmluZyk7XG5cbi8qKiBUaGUgYnVpbHQtaW4gRW5nbGlzaCBtZXNzYWdlcy4gRXZlcnkga2V5IGhlcmUgY2FuIGJlIG92ZXJyaWRkZW4gaW5kaXZpZHVhbGx5LiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfVkFMSURBVElPTl9NRVNTQUdFUzogUmVjb3JkPHN0cmluZywgVmFsaWRhdGlvbk1lc3NhZ2U+ID0ge1xuICByZXF1aXJlZDogJ1RoaXMgZmllbGQgaXMgcmVxdWlyZWQuJyxcbiAgcmVxdWlyZWRTZWxlY3Rpb246ICdQbGVhc2Ugc2VsZWN0IGFuIG9wdGlvbi4nLFxuICBlbWFpbDogJ1BsZWFzZSBlbnRlciBhIHZhbGlkIGVtYWlsIGFkZHJlc3MuJyxcbiAgcGF0dGVybjogJ0ludmFsaWQgZm9ybWF0LicsXG4gIG1pbmxlbmd0aDogKF9sYW5nLCBlcnIpID0+IGBNaW5pbXVtICR7ZXJyPy5yZXF1aXJlZExlbmd0aH0gY2hhcmFjdGVycyByZXF1aXJlZC5gLFxuICBtYXhsZW5ndGg6IChfbGFuZywgZXJyKSA9PiBgTWF4aW11bSAke2Vycj8ucmVxdWlyZWRMZW5ndGh9IGNoYXJhY3RlcnMgYWxsb3dlZC5gLFxuICBtaW46IChfbGFuZywgZXJyKSA9PiBgVmFsdWUgbXVzdCBiZSBhdCBsZWFzdCAke2Vycj8ubWlufS5gLFxuICBtYXg6IChfbGFuZywgZXJyKSA9PiBgVmFsdWUgbXVzdCBub3QgZXhjZWVkICR7ZXJyPy5tYXh9LmAsXG4gIGludmFsaWQ6ICdJbnZhbGlkIHZhbHVlLicsXG4gIGludmFsaWROdW1iZXI6ICdJbnZhbGlkIG51bWJlci4nLFxuICBpbnZhbGlkU2VsZWN0aW9uOiAnSW52YWxpZCBzZWxlY3Rpb24uJyxcbn07XG5cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgVmFsaWRhdGlvbk1lc3NhZ2VzU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgb3ZlcnJpZGVzID0gaW5qZWN0KFZBTElEQVRJT05fTUVTU0FHRVMsIHsgb3B0aW9uYWw6IHRydWUgfSkgPz8ge307XG5cbiAgLyoqXG4gICAqIFRoZSBtZXNzYWdlIGZvciB0aGUgZmlyc3QgZXJyb3IgcHJlc2VudCwgaW4gdGhlIG9yZGVyIHRoZSBjYWxsZXIgbGlzdHMuXG4gICAqXG4gICAqIE9yZGVyIGlzIHRoZSBjYWxsZXIncyBiZWNhdXNlIGl0IGlzIGZpZWxkLXNwZWNpZmljOiBhIGRyb3Bkb3duIHdhbnRzXG4gICAqIGByZXF1aXJlZFNlbGVjdGlvbmAgd2hlcmUgYSB0ZXh0IGlucHV0IHdhbnRzIGByZXF1aXJlZGAsIGFuZCB0aGUgZmlyc3QgbWF0Y2ggd2lucyBzbyB0aGVcbiAgICogbW9zdCBzcGVjaWZpYyBtZXNzYWdlIGlzIHRoZSBvbmUgc2hvd24uXG4gICAqL1xuICByZXNvbHZlKFxuICAgIGVycm9yczogVmFsaWRhdGlvbkVycm9ycyB8IG51bGwgfCB1bmRlZmluZWQsXG4gICAgbGFuZ3VhZ2U6IHN0cmluZyxcbiAgICBvcmRlcjogcmVhZG9ubHkgKHN0cmluZyB8IHJlYWRvbmx5IFtlcnJvcktleTogc3RyaW5nLCBtZXNzYWdlS2V5OiBzdHJpbmddKVtdLFxuICAgIGZhbGxiYWNrS2V5ID0gJ2ludmFsaWQnLFxuICApOiBzdHJpbmcge1xuICAgIGlmICghZXJyb3JzKSByZXR1cm4gJyc7XG5cbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIG9yZGVyKSB7XG4gICAgICAvLyBBIHR1cGxlIG1hcHMgYW4gQW5ndWxhciBlcnJvciBrZXkgdG8gYSBkaWZmZXJlbnQgbWVzc2FnZSBrZXk6IGEgZHJvcGRvd24gcmFpc2VzIHRoZVxuICAgICAgLy8gc3RhbmRhcmQgYHJlcXVpcmVkYCBlcnJvciBidXQgcmVhZHMgYmV0dGVyIGFzIFwiUGxlYXNlIHNlbGVjdCBhbiBvcHRpb25cIiwgYW5kIGJvdGhcbiAgICAgIC8vIG1lc3NhZ2VzIHN0YXkgaW5kZXBlbmRlbnRseSBvdmVycmlkYWJsZS5cbiAgICAgIGNvbnN0IFtlcnJvcktleSwgbWVzc2FnZUtleV0gPSB0eXBlb2YgZW50cnkgPT09ICdzdHJpbmcnID8gW2VudHJ5LCBlbnRyeV0gOiBlbnRyeTtcbiAgICAgIC8vIGBlcnJvcnNbZXJyb3JLZXldYCBpcyB1c3VhbGx5IGFuIG9iamVjdCBvZiBkZXRhaWwsIGJ1dCBgcmVxdWlyZWRgIGlzIHNpbXBseSBgdHJ1ZWAuXG4gICAgICBpZiAoZXJyb3JzW2Vycm9yS2V5XSA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICAgIHJldHVybiB0aGlzLm1lc3NhZ2VGb3IobWVzc2FnZUtleSwgbGFuZ3VhZ2UsIGVycm9yc1tlcnJvcktleV0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5tZXNzYWdlRm9yKGZhbGxiYWNrS2V5LCBsYW5ndWFnZSwgbnVsbCk7XG4gIH1cblxuICAvKiogT25lIG1lc3NhZ2UgYnkga2V5LCBob25vdXJpbmcgYW4gb3ZlcnJpZGUgYmVmb3JlIHRoZSBkZWZhdWx0LiAqL1xuICBtZXNzYWdlRm9yKGtleTogc3RyaW5nLCBsYW5ndWFnZTogc3RyaW5nLCBlcnJvcjogdW5rbm93bik6IHN0cmluZyB7XG4gICAgY29uc3QgbWVzc2FnZSA9IHRoaXMub3ZlcnJpZGVzW2tleV0gPz8gREVGQVVMVF9WQUxJREFUSU9OX01FU1NBR0VTW2tleV07XG4gICAgaWYgKG1lc3NhZ2UgPT09IHVuZGVmaW5lZCkgcmV0dXJuICcnO1xuICAgIHJldHVybiB0eXBlb2YgbWVzc2FnZSA9PT0gJ2Z1bmN0aW9uJyA/IG1lc3NhZ2UobGFuZ3VhZ2UsIGVycm9yKSA6IG1lc3NhZ2U7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { Injectable, inject } from '@angular/core';
|
|
2
|
-
import { Validators } from '@angular/forms';
|
|
3
|
-
import { ASYNC_VALIDATOR_REGISTRY, VALIDATOR_REGISTRY } from '../tokens/injection-tokens';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
/**
|
|
6
|
-
* ValidatorRegistryService — resolves validator configs / key strings to Angular ValidatorFns.
|
|
7
|
-
*/
|
|
8
|
-
export class ValidatorRegistryService {
|
|
9
|
-
consumerRegistry = inject(VALIDATOR_REGISTRY, { optional: true }) ?? new Map();
|
|
10
|
-
asyncRegistry = inject(ASYNC_VALIDATOR_REGISTRY, { optional: true }) ?? new Map();
|
|
11
|
-
/**
|
|
12
|
-
* Resolve a validator key string to a ValidatorFn.
|
|
13
|
-
* Supports parameterized built-ins like 'min:0', 'maxLength:255'.
|
|
14
|
-
*/
|
|
15
|
-
resolve(validatorKey) {
|
|
16
|
-
if (this.consumerRegistry.has(validatorKey)) {
|
|
17
|
-
return this.consumerRegistry.get(validatorKey);
|
|
18
|
-
}
|
|
19
|
-
if (validatorKey === 'required')
|
|
20
|
-
return Validators.required;
|
|
21
|
-
if (validatorKey === 'email')
|
|
22
|
-
return Validators.email;
|
|
23
|
-
const [name, param] = validatorKey.split(':');
|
|
24
|
-
const value = parseFloat(param);
|
|
25
|
-
if (name === 'min' && !isNaN(value))
|
|
26
|
-
return Validators.min(value);
|
|
27
|
-
if (name === 'max' && !isNaN(value))
|
|
28
|
-
return Validators.max(value);
|
|
29
|
-
if (name === 'minLength' && !isNaN(value))
|
|
30
|
-
return Validators.minLength(value);
|
|
31
|
-
if (name === 'maxLength' && !isNaN(value))
|
|
32
|
-
return Validators.maxLength(value);
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
/** Resolve multiple validator keys into a ValidatorFn[] */
|
|
36
|
-
resolveAll(validatorKeys = []) {
|
|
37
|
-
return validatorKeys.map(k => this.resolve(k)).filter((v) => v !== null);
|
|
38
|
-
}
|
|
39
|
-
/** Resolve a FieldValidators object or string[] into ValidatorFn[] */
|
|
40
|
-
resolveFromConfig(config) {
|
|
41
|
-
if (!config)
|
|
42
|
-
return [];
|
|
43
|
-
if (Array.isArray(config))
|
|
44
|
-
return this.resolveAll(config);
|
|
45
|
-
const fnList = [];
|
|
46
|
-
if (config.required)
|
|
47
|
-
fnList.push(Validators.required);
|
|
48
|
-
if (config.min !== undefined)
|
|
49
|
-
fnList.push(Validators.min(config.min));
|
|
50
|
-
if (config.max !== undefined)
|
|
51
|
-
fnList.push(Validators.max(config.max));
|
|
52
|
-
if (config.minLength !== undefined)
|
|
53
|
-
fnList.push(Validators.minLength(config.minLength));
|
|
54
|
-
if (config.maxLength !== undefined)
|
|
55
|
-
fnList.push(Validators.maxLength(config.maxLength));
|
|
56
|
-
if (config.pattern)
|
|
57
|
-
fnList.push(Validators.pattern(config.pattern));
|
|
58
|
-
if (config.email)
|
|
59
|
-
fnList.push(Validators.email);
|
|
60
|
-
// Named validators from the consumer registry. This branch previously hardcoded the
|
|
61
|
-
// built-ins and consulted the registry only for the `string[]` form of this config, so
|
|
62
|
-
// a validator the consumer had registered could not be named from a typed schema
|
|
63
|
-
// without casting it to `any`.
|
|
64
|
-
for (const key of config.custom ?? []) {
|
|
65
|
-
const fn = this.resolve(key);
|
|
66
|
-
if (fn)
|
|
67
|
-
fnList.push(fn);
|
|
68
|
-
}
|
|
69
|
-
return fnList;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Resolve the async validators a field names, in `validators.customAsync`.
|
|
73
|
-
*
|
|
74
|
-
* Async validators are deliberately a separate registry and a separate config key: Angular
|
|
75
|
-
* attaches them through `setAsyncValidators`, runs them only once the synchronous ones
|
|
76
|
-
* pass, and holds the control in `pending` until they settle. Mixing them into the
|
|
77
|
-
* synchronous list would silently never run them.
|
|
78
|
-
*
|
|
79
|
-
* An unknown name is skipped rather than throwing, matching the synchronous behaviour.
|
|
80
|
-
*/
|
|
81
|
-
resolveAsyncFromConfig(config) {
|
|
82
|
-
if (!config || Array.isArray(config))
|
|
83
|
-
return [];
|
|
84
|
-
const out = [];
|
|
85
|
-
for (const key of config.customAsync ?? []) {
|
|
86
|
-
const fn = this.asyncRegistry.get(key);
|
|
87
|
-
if (fn)
|
|
88
|
-
out.push(fn);
|
|
89
|
-
}
|
|
90
|
-
return out;
|
|
91
|
-
}
|
|
92
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidatorRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
93
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidatorRegistryService, providedIn: 'root' });
|
|
94
|
-
}
|
|
95
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidatorRegistryService, decorators: [{
|
|
96
|
-
type: Injectable,
|
|
97
|
-
args: [{ providedIn: 'root' }]
|
|
98
|
-
}] });
|
|
99
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLXJlZ2lzdHJ5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL3ZhbGlkYXRvci1yZWdpc3RyeS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBaUMsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0UsT0FBTyxFQUFFLHdCQUF3QixFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7O0FBRTFGOztHQUVHO0FBRUgsTUFBTSxPQUFPLHdCQUF3QjtJQUNsQixnQkFBZ0IsR0FBRyxNQUFNLENBQUMsa0JBQWtCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQy9FLGFBQWEsR0FBRyxNQUFNLENBQUMsd0JBQXdCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBRW5HOzs7T0FHRztJQUNILE9BQU8sQ0FBQyxZQUFvQjtRQUMxQixJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztZQUM1QyxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDakQsQ0FBQztRQUVELElBQUksWUFBWSxLQUFLLFVBQVU7WUFBRSxPQUFPLFVBQVUsQ0FBQyxRQUFRLENBQUM7UUFDNUQsSUFBSSxZQUFZLEtBQUssT0FBTztZQUFFLE9BQU8sVUFBVSxDQUFDLEtBQUssQ0FBQztRQUV0RCxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxHQUFHLFlBQVksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDOUMsTUFB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QUFDO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNILHNCQUFzQixDQUFDLE1BQW1DO1FBQ3hELElBQUksQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUVoRCxNQUFNLEdBQUcsR0FBdUIsRUFBRSxDQUFDO1FBQ25DLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLFdBQVcsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUMzQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN2QyxJQUFJLEVBQUU7Z0JBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN2QixDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO3dHQTdFVSx3QkFBd0I7NEdBQXhCLHdCQUF3QixjQURYLE1BQU07OzRGQUNuQix3QkFBd0I7a0JBRHBDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBc3luY1ZhbGlkYXRvckZuLCBWYWxpZGF0b3JGbiwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB0eXBlIHsgRmllbGRWYWxpZGF0b3JzIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgQVNZTkNfVkFMSURBVE9SX1JFR0lTVFJZLCBWQUxJREFUT1JfUkVHSVNUUlkgfSBmcm9tICcuLi90b2tlbnMvaW5qZWN0aW9uLXRva2Vucyc7XG5cbi8qKlxuICogVmFsaWRhdG9yUmVnaXN0cnlTZXJ2aWNlIOKAlCByZXNvbHZlcyB2YWxpZGF0b3IgY29uZmlncyAvIGtleSBzdHJpbmdzIHRvIEFuZ3VsYXIgVmFsaWRhdG9yRm5zLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29uc3VtZXJSZWdpc3RyeSA9IGluamVjdChWQUxJREFUT1JfUkVHSVNUUlksIHsgb3B0aW9uYWw6IHRydWUgfSkgPz8gbmV3IE1hcCgpO1xuICBwcml2YXRlIHJlYWRvbmx5IGFzeW5jUmVnaXN0cnkgPSBpbmplY3QoQVNZTkNfVkFMSURBVE9SX1JFR0lTVFJZLCB7IG9wdGlvbmFsOiB0cnVlIH0pID8/IG5ldyBNYXAoKTtcblxuICAvKipcbiAgICogUmVzb2x2ZSBhIHZhbGlkYXRvciBrZXkgc3RyaW5nIHRvIGEgVmFsaWRhdG9yRm4uXG4gICAqIFN1cHBvcnRzIHBhcmFtZXRlcml6ZWQgYnVpbHQtaW5zIGxpa2UgJ21pbjowJywgJ21heExlbmd0aDoyNTUnLlxuICAgKi9cbiAgcmVzb2x2ZSh2YWxpZGF0b3JLZXk6IHN0cmluZyk6IFZhbGlkYXRvckZuIHwgbnVsbCB7XG4gICAgaWYgKHRoaXMuY29uc3VtZXJSZWdpc3RyeS5oYXModmFsaWRhdG9yS2V5KSkge1xuICAgICAgcmV0dXJuIHRoaXMuY29uc3VtZXJSZWdpc3RyeS5nZXQodmFsaWRhdG9yS2V5KTtcbiAgICB9XG5cbiAgICBpZiAodmFsaWRhdG9yS2V5ID09PSAncmVxdWlyZWQnKSByZXR1cm4gVmFsaWRhdG9ycy5yZXF1aXJlZDtcbiAgICBpZiAodmFsaWRhdG9yS2V5ID09PSAnZW1haWwnKSByZXR1cm4gVmFsaWRhdG9ycy5lbWFpbDtcblxuICAgIGNvbnN0IFtuYW1lLCBwYXJhbV0gPSB2YWxpZGF0b3JLZXkuc3BsaXQoJzonKTtcbiAgICBjb25zdCB2YWx1ZSA9IHBhcnNlRmxvYXQocGFyYW0pO1xuXG4gICAgaWYgKG5hbWUgPT09ICdtaW4nICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1pbih2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtYXgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1heCh2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtaW5MZW5ndGgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1pbkxlbmd0aCh2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtYXhMZW5ndGgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1heExlbmd0aCh2YWx1ZSk7XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlIG11bHRpcGxlIHZhbGlkYXRvciBrZXlzIGludG8gYSBWYWxpZGF0b3JGbltdICovXG4gIHJlc29sdmVBbGwodmFsaWRhdG9yS2V5czogc3RyaW5nW10gPSBbXSk6IFZhbGlkYXRvckZuW10ge1xuICAgIHJldHVybiB2YWxpZGF0b3JLZXlzLm1hcChrID0+IHRoaXMucmVzb2x2ZShrKSkuZmlsdGVyKCh2KTogdiBpcyBWYWxpZGF0b3JGbiA9PiB2ICE9PSBudWxsKTtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlIGEgRmllbGRWYWxpZGF0b3JzIG9iamVjdCBvciBzdHJpbmdbXSBpbnRvIFZhbGlkYXRvckZuW10gKi9cbiAgcmVzb2x2ZUZyb21Db25maWcoY29uZmlnPzogRmllbGRWYWxpZGF0b3JzIHwgc3RyaW5nW10pOiBWYWxpZGF0b3JGbltdIHtcbiAgICBpZiAoIWNvbmZpZykgcmV0dXJuIFtdO1xuICAgIGlmIChBcnJheS5pc0FycmF5KGNvbmZpZykpIHJldHVybiB0aGlzLnJlc29sdmVBbGwoY29uZmlnKTtcblxuICAgIGNvbnN0IGZuTGlzdDogVmFsaWRhdG9yRm5bXSA9IFtdO1xuICAgIGlmIChjb25maWcucmVxdWlyZWQpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMucmVxdWlyZWQpO1xuICAgIGlmIChjb25maWcubWluICE9PSB1bmRlZmluZWQpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMubWluKGNvbmZpZy5taW4pKTtcbiAgICBpZiAoY29uZmlnLm1heCAhPT0gdW5kZWZpbmVkKSBmbkxpc3QucHVzaChWYWxpZGF0b3JzLm1heChjb25maWcubWF4KSk7XG4gICAgaWYgKGNvbmZpZy5taW5MZW5ndGggIT09IHVuZGVmaW5lZCkgZm5MaXN0LnB1c2goVmFsaWRhdG9ycy5taW5MZW5ndGgoY29uZmlnLm1pbkxlbmd0aCkpO1xuICAgIGlmIChjb25maWcubWF4TGVuZ3RoICE9PSB1bmRlZmluZWQpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMubWF4TGVuZ3RoKGNvbmZpZy5tYXhMZW5ndGgpKTtcbiAgICBpZiAoY29uZmlnLnBhdHRlcm4pIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMucGF0dGVybihjb25maWcucGF0dGVybikpO1xuICAgIGlmIChjb25maWcuZW1haWwpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMuZW1haWwpO1xuXG4gICAgLy8gTmFtZWQgdmFsaWRhdG9ycyBmcm9tIHRoZSBjb25zdW1lciByZWdpc3RyeS4gVGhpcyBicmFuY2ggcHJldmlvdXNseSBoYXJkY29kZWQgdGhlXG4gICAgLy8gYnVpbHQtaW5zIGFuZCBjb25zdWx0ZWQgdGhlIHJlZ2lzdHJ5IG9ubHkgZm9yIHRoZSBgc3RyaW5nW11gIGZvcm0gb2YgdGhpcyBjb25maWcsIHNvXG4gICAgLy8gYSB2YWxpZGF0b3IgdGhlIGNvbnN1bWVyIGhhZCByZWdpc3RlcmVkIGNvdWxkIG5vdCBiZSBuYW1lZCBmcm9tIGEgdHlwZWQgc2NoZW1hXG4gICAgLy8gd2l0aG91dCBjYXN0aW5nIGl0IHRvIGBhbnlgLlxuICAgIGZvciAoY29uc3Qga2V5IG9mIGNvbmZpZy5jdXN0b20gPz8gW10pIHtcbiAgICAgIGNvbnN0IGZuID0gdGhpcy5yZXNvbHZlKGtleSk7XG4gICAgICBpZiAoZm4pIGZuTGlzdC5wdXNoKGZuKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZm5MaXN0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgdGhlIGFzeW5jIHZhbGlkYXRvcnMgYSBmaWVsZCBuYW1lcywgaW4gYHZhbGlkYXRvcnMuY3VzdG9tQXN5bmNgLlxuICAgKlxuICAgKiBBc3luYyB2YWxpZGF0b3JzIGFyZSBkZWxpYmVyYXRlbHkgYSBzZXBhcmF0ZSByZWdpc3RyeSBhbmQgYSBzZXBhcmF0ZSBjb25maWcga2V5OiBBbmd1bGFyXG4gICAqIGF0dGFjaGVzIHRoZW0gdGhyb3VnaCBgc2V0QXN5bmNWYWxpZGF0b3JzYCwgcnVucyB0aGVtIG9ubHkgb25jZSB0aGUgc3luY2hyb25vdXMgb25lc1xuICAgKiBwYXNzLCBhbmQgaG9sZHMgdGhlIGNvbnRyb2wgaW4gYHBlbmRpbmdgIHVudGlsIHRoZXkgc2V0dGxlLiBNaXhpbmcgdGhlbSBpbnRvIHRoZVxuICAgKiBzeW5jaHJvbm91cyBsaXN0IHdvdWxkIHNpbGVudGx5IG5ldmVyIHJ1biB0aGVtLlxuICAgKlxuICAgKiBBbiB1bmtub3duIG5hbWUgaXMgc2tpcHBlZCByYXRoZXIgdGhhbiB0aHJvd2luZywgbWF0Y2hpbmcgdGhlIHN5bmNocm9ub3VzIGJlaGF2aW91ci5cbiAgICovXG4gIHJlc29sdmVBc3luY0Zyb21Db25maWcoY29uZmlnPzogRmllbGRWYWxpZGF0b3JzIHwgc3RyaW5nW10pOiBBc3luY1ZhbGlkYXRvckZuW10ge1xuICAgIGlmICghY29uZmlnIHx8IEFycmF5LmlzQXJyYXkoY29uZmlnKSkgcmV0dXJuIFtdO1xuXG4gICAgY29uc3Qgb3V0OiBBc3luY1ZhbGlkYXRvckZuW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBjb25maWcuY3VzdG9tQXN5bmMgPz8gW10pIHtcbiAgICAgIGNvbnN0IGZuID0gdGhpcy5hc3luY1JlZ2lzdHJ5LmdldChrZXkpO1xuICAgICAgaWYgKGZuKSBvdXQucHVzaChmbik7XG4gICAgfVxuICAgIHJldHVybiBvdXQ7XG4gIH1cbn1cbiJdfQ==
|