obsidian-dev-utils 101.6.0 → 101.8.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/CHANGELOG.md +9 -0
- package/dist/integration-test-plugin/main.js +4410 -3705
- package/dist/lib/cjs/__merged.cjs +26 -1
- package/dist/lib/cjs/__merged.d.cts +4 -1
- package/dist/lib/cjs/generated-during-build.cjs +1 -1
- package/dist/lib/cjs/obsidian/components/component-ex.cjs +14 -1
- package/dist/lib/cjs/obsidian/components/component-ex.d.cts +11 -0
- package/dist/lib/cjs/obsidian/components/index.cjs +4 -1
- package/dist/lib/cjs/obsidian/components/index.d.cts +1 -0
- package/dist/lib/cjs/obsidian/components/plugin-gate-component.cjs +520 -0
- package/dist/lib/cjs/obsidian/components/plugin-gate-component.d.cts +299 -0
- package/dist/lib/cjs/obsidian/components/plugin-suggestion-component.cjs +17 -38
- package/dist/lib/cjs/obsidian/components/plugin-suggestion-component.d.cts +25 -18
- package/dist/lib/cjs/obsidian/components/rename-delete-handler-component.cjs +7 -2
- package/dist/lib/cjs/obsidian/css-class.cjs +3 -1
- package/dist/lib/cjs/obsidian/css-class.d.cts +9 -0
- package/dist/lib/cjs/obsidian/html-element.cjs +27 -3
- package/dist/lib/cjs/obsidian/html-element.d.cts +36 -0
- package/dist/lib/cjs/obsidian/i18n/locales/en.cjs +15 -1
- package/dist/lib/cjs/obsidian/i18n/locales/en.d.cts +14 -0
- package/dist/lib/cjs/obsidian/i18n/locales/translations-map.d.cts +14 -0
- package/dist/lib/cjs/obsidian/plugin/index.cjs +7 -1
- package/dist/lib/cjs/obsidian/plugin/index.d.cts +2 -0
- package/dist/lib/cjs/obsidian/plugin/plugin-api.cjs +2 -2
- package/dist/lib/cjs/obsidian/plugin/plugin-api.d.cts +34 -15
- package/dist/lib/cjs/obsidian/plugin/plugin-install-state.cjs +208 -0
- package/dist/lib/cjs/obsidian/plugin/plugin-install-state.d.cts +113 -0
- package/dist/lib/cjs/obsidian/plugin/plugin-lifecycle-events.cjs +161 -0
- package/dist/lib/cjs/obsidian/plugin/plugin-lifecycle-events.d.cts +119 -0
- package/dist/lib/cjs/obsidian/plugin/plugin.cjs +241 -21
- package/dist/lib/cjs/obsidian/plugin/plugin.d.cts +133 -4
- package/dist/lib/cjs/script-utils/demo-vault-buttons.cjs +3 -3
- package/dist/lib/cjs/script-utils/demo-vault-buttons.d.cts +8 -2
- package/dist/lib/cjs/script-utils/linters/eslint-config.cjs +9 -1
- package/dist/lib/cjs/script-utils/linters/eslint-rules/index.cjs +4 -1
- package/dist/lib/cjs/script-utils/linters/eslint-rules/index.d.cts +1 -0
- package/dist/lib/cjs/script-utils/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.cjs +408 -0
- package/dist/lib/cjs/script-utils/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.d.cts +10 -0
- package/dist/lib/cjs/script-utils/linters/eslint-rules/obsidian-dev-utils-plugin.cjs +3 -1
- package/dist/lib/esm/__merged.d.mts +4 -1
- package/dist/lib/esm/__merged.mjs +30 -2
- package/dist/lib/esm/generated-during-build.mjs +1 -1
- package/dist/lib/esm/obsidian/components/component-ex.d.mts +11 -0
- package/dist/lib/esm/obsidian/components/component-ex.mjs +14 -1
- package/dist/lib/esm/obsidian/components/index.d.mts +1 -0
- package/dist/lib/esm/obsidian/components/index.mjs +3 -1
- package/dist/lib/esm/obsidian/components/plugin-gate-component.d.mts +299 -0
- package/dist/lib/esm/obsidian/components/plugin-gate-component.mjs +428 -0
- package/dist/lib/esm/obsidian/components/plugin-suggestion-component.d.mts +25 -18
- package/dist/lib/esm/obsidian/components/plugin-suggestion-component.mjs +21 -41
- package/dist/lib/esm/obsidian/components/rename-delete-handler-component.mjs +7 -2
- package/dist/lib/esm/obsidian/css-class.d.mts +9 -0
- package/dist/lib/esm/obsidian/css-class.mjs +3 -1
- package/dist/lib/esm/obsidian/html-element.d.mts +36 -0
- package/dist/lib/esm/obsidian/html-element.mjs +24 -2
- package/dist/lib/esm/obsidian/i18n/locales/en.d.mts +14 -0
- package/dist/lib/esm/obsidian/i18n/locales/en.mjs +15 -1
- package/dist/lib/esm/obsidian/i18n/locales/translations-map.d.mts +14 -0
- package/dist/lib/esm/obsidian/plugin/index.d.mts +2 -0
- package/dist/lib/esm/obsidian/plugin/index.mjs +5 -1
- package/dist/lib/esm/obsidian/plugin/plugin-api.d.mts +34 -15
- package/dist/lib/esm/obsidian/plugin/plugin-api.mjs +2 -2
- package/dist/lib/esm/obsidian/plugin/plugin-install-state.d.mts +113 -0
- package/dist/lib/esm/obsidian/plugin/plugin-install-state.mjs +106 -0
- package/dist/lib/esm/obsidian/plugin/plugin-lifecycle-events.d.mts +119 -0
- package/dist/lib/esm/obsidian/plugin/plugin-lifecycle-events.mjs +54 -0
- package/dist/lib/esm/obsidian/plugin/plugin.d.mts +133 -4
- package/dist/lib/esm/obsidian/plugin/plugin.mjs +245 -21
- package/dist/lib/esm/script-utils/demo-vault-buttons.d.mts +8 -2
- package/dist/lib/esm/script-utils/demo-vault-buttons.mjs +3 -3
- package/dist/lib/esm/script-utils/linters/eslint-config.mjs +9 -1
- package/dist/lib/esm/script-utils/linters/eslint-rules/index.d.mts +1 -0
- package/dist/lib/esm/script-utils/linters/eslint-rules/index.mjs +3 -1
- package/dist/lib/esm/script-utils/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.d.mts +10 -0
- package/dist/lib/esm/script-utils/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian.mjs +302 -0
- package/dist/lib/esm/script-utils/linters/eslint-rules/obsidian-dev-utils-plugin.mjs +3 -1
- package/obsidian/components/plugin-gate-component/package.json +6 -0
- package/obsidian/plugin/plugin-install-state/package.json +6 -0
- package/obsidian/plugin/plugin-lifecycle-events/package.json +6 -0
- package/package.json +1 -1
- package/script-utils/linters/eslint-rules/no-over-cap-wait-in-eval-in-obsidian/package.json +6 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/// <reference path="../../library.d.cts" />
|
|
2
|
+
/**
|
|
3
|
+
* @file
|
|
4
|
+
*
|
|
5
|
+
* The gate on a plugin's feature surface: what must be PRESENT for it to run, and what must NOT be.
|
|
6
|
+
*
|
|
7
|
+
* Both halves answer the same question — may this plugin's `onloadImpl` run right now? — so they are one
|
|
8
|
+
* component rather than two. A second, independent gate would double-load the surface and stack a second
|
|
9
|
+
* "blocked" settings tab onto the same plugin, and neither could see the other's reason for refusing.
|
|
10
|
+
*
|
|
11
|
+
* ## Dependencies: a plugin declaring what it cannot work without
|
|
12
|
+
*
|
|
13
|
+
* This is the strict sibling of `PluginSuggestionComponent`, and the difference is the whole point. A
|
|
14
|
+
* SUGGESTION is an offer — the host keeps working without it and simply cannot do one thing. A DEPENDENCY
|
|
15
|
+
* is a requirement: `onloadImpl` never runs, no command is registered, no handler is installed, nothing is
|
|
16
|
+
* patched. Reach for a suggestion when the other plugin adds something; reach for a dependency when the
|
|
17
|
+
* host's advertised behavior is not there without it.
|
|
18
|
+
*
|
|
19
|
+
* Obsidian has no dependency field in a manifest, which is exactly the problem this closes. Without one,
|
|
20
|
+
* a user meeting an unfamiliar plugin in their list months later has nothing telling them it is
|
|
21
|
+
* load-bearing — they remove it, and the breakage surfaces weeks after that as damage they cannot connect
|
|
22
|
+
* to anything they did. So the relationship is made visible from both ends and enforced while it holds:
|
|
23
|
+
* the dependent explains itself where the user is looking, repairs itself in one click, and reacts the
|
|
24
|
+
* INSTANT the dependency goes away rather than degrading quietly.
|
|
25
|
+
*
|
|
26
|
+
* Three choices are deliberate and worth stating, because each has an obvious-looking alternative:
|
|
27
|
+
*
|
|
28
|
+
* - **Blocked means enabled-but-inert, never self-disabled.** Calling `disablePluginAndSave` on itself
|
|
29
|
+
* would be the literal reading of "refuses to load", and it rewrites a config that belongs to the user —
|
|
30
|
+
* who would then have to remember to re-enable it after fixing the dependency. Staying enabled and inert
|
|
31
|
+
* says the same thing to the user, changes nothing they own, and can undo itself.
|
|
32
|
+
* - **Blocked is not an error.** Throwing from `onload` marks the plugin failed in Obsidian and hands the
|
|
33
|
+
* user a stack trace instead of a sentence and a button.
|
|
34
|
+
* - **A dependency must publish an API.** That is what makes presence, absence, version and departure all
|
|
35
|
+
* observable through one mechanism — `watchPluginApi`'s reference is live, is revoked when the provider
|
|
36
|
+
* unloads, and already classifies not-installed against not-enabled against too-old. A provider with
|
|
37
|
+
* nothing to expose can publish an empty API purely so it can be depended upon; the alternative would be
|
|
38
|
+
* a second, weaker detection path to maintain beside it.
|
|
39
|
+
*
|
|
40
|
+
* ## Conflicts: a plugin declaring what it refuses to run beside
|
|
41
|
+
*
|
|
42
|
+
* The inverse relationship, and it needs its own detection path because the dependency one does not fit.
|
|
43
|
+
* A conflicting plugin is typically an OLD version of some other plugin that still owns behavior this one
|
|
44
|
+
* has taken over — it publishes no API at all, so there is no `apiVersionRange` to compare against.
|
|
45
|
+
*
|
|
46
|
+
* The argument for refusing rather than competing comes from the case this generalizes: two rename/delete
|
|
47
|
+
* handlers acting on one rename corrupt links and move attachments twice, and there is no reliable way to
|
|
48
|
+
* win that race — a handler is elected by registry order, but the patches that do the work sit outside
|
|
49
|
+
* that election, so whichever plugin loaded first keeps a hand on the wheel. Every scheme for seizing
|
|
50
|
+
* control from inside is load-order dependent. Refusing is deterministic where competing is not, and a
|
|
51
|
+
* vault that briefly has no handler is a far better outcome than one with two.
|
|
52
|
+
*
|
|
53
|
+
* Two details of that detection carry over verbatim, because both are load-bearing:
|
|
54
|
+
*
|
|
55
|
+
* - **Versions are read, never the registry.** A plugin that has not loaded yet has registered nothing, so
|
|
56
|
+
* asking the registry gives a different answer depending on when it is asked. `app.plugins.manifests` is
|
|
57
|
+
* populated for every installed plugin at startup, whatever the load order turns out to be.
|
|
58
|
+
* - **An unparseable version counts as conflicting.** Failing closed is the safe direction: a false alarm
|
|
59
|
+
* costs a notice, a false all-clear costs a vault.
|
|
60
|
+
*
|
|
61
|
+
* Not every overlap is that severe, which is why a conflict declares a {@link PluginConflictSeverity}.
|
|
62
|
+
* Two plugins shipping the same command duplicate a palette entry and do the work twice — annoying, not
|
|
63
|
+
* corrupting — and refusing to load over that would be a worse outcome than the overlap. Those declare
|
|
64
|
+
* {@link PluginConflictSeverity.Warn} and both keep running.
|
|
65
|
+
*
|
|
66
|
+
* ## What this can and cannot see
|
|
67
|
+
*
|
|
68
|
+
* Obsidian raises no event when ANOTHER plugin is enabled or disabled (see `plugin-lifecycle-events.ts`),
|
|
69
|
+
* so live conflict detection has a real ceiling and it is stated here rather than implied away. A
|
|
70
|
+
* conflicting plugin built on this library announces itself through the lifecycle broadcast, and is
|
|
71
|
+
* therefore caught the moment it is enabled or disabled. One that is not — an old release predating the
|
|
72
|
+
* broadcast, or a plugin by another author entirely — is caught at the next load, which is when its
|
|
73
|
+
* manifest is read.
|
|
74
|
+
*/
|
|
75
|
+
import type { Plugin } from 'obsidian' with { 'resolution-mode': 'import' };
|
|
76
|
+
import type { PluginNoticeComponent } from './plugin-notice-component.cjs';
|
|
77
|
+
import { ComponentEx } from './component-ex.cjs';
|
|
78
|
+
/**
|
|
79
|
+
* How badly two plugins running side by side goes wrong, and therefore what this one does about it.
|
|
80
|
+
*/
|
|
81
|
+
export declare enum PluginConflictSeverity {
|
|
82
|
+
/**
|
|
83
|
+
* The host refuses to run at all while the conflict holds: `onloadImpl` never runs, nothing is
|
|
84
|
+
* registered, and the plugin explains itself the way a missing dependency does.
|
|
85
|
+
*
|
|
86
|
+
* For an overlap where both plugins acting on the same operation damages the vault.
|
|
87
|
+
*/
|
|
88
|
+
Block = "block",
|
|
89
|
+
/**
|
|
90
|
+
* The host runs anyway and says the overlap is there.
|
|
91
|
+
*
|
|
92
|
+
* For an overlap that is annoying rather than destructive — duplicate commands, work done twice — where
|
|
93
|
+
* refusing to load would cost the user more than the overlap does.
|
|
94
|
+
*/
|
|
95
|
+
Warn = "warn"
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A plugin another plugin refuses to run beside, or warns about running beside.
|
|
99
|
+
*/
|
|
100
|
+
export interface PluginConflict {
|
|
101
|
+
/**
|
|
102
|
+
* The semver range of the OTHER plugin's versions that conflict, e.g. `'<12.0.0'` for "every version
|
|
103
|
+
* before the one that gave this behavior up".
|
|
104
|
+
*
|
|
105
|
+
* A range rather than a minimum, so an overlap confined to one major (`'>=3 <4'`) is expressible, and so
|
|
106
|
+
* is a plugin that conflicts at every version — spell that `'>=0.0.0'`, since `compare-versions` rejects
|
|
107
|
+
* a bare `*`. Evaluated against `manifest.version`; a version that cannot be parsed counts as
|
|
108
|
+
* conflicting.
|
|
109
|
+
*/
|
|
110
|
+
readonly conflictingVersionRange: string;
|
|
111
|
+
/**
|
|
112
|
+
* The `manifest.id` of the conflicting plugin, as listed in Obsidian's community plugin registry.
|
|
113
|
+
*/
|
|
114
|
+
readonly pluginId: string;
|
|
115
|
+
/**
|
|
116
|
+
* The display name of the conflicting plugin, shown to the user.
|
|
117
|
+
*/
|
|
118
|
+
readonly pluginName: string;
|
|
119
|
+
/**
|
|
120
|
+
* A localized sentence saying what goes wrong when both run, shown in the banner.
|
|
121
|
+
*
|
|
122
|
+
* The declaring plugin owns this string because only it knows what the two of them collide over, and a
|
|
123
|
+
* user being asked to disable something deserves to be told why.
|
|
124
|
+
*/
|
|
125
|
+
readonly reason: string;
|
|
126
|
+
/**
|
|
127
|
+
* What this plugin does about the conflict.
|
|
128
|
+
*/
|
|
129
|
+
readonly severity: PluginConflictSeverity;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A plugin another plugin cannot work without.
|
|
133
|
+
*/
|
|
134
|
+
export interface PluginDependency {
|
|
135
|
+
/**
|
|
136
|
+
* The semver range of API contract versions the dependent compiled against, e.g. `'^2'`.
|
|
137
|
+
*
|
|
138
|
+
* A dependency whose published API falls outside the range counts as UNSATISFIED, which is what turns a
|
|
139
|
+
* silent behavioral mismatch between two independently released plugins into a visible "update this
|
|
140
|
+
* one" message. Spell "any version" as `'>=0.0.0'` — `compare-versions` rejects a bare `*`.
|
|
141
|
+
*/
|
|
142
|
+
readonly apiVersionRange: string;
|
|
143
|
+
/**
|
|
144
|
+
* The `manifest.id` of the required plugin, as listed in Obsidian's community plugin registry.
|
|
145
|
+
*/
|
|
146
|
+
readonly pluginId: string;
|
|
147
|
+
/**
|
|
148
|
+
* The display name of the required plugin, shown to the user.
|
|
149
|
+
*/
|
|
150
|
+
readonly pluginName: string;
|
|
151
|
+
/**
|
|
152
|
+
* A localized sentence saying what the dependent does with this plugin, shown in the settings banner.
|
|
153
|
+
*
|
|
154
|
+
* The dependent owns this string because only it knows what it uses the other plugin for, and a user
|
|
155
|
+
* being asked to install something deserves to be told why.
|
|
156
|
+
*/
|
|
157
|
+
readonly reason: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Parameters for the {@link PluginGateComponent} constructor.
|
|
161
|
+
*/
|
|
162
|
+
export interface PluginGateComponentConstructorParams {
|
|
163
|
+
/**
|
|
164
|
+
* The conflicts to enforce. An empty list means the plugin refuses to run beside nothing.
|
|
165
|
+
*/
|
|
166
|
+
readonly conflicts: readonly PluginConflict[];
|
|
167
|
+
/**
|
|
168
|
+
* The dependencies to enforce. An empty list means the plugin depends on nothing, and its feature
|
|
169
|
+
* surface loads immediately.
|
|
170
|
+
*/
|
|
171
|
+
readonly dependencies: readonly PluginDependency[];
|
|
172
|
+
/**
|
|
173
|
+
* Loads the host plugin's feature surface. Called once every dependency is satisfied and no blocking
|
|
174
|
+
* conflict holds, and again after a gate that had closed opens back up.
|
|
175
|
+
*
|
|
176
|
+
* @returns A {@link Promise} that resolves once the surface is loaded.
|
|
177
|
+
*/
|
|
178
|
+
loadFeatureSurface(this: void): Promise<void>;
|
|
179
|
+
/**
|
|
180
|
+
* The host plugin — the one declaring the dependencies and conflicts.
|
|
181
|
+
*/
|
|
182
|
+
readonly plugin: Plugin;
|
|
183
|
+
/**
|
|
184
|
+
* The host plugin's notice component, used to say what is missing, what is in the way, and what changed.
|
|
185
|
+
*/
|
|
186
|
+
readonly pluginNoticeComponent: PluginNoticeComponent;
|
|
187
|
+
/**
|
|
188
|
+
* Unloads the host plugin's feature surface. Called when a gate that had been open closes.
|
|
189
|
+
*/
|
|
190
|
+
unloadFeatureSurface(this: void): void;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Enforces a plugin's mandatory dependencies and declared conflicts, gating its feature surface on both.
|
|
194
|
+
*/
|
|
195
|
+
export declare class PluginGateComponent extends ComponentEx {
|
|
196
|
+
private readonly announcedWarningPluginIds;
|
|
197
|
+
private readonly apiRefs;
|
|
198
|
+
private blockedSettingTab;
|
|
199
|
+
private readonly conflicts;
|
|
200
|
+
private readonly dependencies;
|
|
201
|
+
private hasAnnouncedBlocked;
|
|
202
|
+
private isFeatureSurfaceLoaded;
|
|
203
|
+
private isLayoutReady;
|
|
204
|
+
private readonly loadFeatureSurface;
|
|
205
|
+
private readonly plugin;
|
|
206
|
+
private readonly pluginNoticeComponent;
|
|
207
|
+
private readonly unloadFeatureSurface;
|
|
208
|
+
private get app();
|
|
209
|
+
/**
|
|
210
|
+
* Creates an instance of {@link PluginGateComponent}.
|
|
211
|
+
*
|
|
212
|
+
* @param params - The constructor parameters.
|
|
213
|
+
*/
|
|
214
|
+
constructor(params: PluginGateComponentConstructorParams);
|
|
215
|
+
/**
|
|
216
|
+
* Starts watching every declared dependency and conflict.
|
|
217
|
+
*/
|
|
218
|
+
onload(): void;
|
|
219
|
+
/**
|
|
220
|
+
* Evaluates the gate once the watches are in place, loading the feature surface if it is already open.
|
|
221
|
+
*
|
|
222
|
+
* @returns A {@link Promise} that resolves once the first evaluation is complete.
|
|
223
|
+
*/
|
|
224
|
+
onloadAsync(): Promise<void>;
|
|
225
|
+
/**
|
|
226
|
+
* Renders a banner for every conflict the host is running alongside, so a plugin can put the overlap in
|
|
227
|
+
* its own settings tab.
|
|
228
|
+
*
|
|
229
|
+
* Consumer-invoked, exactly like `PluginSuggestionComponent.renderBanner`: the library registers the
|
|
230
|
+
* settings tab a BLOCKED plugin needs, because that plugin never got to register one of its own, but it
|
|
231
|
+
* has no hook into the tab a running plugin builds. Renders nothing when no warning conflict holds.
|
|
232
|
+
*
|
|
233
|
+
* @param containerEl - The element to render into.
|
|
234
|
+
*/
|
|
235
|
+
renderConflictWarningBanner(containerEl: HTMLElement): void;
|
|
236
|
+
private announceWarnings;
|
|
237
|
+
private createBlockedMessage;
|
|
238
|
+
private createConflictAppearedMessage;
|
|
239
|
+
private createConflictBlockedMessage;
|
|
240
|
+
private createConflictWarningMessage;
|
|
241
|
+
private createDependencyLostMessage;
|
|
242
|
+
/**
|
|
243
|
+
* Finds the declared conflicts of one severity that are currently in force.
|
|
244
|
+
*
|
|
245
|
+
* @param severity - The severity to select.
|
|
246
|
+
* @returns The conflicts holding right now, in the order they were declared.
|
|
247
|
+
*/
|
|
248
|
+
private getActiveConflicts;
|
|
249
|
+
private getUnsatisfiedDependencies;
|
|
250
|
+
private hideBlockedSettingTab;
|
|
251
|
+
/**
|
|
252
|
+
* Decides whether one declared conflict is in force right now.
|
|
253
|
+
*
|
|
254
|
+
* Only an ENABLED plugin counts. One that is installed but switched off registers nothing, so it cannot
|
|
255
|
+
* collide, and acting on it would be an alarm the user can only answer by uninstalling something they
|
|
256
|
+
* have already turned off.
|
|
257
|
+
*
|
|
258
|
+
* @param conflict - The declared conflict.
|
|
259
|
+
* @returns Whether the conflicting plugin is enabled at a conflicting version.
|
|
260
|
+
*/
|
|
261
|
+
private isConflictActive;
|
|
262
|
+
/**
|
|
263
|
+
* Says what is in the way, and puts the same explanation where the user will look for the plugin's
|
|
264
|
+
* settings.
|
|
265
|
+
*
|
|
266
|
+
* @param unsatisfiedDependencies - The dependencies that are not currently satisfied.
|
|
267
|
+
* @param blockingConflicts - The conflicts currently refusing the plugin the right to run.
|
|
268
|
+
*/
|
|
269
|
+
private presentUnsatisfied;
|
|
270
|
+
/**
|
|
271
|
+
* Re-evaluates the gate and moves the feature surface to match.
|
|
272
|
+
*
|
|
273
|
+
* @returns A {@link Promise} that resolves once the surface matches the gate.
|
|
274
|
+
*/
|
|
275
|
+
private refresh;
|
|
276
|
+
/**
|
|
277
|
+
* Renders the blocked explanation into a settings-tab container: what is missing or in the way, why it
|
|
278
|
+
* matters, and the button that fixes it.
|
|
279
|
+
*
|
|
280
|
+
* @param containerEl - The element to render into.
|
|
281
|
+
* @param unsatisfiedDependencies - The dependencies that are not currently satisfied.
|
|
282
|
+
* @param blockingConflicts - The conflicts currently refusing the plugin the right to run.
|
|
283
|
+
*/
|
|
284
|
+
private renderBlockedBanner;
|
|
285
|
+
/**
|
|
286
|
+
* Renders one conflict: what it is, why it matters, and the two ways out of it.
|
|
287
|
+
*
|
|
288
|
+
* The repair is offered on the OTHER plugin — disabling it is the one thing this plugin can do in a
|
|
289
|
+
* click, since it cannot update someone else's plugin — and it is the persisted `disablePluginAndSave`
|
|
290
|
+
* rather than the transient disable, because the user asked for it by clicking.
|
|
291
|
+
*
|
|
292
|
+
* @param containerEl - The element to render into.
|
|
293
|
+
* @param conflict - The conflict to render.
|
|
294
|
+
* @param messageFragment - The sentence explaining the conflict.
|
|
295
|
+
*/
|
|
296
|
+
private renderConflictEntry;
|
|
297
|
+
private renderOpenSettingsButton;
|
|
298
|
+
private showBlockedSettingTab;
|
|
299
|
+
}
|
|
@@ -148,17 +148,12 @@ __export(plugin_suggestion_component_exports, {
|
|
|
148
148
|
module.exports = __toCommonJS(plugin_suggestion_component_exports);
|
|
149
149
|
var import_obsidian = require('obsidian');
|
|
150
150
|
var import_async = require('../../async.cjs');
|
|
151
|
-
var import_community_plugins = require('../community-plugins.cjs');
|
|
152
151
|
var import_css_class = require('../css-class.cjs');
|
|
153
152
|
var import_i18n = require('../i18n/i18n.cjs');
|
|
153
|
+
var import_plugin_install_state = require('../plugin/plugin-install-state.cjs');
|
|
154
154
|
var import_component_ex = require('./component-ex.cjs');
|
|
155
155
|
var import_layout_ready_component = require('./layout-ready-component.cjs');
|
|
156
|
-
|
|
157
|
-
SuggestedPluginState2["Enabled"] = "enabled";
|
|
158
|
-
SuggestedPluginState2["InstalledButDisabled"] = "installedButDisabled";
|
|
159
|
-
SuggestedPluginState2["NotInstalled"] = "notInstalled";
|
|
160
|
-
return SuggestedPluginState2;
|
|
161
|
-
})(SuggestedPluginState || {});
|
|
156
|
+
const SuggestedPluginState = import_plugin_install_state.InstalledPluginState;
|
|
162
157
|
class PluginSuggestionComponent extends import_component_ex.ComponentEx {
|
|
163
158
|
app;
|
|
164
159
|
isSuggestionDeclined;
|
|
@@ -190,10 +185,10 @@ class PluginSuggestionComponent extends import_component_ex.ComponentEx {
|
|
|
190
185
|
* @returns The {@link SuggestedPluginState}.
|
|
191
186
|
*/
|
|
192
187
|
getSuggestedPluginState() {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
188
|
+
return (0, import_plugin_install_state.getInstalledPluginState)({
|
|
189
|
+
app: this.app,
|
|
190
|
+
pluginId: this.suggestedPluginId
|
|
191
|
+
});
|
|
197
192
|
}
|
|
198
193
|
/**
|
|
199
194
|
* Installs (when needed) and enables the suggested plugin, reporting the outcome as a notice.
|
|
@@ -202,32 +197,16 @@ class PluginSuggestionComponent extends import_component_ex.ComponentEx {
|
|
|
202
197
|
* reported.
|
|
203
198
|
*/
|
|
204
199
|
async installAndEnableSuggestedPlugin() {
|
|
205
|
-
|
|
206
|
-
if (state === "enabled" /* Enabled */) {
|
|
200
|
+
if (this.getSuggestedPluginState() === SuggestedPluginState.Enabled) {
|
|
207
201
|
return;
|
|
208
202
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
} else {
|
|
216
|
-
await (0, import_community_plugins.installConfigureEnableCommunityPlugin)({
|
|
217
|
-
app: this.app,
|
|
218
|
-
pluginId: this.suggestedPluginId
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
} catch (error) {
|
|
222
|
-
this.pluginNoticeComponent.showNotice((0, import_i18n.t)(($) => $.obsidianDevUtils.pluginSuggestion.installFailed, {
|
|
223
|
-
pluginName: this.suggestedPluginName
|
|
224
|
-
}));
|
|
225
|
-
throw error;
|
|
226
|
-
}
|
|
203
|
+
await (0, import_plugin_install_state.installAndEnablePlugin)({
|
|
204
|
+
app: this.app,
|
|
205
|
+
pluginId: this.suggestedPluginId,
|
|
206
|
+
pluginName: this.suggestedPluginName,
|
|
207
|
+
pluginNoticeComponent: this.pluginNoticeComponent
|
|
208
|
+
});
|
|
227
209
|
await this.setSuggestionDeclined(false);
|
|
228
|
-
this.pluginNoticeComponent.showNotice((0, import_i18n.t)(($) => $.obsidianDevUtils.pluginSuggestion.installed, {
|
|
229
|
-
pluginName: this.suggestedPluginName
|
|
230
|
-
}));
|
|
231
210
|
}
|
|
232
211
|
/**
|
|
233
212
|
* Loads the component, showing the suggestion notice once the layout is ready AND the host's settings
|
|
@@ -267,7 +246,7 @@ class PluginSuggestionComponent extends import_component_ex.ComponentEx {
|
|
|
267
246
|
*/
|
|
268
247
|
renderBanner(containerEl) {
|
|
269
248
|
const state = this.getSuggestedPluginState();
|
|
270
|
-
if (state ===
|
|
249
|
+
if (state === SuggestedPluginState.Enabled) {
|
|
271
250
|
return;
|
|
272
251
|
}
|
|
273
252
|
const bannerEl = containerEl.createDiv({
|
|
@@ -280,12 +259,12 @@ class PluginSuggestionComponent extends import_component_ex.ComponentEx {
|
|
|
280
259
|
}
|
|
281
260
|
getActionButtonText(state) {
|
|
282
261
|
return (0, import_i18n.t)(
|
|
283
|
-
($) => state ===
|
|
262
|
+
($) => state === SuggestedPluginState.InstalledButDisabled ? $.obsidianDevUtils.pluginSuggestion.enable : $.obsidianDevUtils.pluginSuggestion.install
|
|
284
263
|
);
|
|
285
264
|
}
|
|
286
265
|
showSuggestionNotice() {
|
|
287
266
|
const state = this.getSuggestedPluginState();
|
|
288
|
-
if (state ===
|
|
267
|
+
if (state === SuggestedPluginState.Enabled || this.isSuggestionDeclined()) {
|
|
289
268
|
return;
|
|
290
269
|
}
|
|
291
270
|
const fragment = createFragment((fragmentEl) => {
|
|
@@ -306,4 +285,4 @@ class PluginSuggestionComponent extends import_component_ex.ComponentEx {
|
|
|
306
285
|
PluginSuggestionComponent,
|
|
307
286
|
SuggestedPluginState
|
|
308
287
|
});
|
|
309
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL2NvbXBvbmVudHMvcGx1Z2luLXN1Z2dlc3Rpb24tY29tcG9uZW50LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogQ29tcG9uZW50IHRoYXQgc3VnZ2VzdHMgaW5zdGFsbGluZyBhbm90aGVyIGNvbW11bml0eSBwbHVnaW4gdGhlIGhvc3QgcGx1Z2luIG5lZWRzIGluIG9yZGVyIHRvIG9mZmVyXG4gKiBzb21lIG9mIGl0cyBiZWhhdmlvci5cbiAqXG4gKiBBIHN1Z2dlc3Rpb24gaXMgbm90IGEgZGVwZW5kZW5jeS4gT2JzaWRpYW4gaGFzIG5vIG1lY2hhbmlzbSBmb3Igb25lIGNvbW11bml0eSBwbHVnaW4gdG8gcmVxdWlyZVxuICogYW5vdGhlciwgYW5kIGludmVudGluZyBvbmUgYnkgcmVmdXNpbmcgdG8gbG9hZCB3b3VsZCBwdW5pc2ggdGhlIHVzZXIgZm9yIHNvbWV0aGluZyB0aGV5IG5ldmVyIGFncmVlZFxuICogdG8uIFNvIHRoZSBob3N0IHBsdWdpbiBrZWVwcyB3b3JraW5nIHdpdGhvdXQgdGhlIHN1Z2dlc3RlZCBwbHVnaW4gXHUyMDE0IGl0IHNpbXBseSBjYW5ub3Qgb2ZmZXIgd2hhdGV2ZXJcbiAqIHRoYXQgcGx1Z2luIG93bnMgXHUyMDE0IGFuZCB0aGlzIGNvbXBvbmVudCBhc2tzLCBvbmNlLCB3aGV0aGVyIHRoZSB1c2VyIHdvdWxkIGxpa2UgaXQgaW5zdGFsbGVkLlxuICpcbiAqIFRoZSBhc2sgaXMgc3VyZmFjZWQgdHdpY2UsIGRlbGliZXJhdGVseSwgYmVjYXVzZSB0aGUgdHdvIHBsYWNlbWVudHMgYW5zd2VyIGRpZmZlcmVudCBxdWVzdGlvbnM6XG4gKiBhIG5vdGljZSBvbiBsb2FkIChcInlvdSBhcmUgbWlzc2luZyBzb21ldGhpbmcgeW91IHByb2JhYmx5IHdhbnRcIikgYW5kIGEgc2V0dGluZ3MtdGFiIGJhbm5lciAoXCJ0aGVcbiAqIHNldHRpbmdzIHlvdSBjYW1lIGxvb2tpbmcgZm9yIGxpdmUgaW4gYW5vdGhlciBwbHVnaW5cIikuIERlY2xpbmluZyBzaWxlbmNlcyBvbmx5IHRoZSBub3RpY2UgXHUyMDE0IGEgdXNlclxuICogd2hvIG9wZW5zIHRoZSBzZXR0aW5ncyB0YWIgaXMgYXNraW5nIGFib3V0IHRoZSBmZWF0dXJlIHJpZ2h0IHRoZW4sIHNvIHRoZSBiYW5uZXIgc3RheXMuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBBcHAgfSBmcm9tICdvYnNpZGlhbic7XG5pbXBvcnQgdHlwZSB7IFByb21pc2FibGUgfSBmcm9tICd0eXBlLWZlc3QnO1xuXG5pbXBvcnQgeyBCdXR0b25Db21wb25lbnQgfSBmcm9tICdvYnNpZGlhbic7XG5cbmltcG9ydCB0eXBlIHsgUGx1Z2luTm90aWNlQ29tcG9uZW50IH0gZnJvbSAnLi9wbHVnaW4tbm90aWNlLWNvbXBvbmVudC50cyc7XG5pbXBvcnQgdHlwZSB7IFBsdWdpblNldHRpbmdzQ29tcG9uZW50QmFzZSB9IGZyb20gJy4vcGx1Z2luLXNldHRpbmdzLWNvbXBvbmVudC50cyc7XG5cbmltcG9ydCB7IGNvbnZlcnRBc3luY1RvU3luYyB9IGZyb20gJy4uLy4uL2FzeW5jLnRzJztcbmltcG9ydCB7XG4gIGVuYWJsZUNvbW11bml0eVBsdWdpbixcbiAgaW5zdGFsbENvbmZpZ3VyZUVuYWJsZUNvbW11bml0eVBsdWdpblxufSBmcm9tICcuLi9jb21tdW5pdHktcGx1Z2lucy50cyc7XG5pbXBvcnQgeyBDc3NDbGFzcyB9IGZyb20gJy4uL2Nzcy1jbGFzcy50cyc7XG5pbXBvcnQgeyB0IH0gZnJvbSAnLi4vaTE4bi9pMThuLnRzJztcbmltcG9ydCB7IENvbXBvbmVudEV4IH0gZnJvbSAnLi9jb21wb25lbnQtZXgudHMnO1xuaW1wb3J0IHsgQ2FsbGJhY2tMYXlvdXRSZWFkeUNvbXBvbmVudCB9IGZyb20gJy4vbGF5b3V0LXJlYWR5LWNvbXBvbmVudC50cyc7XG5cbi8qKlxuICogSG93IHRoZSBzdWdnZXN0ZWQgcGx1Z2luIGlzIGN1cnJlbnRseSBwcmVzZW50IGluIHRoZSB2YXVsdC5cbiAqL1xuZXhwb3J0IGVudW0gU3VnZ2VzdGVkUGx1Z2luU3RhdGUge1xuICAvKipcbiAgICogSW5zdGFsbGVkIGFuZCBlbmFibGVkIFx1MjAxNCB0aGVyZSBpcyBub3RoaW5nIHRvIHN1Z2dlc3QuXG4gICAqL1xuICBFbmFibGVkID0gJ2VuYWJsZWQnLFxuXG4gIC8qKlxuICAgKiBJbnN0YWxsZWQgYnV0IGRpc2FibGVkLiBPbmx5IGFuIGVuYWJsZSBpcyBuZWVkZWQsIHNvIG5vIGRvd25sb2FkIGhhcHBlbnMuXG4gICAqL1xuICBJbnN0YWxsZWRCdXREaXNhYmxlZCA9ICdpbnN0YWxsZWRCdXREaXNhYmxlZCcsXG5cbiAgLyoqXG4gICAqIE5vdCBpbnN0YWxsZWQgYXQgYWxsLlxuICAgKi9cbiAgTm90SW5zdGFsbGVkID0gJ25vdEluc3RhbGxlZCdcbn1cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciB0aGUge0BsaW5rIFBsdWdpblN1Z2dlc3Rpb25Db21wb25lbnR9IGNvbnN0cnVjdG9yLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBsdWdpblN1Z2dlc3Rpb25Db21wb25lbnRDb25zdHJ1Y3RvclBhcmFtcyB7XG4gIC8qKlxuICAgKiBUaGUgT2JzaWRpYW4gYXBwIGluc3RhbmNlLlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwOiBBcHA7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHVzZXIgaGFzIGFscmVhZHkgZGVjbGluZWQgdGhpcyBzdWdnZXN0aW9uLlxuICAgKlxuICAgKiBTdG9yYWdlIGJlbG9uZ3MgdG8gdGhlIGhvc3QgcGx1Z2luICh0eXBpY2FsbHkgb25lIG9mIGl0cyBzZXR0aW5ncyksIGJlY2F1c2UgdGhpcyBjb21wb25lbnQgaGFzIG5vXG4gICAqIGBkYXRhLmpzb25gIG9mIGl0cyBvd24gYW5kIGEgZGVjbGluZSBoYXMgdG8gb3V0bGl2ZSBhIHJlbG9hZC5cbiAgICpcbiAgICogT25seSBldmVyIGNhbGxlZCBvbmNlIHtAbGluayBwbHVnaW5TZXR0aW5nc0NvbXBvbmVudH0gcmVwb3J0cyBpdHMgc2V0dGluZ3MgbG9hZGVkLCBzbyBhbiBpbXBsZW1lbnRhdGlvblxuICAgKiByZWFkaW5nIGEgc2V0dGluZyBpcyBndWFyYW50ZWVkIHRvIHJlYWQgdGhlIHN0b3JlZCB2YWx1ZSByYXRoZXIgdGhhbiBpdHMgZGVmYXVsdC5cbiAgICpcbiAgICogQHJldHVybnMgYHRydWVgIHdoZW4gdGhlIHN1Z2dlc3Rpb24gaGFzIGJlZW4gZGVjbGluZWQuXG4gICAqL1xuICBpc1N1Z2dlc3Rpb25EZWNsaW5lZCh0aGlzOiB2b2lkKTogYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIG5vdGljZSBjb21wb25lbnQgb2YgdGhlIHBsdWdpbiBtYWtpbmcgdGhlIHN1Z2dlc3Rpb24sIHVzZWQgdG8gc2hvdyB0aGUgc3VnZ2VzdGlvbiBhbmQgaXRzXG4gICAqIG91dGNvbWUuXG4gICAqL1xuICByZWFkb25seSBwbHVnaW5Ob3RpY2VDb21wb25lbnQ6IFBsdWdpbk5vdGljZUNvbXBvbmVudDtcblxuICAvKipcbiAgICogVGhlIHNldHRpbmdzIGNvbXBvbmVudCBob2xkaW5nIHdoYXRldmVyIHtAbGluayBpc1N1Z2dlc3Rpb25EZWNsaW5lZH0gcmVhZHMuXG4gICAqXG4gICAqIFRha2VuIGFzIGEgd2hvbGUgY29tcG9uZW50IHJhdGhlciB0aGFuIGFzIGEgYmFyZSBcInJlYWR5XCIgZmxhZyBzbyB0aGUgaG9zdCBjYW5ub3QgZm9yZ2V0IHRvIHdpcmUgdGhlXG4gICAqIHdhaXQ6IHRoZSBub3RpY2UgaXMgZGVjaWRlZCBvbmx5IGFmdGVyIHRoaXMgY29tcG9uZW50IGhhcyByZWFkIGBkYXRhLmpzb25gLiBTZWVcbiAgICoge0BsaW5rIFBsdWdpblNldHRpbmdzQ29tcG9uZW50QmFzZS53aGVuTG9hZGVkRnJvbUZpbGV9IGZvciB3aHkgdGhlIHJlYWQgY2Fubm90IHNpbXBseSBoYXBwZW4gYXRcbiAgICogbGF5b3V0LXJlYWR5LlxuICAgKi9cbiAgcmVhZG9ubHkgcGx1Z2luU2V0dGluZ3NDb21wb25lbnQ6IFBsdWdpblNldHRpbmdzQ29tcG9uZW50QmFzZTxvYmplY3Q+O1xuXG4gIC8qKlxuICAgKiBUaGUgbG9jYWxpemVkIHNlbnRlbmNlIGV4cGxhaW5pbmcgd2hhdCB0aGUgaG9zdCBwbHVnaW4gY2Fubm90IGRvIHdpdGhvdXQgdGhlIHN1Z2dlc3RlZCBwbHVnaW4uIFRoZVxuICAgKiBob3N0IHBsdWdpbiBvd25zIHRoaXMgc3RyaW5nOiBvbmx5IGl0IGtub3dzIHdoaWNoIG9mIGl0cyBmZWF0dXJlcyBhcmUgYWZmZWN0ZWQuXG4gICAqL1xuICByZWFkb25seSByZWFzb246IHN0cmluZztcblxuICAvKipcbiAgICogUmVjb3JkcyB0aGUgdXNlcidzIGFuc3dlciB0byB0aGUgc3VnZ2VzdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIGlzRGVjbGluZWQgLSBgdHJ1ZWAgd2hlbiB0aGUgdXNlciBkZWNsaW5lZC5cbiAgICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBhbnN3ZXIgaXMgcGVyc2lzdGVkLlxuICAgKi9cbiAgc2V0U3VnZ2VzdGlvbkRlY2xpbmVkKHRoaXM6IHZvaWQsIGlzRGVjbGluZWQ6IGJvb2xlYW4pOiBQcm9taXNhYmxlPHZvaWQ+O1xuXG4gIC8qKlxuICAgKiBUaGUgaWQgb2YgdGhlIHN1Z2dlc3RlZCBwbHVnaW4sIGFzIGxpc3RlZCBpbiBPYnNpZGlhbidzIGNvbW11bml0eSBwbHVnaW4gcmVnaXN0cnkuXG4gICAqL1xuICByZWFkb25seSBzdWdnZXN0ZWRQbHVnaW5JZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgZGlzcGxheSBuYW1lIG9mIHRoZSBzdWdnZXN0ZWQgcGx1Z2luLCBzaG93biB0byB0aGUgdXNlci5cbiAgICovXG4gIHJlYWRvbmx5IHN1Z2dlc3RlZFBsdWdpbk5hbWU6IHN0cmluZztcbn1cblxuLyoqXG4gKiBTdWdnZXN0cyBpbnN0YWxsaW5nIGFub3RoZXIgY29tbXVuaXR5IHBsdWdpbiwgdmlhIGEgbG9hZC10aW1lIG5vdGljZSBhbmQgYSBzZXR0aW5ncy10YWIgYmFubmVyLlxuICovXG5leHBvcnQgY2xhc3MgUGx1Z2luU3VnZ2VzdGlvbkNvbXBvbmVudCBleHRlbmRzIENvbXBvbmVudEV4IHtcbiAgcHJpdmF0ZSByZWFkb25seSBhcHA6IEFwcDtcbiAgcHJpdmF0ZSByZWFkb25seSBpc1N1Z2dlc3Rpb25EZWNsaW5lZDogKCkgPT4gYm9vbGVhbjtcbiAgcHJpdmF0ZSByZWFkb25seSBwbHVnaW5Ob3RpY2VDb21wb25lbnQ6IFBsdWdpbk5vdGljZUNvbXBvbmVudDtcbiAgcHJpdmF0ZSByZWFkb25seSBwbHVnaW5TZXR0aW5nc0NvbXBvbmVudDogUGx1Z2luU2V0dGluZ3NDb21wb25lbnRCYXNlPG9iamVjdD47XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVhc29uOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2V0U3VnZ2VzdGlvbkRlY2xpbmVkOiAoaXNEZWNsaW5lZDogYm9vbGVhbikgPT4gUHJvbWlzYWJsZTx2b2lkPjtcbiAgcHJpdmF0ZSByZWFkb25seSBzdWdnZXN0ZWRQbHVnaW5JZDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHN1Z2dlc3RlZFBsdWdpbk5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiB7QGxpbmsgUGx1Z2luU3VnZ2VzdGlvbkNvbXBvbmVudH0uXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgY29uc3RydWN0b3IgcGFyYW1ldGVycy5cbiAgICovXG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihwYXJhbXM6IFBsdWdpblN1Z2dlc3Rpb25Db21wb25lbnRDb25zdHJ1Y3RvclBhcmFtcykge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5hcHAgPSBwYXJhbXMuYXBwO1xuICAgIHRoaXMucGx1Z2luTm90aWNlQ29tcG9uZW50ID0gcGFyYW1zLnBsdWdpbk5vdGljZUNvbXBvbmVudDtcbiAgICB0aGlzLnBsdWdpblNldHRpbmdzQ29tcG9uZW50ID0gcGFyYW1zLnBsdWdpblNldHRpbmdzQ29tcG9uZW50O1xuICAgIHRoaXMucmVhc29uID0gcGFyYW1zLnJlYXNvbjtcbiAgICB0aGlzLnN1Z2dlc3RlZFBsdWdpbklkID0gcGFyYW1zLnN1Z2dlc3RlZFBsdWdpbklkO1xuICAgIHRoaXMuc3VnZ2VzdGVkUGx1Z2luTmFtZSA9IHBhcmFtcy5zdWdnZXN0ZWRQbHVnaW5OYW1lO1xuICAgIHRoaXMuaXNTdWdnZXN0aW9uRGVjbGluZWQgPSBwYXJhbXMuaXNTdWdnZXN0aW9uRGVjbGluZWQ7XG4gICAgdGhpcy5zZXRTdWdnZXN0aW9uRGVjbGluZWQgPSBwYXJhbXMuc2V0U3VnZ2VzdGlvbkRlY2xpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIGhvdyB0aGUgc3VnZ2VzdGVkIHBsdWdpbiBpcyBjdXJyZW50bHkgcHJlc2VudCBpbiB0aGUgdmF1bHQuXG4gICAqXG4gICAqIEByZXR1cm5zIFRoZSB7QGxpbmsgU3VnZ2VzdGVkUGx1Z2luU3RhdGV9LlxuICAgKi9cbiAgcHVibGljIGdldFN1Z2dlc3RlZFBsdWdpblN0YXRlKCk6IFN1Z2dlc3RlZFBsdWdpblN0YXRlIHtcbiAgICBpZiAodGhpcy5hcHAucGx1Z2lucy5lbmFibGVkUGx1Z2lucy5oYXModGhpcy5zdWdnZXN0ZWRQbHVnaW5JZCkpIHtcbiAgICAgIHJldHVybiBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5FbmFibGVkO1xuICAgIH1cblxuICAgIHJldHVybiBPYmplY3QuaGFzT3duKHRoaXMuYXBwLnBsdWdpbnMubWFuaWZlc3RzLCB0aGlzLnN1Z2dlc3RlZFBsdWdpbklkKVxuICAgICAgPyBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5JbnN0YWxsZWRCdXREaXNhYmxlZFxuICAgICAgOiBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5Ob3RJbnN0YWxsZWQ7XG4gIH1cblxuICAvKipcbiAgICogSW5zdGFsbHMgKHdoZW4gbmVlZGVkKSBhbmQgZW5hYmxlcyB0aGUgc3VnZ2VzdGVkIHBsdWdpbiwgcmVwb3J0aW5nIHRoZSBvdXRjb21lIGFzIGEgbm90aWNlLlxuICAgKlxuICAgKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHBsdWdpbiBpcyBlbmFibGVkLCBvciBvbmNlIHRoZSBmYWlsdXJlIGhhcyBiZWVuXG4gICAqIHJlcG9ydGVkLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGluc3RhbGxBbmRFbmFibGVTdWdnZXN0ZWRQbHVnaW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgc3RhdGUgPSB0aGlzLmdldFN1Z2dlc3RlZFBsdWdpblN0YXRlKCk7XG4gICAgaWYgKHN0YXRlID09PSBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5FbmFibGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGlmIChzdGF0ZSA9PT0gU3VnZ2VzdGVkUGx1Z2luU3RhdGUuSW5zdGFsbGVkQnV0RGlzYWJsZWQpIHtcbiAgICAgICAgYXdhaXQgZW5hYmxlQ29tbXVuaXR5UGx1Z2luKHtcbiAgICAgICAgICBhcHA6IHRoaXMuYXBwLFxuICAgICAgICAgIHBsdWdpbklkOiB0aGlzLnN1Z2dlc3RlZFBsdWdpbklkXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXdhaXQgaW5zdGFsbENvbmZpZ3VyZUVuYWJsZUNvbW11bml0eVBsdWdpbih7XG4gICAgICAgICAgYXBwOiB0aGlzLmFwcCxcbiAgICAgICAgICBwbHVnaW5JZDogdGhpcy5zdWdnZXN0ZWRQbHVnaW5JZFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5wbHVnaW5Ob3RpY2VDb21wb25lbnQuc2hvd05vdGljZSh0KCgkKSA9PiAkLm9ic2lkaWFuRGV2VXRpbHMucGx1Z2luU3VnZ2VzdGlvbi5pbnN0YWxsRmFpbGVkLCB7XG4gICAgICAgIHBsdWdpbk5hbWU6IHRoaXMuc3VnZ2VzdGVkUGx1Z2luTmFtZVxuICAgICAgfSkpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5zZXRTdWdnZXN0aW9uRGVjbGluZWQoZmFsc2UpO1xuICAgIHRoaXMucGx1Z2luTm90aWNlQ29tcG9uZW50LnNob3dOb3RpY2UodCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpblN1Z2dlc3Rpb24uaW5zdGFsbGVkLCB7XG4gICAgICBwbHVnaW5OYW1lOiB0aGlzLnN1Z2dlc3RlZFBsdWdpbk5hbWVcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIGNvbXBvbmVudCwgc2hvd2luZyB0aGUgc3VnZ2VzdGlvbiBub3RpY2Ugb25jZSB0aGUgbGF5b3V0IGlzIHJlYWR5IEFORCB0aGUgaG9zdCdzIHNldHRpbmdzXG4gICAqIGhhdmUgYmVlbiByZWFkIGZyb20gZGlzay5cbiAgICpcbiAgICogQm90aCB3YWl0cyBtYXR0ZXIsIGFuZCBuZWl0aGVyIGltcGxpZXMgdGhlIG90aGVyOlxuICAgKlxuICAgKiAtIExheW91dC1yZWFkeSwgYmVjYXVzZSBwbHVnaW5zIGxvYWQgaW4gYW4gdW5zcGVjaWZpZWQgb3JkZXIsIHNvIHRoZSBzdWdnZXN0ZWQgcGx1Z2luIG1heSB3ZWxsIGJlXG4gICAqICAgZW5hYmxlZCBhIG1vbWVudCBhZnRlciB0aGlzIG9uZS4gQ2hlY2tpbmcgZWFybGllciB3b3VsZCBzdWdnZXN0IGluc3RhbGxpbmcgc29tZXRoaW5nIHRoZSB1c2VyXG4gICAqICAgYWxyZWFkeSBoYXMuXG4gICAqIC0gU2V0dGluZ3MtbG9hZGVkLCBiZWNhdXNlIHtAbGluayBQbHVnaW5TdWdnZXN0aW9uQ29tcG9uZW50Q29uc3RydWN0b3JQYXJhbXMuaXNTdWdnZXN0aW9uRGVjbGluZWR9XG4gICAqICAgcmVhZHMgYSBzZXR0aW5nIG9mIHRoZSBob3N0LCBhbmQgdGhlIGhvc3QncyBzZXR0aW5ncyBjb21wb25lbnQgaXMgYSBTSUJMSU5HIHdob3NlIG93biBhc3luYyBsb2FkIGlzXG4gICAqICAgc3RpbGwgaW4gZmxpZ2h0IGhlcmUuIE9uIGEgbGF5b3V0IHRoYXQgaXMgYWxyZWFkeSByZWFkeSBcdTIwMTQgYSBydW50aW1lIGVuYWJsZSBmcm9tIHRoZSBDb21tdW5pdHlcbiAgICogICBQbHVnaW5zIHRhYiwgb3IgYSByZS1lbmFibGUgYWZ0ZXIgYW4gdXBkYXRlIFx1MjAxNCB0aGUgbGF5b3V0LXJlYWR5IGNhbGxiYWNrIGZpcmVzIGltbWVkaWF0ZWx5LCBzbyB0aGVcbiAgICogICByZWFkIHdvdWxkIHNlZSB0aGUgZGVmYXVsdCBgZmFsc2VgIGFuZCBhc2sgYWdhaW4gYSB1c2VyIHdobyBoYXMgYWxyZWFkeSBkZWNsaW5lZC5cbiAgICovXG4gIHB1YmxpYyBvdmVycmlkZSBvbmxvYWQoKTogdm9pZCB7XG4gICAgdGhpcy5hZGRDaGlsZChcbiAgICAgIG5ldyBDYWxsYmFja0xheW91dFJlYWR5Q29tcG9uZW50KHRoaXMuYXBwLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMucGx1Z2luU2V0dGluZ3NDb21wb25lbnQud2hlbkxvYWRlZEZyb21GaWxlKCk7XG4gICAgICAgIGlmICh0aGlzLmlzVW5sb2FkZWQoKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2hvd1N1Z2dlc3Rpb25Ob3RpY2UoKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXJzIHRoZSBzdWdnZXN0aW9uIGJhbm5lciBpbnRvIGEgc2V0dGluZ3MtdGFiIGNvbnRhaW5lciwgd2l0aCBhIGJ1dHRvbiB0aGF0IGluc3RhbGxzIGFuZCBlbmFibGVzXG4gICAqIHRoZSBzdWdnZXN0ZWQgcGx1Z2luLlxuICAgKlxuICAgKiBSZW5kZXJzIG5vdGhpbmcgd2hlbiB0aGUgc3VnZ2VzdGVkIHBsdWdpbiBpcyBhbHJlYWR5IGVuYWJsZWQuIFVubGlrZSB0aGUgbm90aWNlLCB0aGUgYmFubmVyIGlnbm9yZXMgYVxuICAgKiBwcmV2aW91cyBkZWNsaW5lIFx1MjAxNCB0aGUgdXNlciBpcyBsb29raW5nIGF0IHRoZXNlIHNldHRpbmdzIHJpZ2h0IG5vdywgd2hpY2ggaXMgYSBmcmVzaGVyIHNpZ25hbCB0aGFuIGFuXG4gICAqIGFuc3dlciB0aGV5IGdhdmUgZWFybGllci5cbiAgICpcbiAgICogQHBhcmFtIGNvbnRhaW5lckVsIC0gVGhlIGVsZW1lbnQgdG8gcmVuZGVyIHRoZSBiYW5uZXIgaW50by5cbiAgICovXG4gIHB1YmxpYyByZW5kZXJCYW5uZXIoY29udGFpbmVyRWw6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgY29uc3Qgc3RhdGUgPSB0aGlzLmdldFN1Z2dlc3RlZFBsdWdpblN0YXRlKCk7XG4gICAgaWYgKHN0YXRlID09PSBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5FbmFibGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgYmFubmVyRWwgPSBjb250YWluZXJFbC5jcmVhdGVEaXYoe1xuICAgICAgY2xzOiBbQ3NzQ2xhc3MuTGlicmFyeU5hbWUsIENzc0NsYXNzLlBsdWdpblN1Z2dlc3Rpb25CYW5uZXJdXG4gICAgfSk7XG4gICAgYmFubmVyRWwuY3JlYXRlRGl2KHsgdGV4dDogdGhpcy5yZWFzb24gfSk7XG5cbiAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJhbm5lckVsKVxuICAgICAgLnNldEJ1dHRvblRleHQodGhpcy5nZXRBY3Rpb25CdXR0b25UZXh0KHN0YXRlKSlcbiAgICAgIC5zZXRDdGEoKVxuICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbnN0YWxsQW5kRW5hYmxlU3VnZ2VzdGVkUGx1Z2luKCk7XG4gICAgICB9KSk7XG4gIH1cblxuICBwcml2YXRlIGdldEFjdGlvbkJ1dHRvblRleHQoc3RhdGU6IFN1Z2dlc3RlZFBsdWdpblN0YXRlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdCgoJCkgPT5cbiAgICAgIHN0YXRlID09PSBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5JbnN0YWxsZWRCdXREaXNhYmxlZFxuICAgICAgICA/ICQub2JzaWRpYW5EZXZVdGlscy5wbHVnaW5TdWdnZXN0aW9uLmVuYWJsZVxuICAgICAgICA6ICQub2JzaWRpYW5EZXZVdGlscy5wbHVnaW5TdWdnZXN0aW9uLmluc3RhbGxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBzaG93U3VnZ2VzdGlvbk5vdGljZSgpOiB2b2lkIHtcbiAgICBjb25zdCBzdGF0ZSA9IHRoaXMuZ2V0U3VnZ2VzdGVkUGx1Z2luU3RhdGUoKTtcbiAgICBpZiAoc3RhdGUgPT09IFN1Z2dlc3RlZFBsdWdpblN0YXRlLkVuYWJsZWQgfHwgdGhpcy5pc1N1Z2dlc3Rpb25EZWNsaW5lZCgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZnJhZ21lbnQgPSBjcmVhdGVGcmFnbWVudCgoZnJhZ21lbnRFbCkgPT4ge1xuICAgICAgZnJhZ21lbnRFbC5jcmVhdGVEaXYoeyB0ZXh0OiB0aGlzLnJlYXNvbiB9KTtcbiAgICAgIGNvbnN0IGJ1dHRvbnNFbCA9IGZyYWdtZW50RWwuY3JlYXRlRGl2KCk7XG5cbiAgICAgIG5ldyBCdXR0b25Db21wb25lbnQoYnV0dG9uc0VsKVxuICAgICAgICAuc2V0QnV0dG9uVGV4dCh0aGlzLmdldEFjdGlvbkJ1dHRvblRleHQoc3RhdGUpKVxuICAgICAgICAuc2V0Q3RhKClcbiAgICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmluc3RhbGxBbmRFbmFibGVTdWdnZXN0ZWRQbHVnaW4oKTtcbiAgICAgICAgfSkpO1xuXG4gICAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJ1dHRvbnNFbClcbiAgICAgICAgLnNldEJ1dHRvblRleHQodCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpblN1Z2dlc3Rpb24ubm90Tm93KSlcbiAgICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnNldFN1Z2dlc3Rpb25EZWNsaW5lZCh0cnVlKTtcbiAgICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5wbHVnaW5Ob3RpY2VDb21wb25lbnQuc2hvd05vdGljZShmcmFnbWVudCwgeyBzaG91bGRIaWRlT25DbGljazogZmFsc2UgfSk7XG4gIH1cbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFvQkEsc0JBQWdDO0FBS2hDLG1CQUFtQztBQUNuQywrQkFHTztBQUNQLHVCQUF5QjtBQUN6QixrQkFBa0I7QUFDbEIsMEJBQTRCO0FBQzVCLG9DQUE2QztBQUt0QyxJQUFLLHVCQUFMLGtCQUFLQSwwQkFBTDtBQUlMLEVBQUFBLHNCQUFBLGFBQVU7QUFLVixFQUFBQSxzQkFBQSwwQkFBdUI7QUFLdkIsRUFBQUEsc0JBQUEsa0JBQWU7QUFkTCxTQUFBQTtBQUFBLEdBQUE7QUFtRkwsTUFBTSxrQ0FBa0MsZ0NBQVk7QUFBQSxFQUN4QztBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFPVixZQUFZLFFBQW9EO0FBQ3JFLFVBQU07QUFDTixTQUFLLE1BQU0sT0FBTztBQUNsQixTQUFLLHdCQUF3QixPQUFPO0FBQ3BDLFNBQUssMEJBQTBCLE9BQU87QUFDdEMsU0FBSyxTQUFTLE9BQU87QUFDckIsU0FBSyxvQkFBb0IsT0FBTztBQUNoQyxTQUFLLHNCQUFzQixPQUFPO0FBQ2xDLFNBQUssdUJBQXVCLE9BQU87QUFDbkMsU0FBSyx3QkFBd0IsT0FBTztBQUFBLEVBQ3RDO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBT08sMEJBQWdEO0FBQ3JELFFBQUksS0FBSyxJQUFJLFFBQVEsZUFBZSxJQUFJLEtBQUssaUJBQWlCLEdBQUc7QUFDL0QsYUFBTztBQUFBLElBQ1Q7QUFFQSxXQUFPLE9BQU8sT0FBTyxLQUFLLElBQUksUUFBUSxXQUFXLEtBQUssaUJBQWlCLElBQ25FLG9EQUNBO0FBQUEsRUFDTjtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBUUEsTUFBYSxrQ0FBaUQ7QUFDNUQsVUFBTSxRQUFRLEtBQUssd0JBQXdCO0FBQzNDLFFBQUksVUFBVSx5QkFBOEI7QUFDMUM7QUFBQSxJQUNGO0FBRUEsUUFBSTtBQUNGLFVBQUksVUFBVSxtREFBMkM7QUFDdkQsa0JBQU0sZ0RBQXNCO0FBQUEsVUFDMUIsS0FBSyxLQUFLO0FBQUEsVUFDVixVQUFVLEtBQUs7QUFBQSxRQUNqQixDQUFDO0FBQUEsTUFDSCxPQUFPO0FBQ0wsa0JBQU0sZ0VBQXNDO0FBQUEsVUFDMUMsS0FBSyxLQUFLO0FBQUEsVUFDVixVQUFVLEtBQUs7QUFBQSxRQUNqQixDQUFDO0FBQUEsTUFDSDtBQUFBLElBQ0YsU0FBUyxPQUFPO0FBQ2QsV0FBSyxzQkFBc0IsZUFBVyxlQUFFLENBQUMsTUFBTSxFQUFFLGlCQUFpQixpQkFBaUIsZUFBZTtBQUFBLFFBQ2hHLFlBQVksS0FBSztBQUFBLE1BQ25CLENBQUMsQ0FBQztBQUNGLFlBQU07QUFBQSxJQUNSO0FBRUEsVUFBTSxLQUFLLHNCQUFzQixLQUFLO0FBQ3RDLFNBQUssc0JBQXNCLGVBQVcsZUFBRSxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsaUJBQWlCLFdBQVc7QUFBQSxNQUM1RixZQUFZLEtBQUs7QUFBQSxJQUNuQixDQUFDLENBQUM7QUFBQSxFQUNKO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFpQmdCLFNBQWU7QUFDN0IsU0FBSztBQUFBLE1BQ0gsSUFBSSwyREFBNkIsS0FBSyxLQUFLLFlBQVk7QUFDckQsY0FBTSxLQUFLLHdCQUF3QixtQkFBbUI7QUFDdEQsWUFBSSxLQUFLLFdBQVcsR0FBRztBQUNyQjtBQUFBLFFBQ0Y7QUFFQSxhQUFLLHFCQUFxQjtBQUFBLE1BQzVCLENBQUM7QUFBQSxJQUNIO0FBQUEsRUFDRjtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFZTyxhQUFhLGFBQWdDO0FBQ2xELFVBQU0sUUFBUSxLQUFLLHdCQUF3QjtBQUMzQyxRQUFJLFVBQVUseUJBQThCO0FBQzFDO0FBQUEsSUFDRjtBQUVBLFVBQU0sV0FBVyxZQUFZLFVBQVU7QUFBQSxNQUNyQyxLQUFLLENBQUMsMEJBQVMsYUFBYSwwQkFBUyxzQkFBc0I7QUFBQSxJQUM3RCxDQUFDO0FBQ0QsYUFBUyxVQUFVLEVBQUUsTUFBTSxLQUFLLE9BQU8sQ0FBQztBQUV4QyxRQUFJLGdDQUFnQixRQUFRLEVBQ3pCLGNBQWMsS0FBSyxvQkFBb0IsS0FBSyxDQUFDLEVBQzdDLE9BQU8sRUFDUCxZQUFRLGlDQUFtQixZQUFZO0FBQ3RDLFlBQU0sS0FBSyxnQ0FBZ0M7QUFBQSxJQUM3QyxDQUFDLENBQUM7QUFBQSxFQUNOO0FBQUEsRUFFUSxvQkFBb0IsT0FBcUM7QUFDL0QsZUFBTztBQUFBLE1BQUUsQ0FBQyxNQUNSLFVBQVUsb0RBQ04sRUFBRSxpQkFBaUIsaUJBQWlCLFNBQ3BDLEVBQUUsaUJBQWlCLGlCQUFpQjtBQUFBLElBQzFDO0FBQUEsRUFDRjtBQUFBLEVBRVEsdUJBQTZCO0FBQ25DLFVBQU0sUUFBUSxLQUFLLHdCQUF3QjtBQUMzQyxRQUFJLFVBQVUsMkJBQWdDLEtBQUsscUJBQXFCLEdBQUc7QUFDekU7QUFBQSxJQUNGO0FBRUEsVUFBTSxXQUFXLGVBQWUsQ0FBQyxlQUFlO0FBQzlDLGlCQUFXLFVBQVUsRUFBRSxNQUFNLEtBQUssT0FBTyxDQUFDO0FBQzFDLFlBQU0sWUFBWSxXQUFXLFVBQVU7QUFFdkMsVUFBSSxnQ0FBZ0IsU0FBUyxFQUMxQixjQUFjLEtBQUssb0JBQW9CLEtBQUssQ0FBQyxFQUM3QyxPQUFPLEVBQ1AsWUFBUSxpQ0FBbUIsWUFBWTtBQUN0QyxjQUFNLEtBQUssZ0NBQWdDO0FBQUEsTUFDN0MsQ0FBQyxDQUFDO0FBRUosVUFBSSxnQ0FBZ0IsU0FBUyxFQUMxQixrQkFBYyxlQUFFLENBQUMsTUFBTSxFQUFFLGlCQUFpQixpQkFBaUIsTUFBTSxDQUFDLEVBQ2xFLFlBQVEsaUNBQW1CLFlBQVk7QUFDdEMsY0FBTSxLQUFLLHNCQUFzQixJQUFJO0FBQUEsTUFDdkMsQ0FBQyxDQUFDO0FBQUEsSUFDTixDQUFDO0FBRUQsU0FBSyxzQkFBc0IsV0FBVyxVQUFVLEVBQUUsbUJBQW1CLE1BQU0sQ0FBQztBQUFBLEVBQzlFO0FBQ0Y7IiwKICAibmFtZXMiOiBbIlN1Z2dlc3RlZFBsdWdpblN0YXRlIl0KfQo=
|
|
288
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL2NvbXBvbmVudHMvcGx1Z2luLXN1Z2dlc3Rpb24tY29tcG9uZW50LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogQ29tcG9uZW50IHRoYXQgc3VnZ2VzdHMgaW5zdGFsbGluZyBhbm90aGVyIGNvbW11bml0eSBwbHVnaW4gdGhlIGhvc3QgcGx1Z2luIG5lZWRzIGluIG9yZGVyIHRvIG9mZmVyXG4gKiBzb21lIG9mIGl0cyBiZWhhdmlvci5cbiAqXG4gKiBBIHN1Z2dlc3Rpb24gaXMgbm90IGEgZGVwZW5kZW5jeSBcdTIwMTQgYnV0IGEgZGVwZW5kZW5jeSBpcyBub3cgYSB0aGluZyB0aGlzIGxpYnJhcnkgSEFTLCBzbyB0aGUgY2hvaWNlXG4gKiBiZXR3ZWVuIHRoZW0gaXMgYSByZWFsIG9uZS4gVXNlIGEgc3VnZ2VzdGlvbiB3aGVuIHRoZSBvdGhlciBwbHVnaW4gQUREUyBzb21ldGhpbmc6IHRoZSBob3N0IGtlZXBzXG4gKiB3b3JraW5nIHdpdGhvdXQgaXQsIHNpbXBseSB1bmFibGUgdG8gb2ZmZXIgd2hhdGV2ZXIgdGhhdCBwbHVnaW4gb3ducywgYW5kIHRoaXMgY29tcG9uZW50IGFza3Mgb25jZVxuICogd2hldGhlciB0aGUgdXNlciB3b3VsZCBsaWtlIGl0IGluc3RhbGxlZC4gVXNlIGBQbHVnaW5HYXRlQ29tcG9uZW50YCB3aGVuIHRoZSBob3N0J3MgYWR2ZXJ0aXNlZFxuICogYmVoYXZpb3IgaXMgbm90IHRoZXJlIGF0IGFsbCB3aXRob3V0IHRoZSBvdGhlciBwbHVnaW4uXG4gKlxuICogVGhpcyBmaWxlIHVzZWQgdG8gYXJndWUgdGhlIHN0cm9uZ2VyIHBvc2l0aW9uIFx1MjAxNCB0aGF0IHJlcXVpcmluZyBhbm90aGVyIHBsdWdpbiBzaG91bGQgbm90IGV4aXN0LCBiZWNhdXNlXG4gKiBcImludmVudGluZyBvbmUgYnkgcmVmdXNpbmcgdG8gbG9hZCB3b3VsZCBwdW5pc2ggdGhlIHVzZXIgZm9yIHNvbWV0aGluZyB0aGV5IG5ldmVyIGFncmVlZCB0b1wiLiBUaGF0IHdhc1xuICogd3JvbmcgYWJvdXQgd2hpY2ggb3B0aW9uIHB1bmlzaGVzIHRoZSB1c2VyLCBhbmQgdGhlIGNvdW50ZXItY2FzZSBpcyB3b3J0aCBrZWVwaW5nIHJhdGhlciB0aGFuIHF1aWV0bHlcbiAqIGRlbGV0aW5nLiBBIGxvYWQtYmVhcmluZyBwbHVnaW4gdGhlIHVzZXIgY2Fubm90IGlkZW50aWZ5IGlzIG5vdCBhIG5ldXRyYWwgb3V0Y29tZTogbW9udGhzIGxhdGVyIHRoZXlcbiAqIG1lZXQgaXQgaW4gdGhlaXIgcGx1Z2luIGxpc3QsIG5vdGhpbmcgaW4gT2JzaWRpYW4ncyBtYW5pZmVzdCBmb3JtYXQgc2F5cyBhbnl0aGluZyBkZXBlbmRzIG9uIGl0LCB0aGV5XG4gKiByZW1vdmUgaXQsIGFuZCB0aGUgZGFtYWdlIHN1cmZhY2VzIHdlZWtzIGFmdGVyIHRoYXQgd2l0aCBubyB3YXkgdG8gY29ubmVjdCB0aGUgdHdvLiBCZXNpZGUgdGhhdCwgYVxuICogbWFuZGF0b3J5IGRlcGVuZGVuY3kgdGhhdCBzdGF5cyBlbmFibGVkLWJ1dC1pbmVydCwgbmFtZXMgd2hhdCBpdCBpcyB3YWl0aW5nIGZvciwgaW5zdGFsbHMgaXQgaW4gb25lXG4gKiBjbGljayBhbmQgcmVzdW1lcyB3aXRob3V0IGEgcmVzdGFydCBpcyBub3QgYSBwdW5pc2htZW50IFx1MjAxNCBpdCBpcyB0aGUgc2FtZSBpbmZvcm1hdGlvbiwgZGVsaXZlcmVkIHdoaWxlXG4gKiB0aGUgdXNlciBjYW4gc3RpbGwgYWN0IG9uIGl0LlxuICpcbiAqIFRoZSBhc2sgaXMgc3VyZmFjZWQgdHdpY2UsIGRlbGliZXJhdGVseSwgYmVjYXVzZSB0aGUgdHdvIHBsYWNlbWVudHMgYW5zd2VyIGRpZmZlcmVudCBxdWVzdGlvbnM6XG4gKiBhIG5vdGljZSBvbiBsb2FkIChcInlvdSBhcmUgbWlzc2luZyBzb21ldGhpbmcgeW91IHByb2JhYmx5IHdhbnRcIikgYW5kIGEgc2V0dGluZ3MtdGFiIGJhbm5lciAoXCJ0aGVcbiAqIHNldHRpbmdzIHlvdSBjYW1lIGxvb2tpbmcgZm9yIGxpdmUgaW4gYW5vdGhlciBwbHVnaW5cIikuIERlY2xpbmluZyBzaWxlbmNlcyBvbmx5IHRoZSBub3RpY2UgXHUyMDE0IGEgdXNlclxuICogd2hvIG9wZW5zIHRoZSBzZXR0aW5ncyB0YWIgaXMgYXNraW5nIGFib3V0IHRoZSBmZWF0dXJlIHJpZ2h0IHRoZW4sIHNvIHRoZSBiYW5uZXIgc3RheXMuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBBcHAgfSBmcm9tICdvYnNpZGlhbic7XG5pbXBvcnQgdHlwZSB7IFByb21pc2FibGUgfSBmcm9tICd0eXBlLWZlc3QnO1xuXG5pbXBvcnQgeyBCdXR0b25Db21wb25lbnQgfSBmcm9tICdvYnNpZGlhbic7XG5cbmltcG9ydCB0eXBlIHsgUGx1Z2luTm90aWNlQ29tcG9uZW50IH0gZnJvbSAnLi9wbHVnaW4tbm90aWNlLWNvbXBvbmVudC50cyc7XG5pbXBvcnQgdHlwZSB7IFBsdWdpblNldHRpbmdzQ29tcG9uZW50QmFzZSB9IGZyb20gJy4vcGx1Z2luLXNldHRpbmdzLWNvbXBvbmVudC50cyc7XG5cbmltcG9ydCB7IGNvbnZlcnRBc3luY1RvU3luYyB9IGZyb20gJy4uLy4uL2FzeW5jLnRzJztcbmltcG9ydCB7IENzc0NsYXNzIH0gZnJvbSAnLi4vY3NzLWNsYXNzLnRzJztcbmltcG9ydCB7IHQgfSBmcm9tICcuLi9pMThuL2kxOG4udHMnO1xuaW1wb3J0IHtcbiAgZ2V0SW5zdGFsbGVkUGx1Z2luU3RhdGUsXG4gIGluc3RhbGxBbmRFbmFibGVQbHVnaW4sXG4gIEluc3RhbGxlZFBsdWdpblN0YXRlXG59IGZyb20gJy4uL3BsdWdpbi9wbHVnaW4taW5zdGFsbC1zdGF0ZS50cyc7XG5pbXBvcnQgeyBDb21wb25lbnRFeCB9IGZyb20gJy4vY29tcG9uZW50LWV4LnRzJztcbmltcG9ydCB7IENhbGxiYWNrTGF5b3V0UmVhZHlDb21wb25lbnQgfSBmcm9tICcuL2xheW91dC1yZWFkeS1jb21wb25lbnQudHMnO1xuXG4vKipcbiAqIEhvdyB0aGUgc3VnZ2VzdGVkIHBsdWdpbiBpcyBjdXJyZW50bHkgcHJlc2VudCBpbiB0aGUgdmF1bHQuXG4gKlxuICogVGhlIHNhbWUgdGhyZWUgc3RhdGVzIGEgbWFuZGF0b3J5IGRlcGVuZGVuY3kgaXMgaW4sIHNvIHRoaXMgaXMge0BsaW5rIEluc3RhbGxlZFBsdWdpblN0YXRlfSB1bmRlciB0aGVcbiAqIG5hbWUgdGhpcyBjb21wb25lbnQgaGFzIGFsd2F5cyB1c2VkIFx1MjAxNCBvbmUgZW51bSwgc28gYSBjYWxsZXIgaG9sZGluZyBhIHN0YXRlIGZyb20gZWl0aGVyIGNvbXBvbmVudCBjYW5cbiAqIGNvbXBhcmUgaXQgYWdhaW5zdCBlaXRoZXIgbmFtZS5cbiAqL1xuZXhwb3J0IGNvbnN0IFN1Z2dlc3RlZFBsdWdpblN0YXRlID0gSW5zdGFsbGVkUGx1Z2luU3RhdGU7XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3IgdGhlIHtAbGluayBQbHVnaW5TdWdnZXN0aW9uQ29tcG9uZW50fSBjb25zdHJ1Y3Rvci5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQbHVnaW5TdWdnZXN0aW9uQ29tcG9uZW50Q29uc3RydWN0b3JQYXJhbXMge1xuICAvKipcbiAgICogVGhlIE9ic2lkaWFuIGFwcCBpbnN0YW5jZS5cbiAgICovXG4gIHJlYWRvbmx5IGFwcDogQXBwO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSB1c2VyIGhhcyBhbHJlYWR5IGRlY2xpbmVkIHRoaXMgc3VnZ2VzdGlvbi5cbiAgICpcbiAgICogU3RvcmFnZSBiZWxvbmdzIHRvIHRoZSBob3N0IHBsdWdpbiAodHlwaWNhbGx5IG9uZSBvZiBpdHMgc2V0dGluZ3MpLCBiZWNhdXNlIHRoaXMgY29tcG9uZW50IGhhcyBub1xuICAgKiBgZGF0YS5qc29uYCBvZiBpdHMgb3duIGFuZCBhIGRlY2xpbmUgaGFzIHRvIG91dGxpdmUgYSByZWxvYWQuXG4gICAqXG4gICAqIE9ubHkgZXZlciBjYWxsZWQgb25jZSB7QGxpbmsgcGx1Z2luU2V0dGluZ3NDb21wb25lbnR9IHJlcG9ydHMgaXRzIHNldHRpbmdzIGxvYWRlZCwgc28gYW4gaW1wbGVtZW50YXRpb25cbiAgICogcmVhZGluZyBhIHNldHRpbmcgaXMgZ3VhcmFudGVlZCB0byByZWFkIHRoZSBzdG9yZWQgdmFsdWUgcmF0aGVyIHRoYW4gaXRzIGRlZmF1bHQuXG4gICAqXG4gICAqIEByZXR1cm5zIGB0cnVlYCB3aGVuIHRoZSBzdWdnZXN0aW9uIGhhcyBiZWVuIGRlY2xpbmVkLlxuICAgKi9cbiAgaXNTdWdnZXN0aW9uRGVjbGluZWQodGhpczogdm9pZCk6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBub3RpY2UgY29tcG9uZW50IG9mIHRoZSBwbHVnaW4gbWFraW5nIHRoZSBzdWdnZXN0aW9uLCB1c2VkIHRvIHNob3cgdGhlIHN1Z2dlc3Rpb24gYW5kIGl0c1xuICAgKiBvdXRjb21lLlxuICAgKi9cbiAgcmVhZG9ubHkgcGx1Z2luTm90aWNlQ29tcG9uZW50OiBQbHVnaW5Ob3RpY2VDb21wb25lbnQ7XG5cbiAgLyoqXG4gICAqIFRoZSBzZXR0aW5ncyBjb21wb25lbnQgaG9sZGluZyB3aGF0ZXZlciB7QGxpbmsgaXNTdWdnZXN0aW9uRGVjbGluZWR9IHJlYWRzLlxuICAgKlxuICAgKiBUYWtlbiBhcyBhIHdob2xlIGNvbXBvbmVudCByYXRoZXIgdGhhbiBhcyBhIGJhcmUgXCJyZWFkeVwiIGZsYWcgc28gdGhlIGhvc3QgY2Fubm90IGZvcmdldCB0byB3aXJlIHRoZVxuICAgKiB3YWl0OiB0aGUgbm90aWNlIGlzIGRlY2lkZWQgb25seSBhZnRlciB0aGlzIGNvbXBvbmVudCBoYXMgcmVhZCBgZGF0YS5qc29uYC4gU2VlXG4gICAqIHtAbGluayBQbHVnaW5TZXR0aW5nc0NvbXBvbmVudEJhc2Uud2hlbkxvYWRlZEZyb21GaWxlfSBmb3Igd2h5IHRoZSByZWFkIGNhbm5vdCBzaW1wbHkgaGFwcGVuIGF0XG4gICAqIGxheW91dC1yZWFkeS5cbiAgICovXG4gIHJlYWRvbmx5IHBsdWdpblNldHRpbmdzQ29tcG9uZW50OiBQbHVnaW5TZXR0aW5nc0NvbXBvbmVudEJhc2U8b2JqZWN0PjtcblxuICAvKipcbiAgICogVGhlIGxvY2FsaXplZCBzZW50ZW5jZSBleHBsYWluaW5nIHdoYXQgdGhlIGhvc3QgcGx1Z2luIGNhbm5vdCBkbyB3aXRob3V0IHRoZSBzdWdnZXN0ZWQgcGx1Z2luLiBUaGVcbiAgICogaG9zdCBwbHVnaW4gb3ducyB0aGlzIHN0cmluZzogb25seSBpdCBrbm93cyB3aGljaCBvZiBpdHMgZmVhdHVyZXMgYXJlIGFmZmVjdGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgcmVhc29uOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJlY29yZHMgdGhlIHVzZXIncyBhbnN3ZXIgdG8gdGhlIHN1Z2dlc3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSBpc0RlY2xpbmVkIC0gYHRydWVgIHdoZW4gdGhlIHVzZXIgZGVjbGluZWQuXG4gICAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYW5zd2VyIGlzIHBlcnNpc3RlZC5cbiAgICovXG4gIHNldFN1Z2dlc3Rpb25EZWNsaW5lZCh0aGlzOiB2b2lkLCBpc0RlY2xpbmVkOiBib29sZWFuKTogUHJvbWlzYWJsZTx2b2lkPjtcblxuICAvKipcbiAgICogVGhlIGlkIG9mIHRoZSBzdWdnZXN0ZWQgcGx1Z2luLCBhcyBsaXN0ZWQgaW4gT2JzaWRpYW4ncyBjb21tdW5pdHkgcGx1Z2luIHJlZ2lzdHJ5LlxuICAgKi9cbiAgcmVhZG9ubHkgc3VnZ2VzdGVkUGx1Z2luSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRpc3BsYXkgbmFtZSBvZiB0aGUgc3VnZ2VzdGVkIHBsdWdpbiwgc2hvd24gdG8gdGhlIHVzZXIuXG4gICAqL1xuICByZWFkb25seSBzdWdnZXN0ZWRQbHVnaW5OYW1lOiBzdHJpbmc7XG59XG5cbi8qKlxuICogSG93IHRoZSBzdWdnZXN0ZWQgcGx1Z2luIGlzIGN1cnJlbnRseSBwcmVzZW50IGluIHRoZSB2YXVsdC5cbiAqL1xuZXhwb3J0IHR5cGUgU3VnZ2VzdGVkUGx1Z2luU3RhdGUgPSBJbnN0YWxsZWRQbHVnaW5TdGF0ZTtcblxuLyoqXG4gKiBTdWdnZXN0cyBpbnN0YWxsaW5nIGFub3RoZXIgY29tbXVuaXR5IHBsdWdpbiwgdmlhIGEgbG9hZC10aW1lIG5vdGljZSBhbmQgYSBzZXR0aW5ncy10YWIgYmFubmVyLlxuICovXG5leHBvcnQgY2xhc3MgUGx1Z2luU3VnZ2VzdGlvbkNvbXBvbmVudCBleHRlbmRzIENvbXBvbmVudEV4IHtcbiAgcHJpdmF0ZSByZWFkb25seSBhcHA6IEFwcDtcbiAgcHJpdmF0ZSByZWFkb25seSBpc1N1Z2dlc3Rpb25EZWNsaW5lZDogKCkgPT4gYm9vbGVhbjtcbiAgcHJpdmF0ZSByZWFkb25seSBwbHVnaW5Ob3RpY2VDb21wb25lbnQ6IFBsdWdpbk5vdGljZUNvbXBvbmVudDtcbiAgcHJpdmF0ZSByZWFkb25seSBwbHVnaW5TZXR0aW5nc0NvbXBvbmVudDogUGx1Z2luU2V0dGluZ3NDb21wb25lbnRCYXNlPG9iamVjdD47XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVhc29uOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2V0U3VnZ2VzdGlvbkRlY2xpbmVkOiAoaXNEZWNsaW5lZDogYm9vbGVhbikgPT4gUHJvbWlzYWJsZTx2b2lkPjtcbiAgcHJpdmF0ZSByZWFkb25seSBzdWdnZXN0ZWRQbHVnaW5JZDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHN1Z2dlc3RlZFBsdWdpbk5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiB7QGxpbmsgUGx1Z2luU3VnZ2VzdGlvbkNvbXBvbmVudH0uXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgY29uc3RydWN0b3IgcGFyYW1ldGVycy5cbiAgICovXG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihwYXJhbXM6IFBsdWdpblN1Z2dlc3Rpb25Db21wb25lbnRDb25zdHJ1Y3RvclBhcmFtcykge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5hcHAgPSBwYXJhbXMuYXBwO1xuICAgIHRoaXMucGx1Z2luTm90aWNlQ29tcG9uZW50ID0gcGFyYW1zLnBsdWdpbk5vdGljZUNvbXBvbmVudDtcbiAgICB0aGlzLnBsdWdpblNldHRpbmdzQ29tcG9uZW50ID0gcGFyYW1zLnBsdWdpblNldHRpbmdzQ29tcG9uZW50O1xuICAgIHRoaXMucmVhc29uID0gcGFyYW1zLnJlYXNvbjtcbiAgICB0aGlzLnN1Z2dlc3RlZFBsdWdpbklkID0gcGFyYW1zLnN1Z2dlc3RlZFBsdWdpbklkO1xuICAgIHRoaXMuc3VnZ2VzdGVkUGx1Z2luTmFtZSA9IHBhcmFtcy5zdWdnZXN0ZWRQbHVnaW5OYW1lO1xuICAgIHRoaXMuaXNTdWdnZXN0aW9uRGVjbGluZWQgPSBwYXJhbXMuaXNTdWdnZXN0aW9uRGVjbGluZWQ7XG4gICAgdGhpcy5zZXRTdWdnZXN0aW9uRGVjbGluZWQgPSBwYXJhbXMuc2V0U3VnZ2VzdGlvbkRlY2xpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIGhvdyB0aGUgc3VnZ2VzdGVkIHBsdWdpbiBpcyBjdXJyZW50bHkgcHJlc2VudCBpbiB0aGUgdmF1bHQuXG4gICAqXG4gICAqIEByZXR1cm5zIFRoZSB7QGxpbmsgU3VnZ2VzdGVkUGx1Z2luU3RhdGV9LlxuICAgKi9cbiAgcHVibGljIGdldFN1Z2dlc3RlZFBsdWdpblN0YXRlKCk6IFN1Z2dlc3RlZFBsdWdpblN0YXRlIHtcbiAgICByZXR1cm4gZ2V0SW5zdGFsbGVkUGx1Z2luU3RhdGUoe1xuICAgICAgYXBwOiB0aGlzLmFwcCxcbiAgICAgIHBsdWdpbklkOiB0aGlzLnN1Z2dlc3RlZFBsdWdpbklkXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogSW5zdGFsbHMgKHdoZW4gbmVlZGVkKSBhbmQgZW5hYmxlcyB0aGUgc3VnZ2VzdGVkIHBsdWdpbiwgcmVwb3J0aW5nIHRoZSBvdXRjb21lIGFzIGEgbm90aWNlLlxuICAgKlxuICAgKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHBsdWdpbiBpcyBlbmFibGVkLCBvciBvbmNlIHRoZSBmYWlsdXJlIGhhcyBiZWVuXG4gICAqIHJlcG9ydGVkLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGluc3RhbGxBbmRFbmFibGVTdWdnZXN0ZWRQbHVnaW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0U3VnZ2VzdGVkUGx1Z2luU3RhdGUoKSA9PT0gU3VnZ2VzdGVkUGx1Z2luU3RhdGUuRW5hYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGF3YWl0IGluc3RhbGxBbmRFbmFibGVQbHVnaW4oe1xuICAgICAgYXBwOiB0aGlzLmFwcCxcbiAgICAgIHBsdWdpbklkOiB0aGlzLnN1Z2dlc3RlZFBsdWdpbklkLFxuICAgICAgcGx1Z2luTmFtZTogdGhpcy5zdWdnZXN0ZWRQbHVnaW5OYW1lLFxuICAgICAgcGx1Z2luTm90aWNlQ29tcG9uZW50OiB0aGlzLnBsdWdpbk5vdGljZUNvbXBvbmVudFxuICAgIH0pO1xuXG4gICAgLy8gT25seSBhZnRlciB0aGUgaW5zdGFsbCBhY3R1YWxseSBzdWNjZWVkZWQgXHUyMDE0IGBpbnN0YWxsQW5kRW5hYmxlUGx1Z2luYCByZXRocm93cyBvbiBmYWlsdXJlLCBzbyBhXG4gICAgLy8gRmFpbGVkIGF0dGVtcHQgbGVhdmVzIGEgcHJldmlvdXMgZGVjbGluZSBzdGFuZGluZyByYXRoZXIgdGhhbiBzaWxlbnRseSBjbGVhcmluZyBpdC5cbiAgICBhd2FpdCB0aGlzLnNldFN1Z2dlc3Rpb25EZWNsaW5lZChmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIGNvbXBvbmVudCwgc2hvd2luZyB0aGUgc3VnZ2VzdGlvbiBub3RpY2Ugb25jZSB0aGUgbGF5b3V0IGlzIHJlYWR5IEFORCB0aGUgaG9zdCdzIHNldHRpbmdzXG4gICAqIGhhdmUgYmVlbiByZWFkIGZyb20gZGlzay5cbiAgICpcbiAgICogQm90aCB3YWl0cyBtYXR0ZXIsIGFuZCBuZWl0aGVyIGltcGxpZXMgdGhlIG90aGVyOlxuICAgKlxuICAgKiAtIExheW91dC1yZWFkeSwgYmVjYXVzZSBwbHVnaW5zIGxvYWQgaW4gYW4gdW5zcGVjaWZpZWQgb3JkZXIsIHNvIHRoZSBzdWdnZXN0ZWQgcGx1Z2luIG1heSB3ZWxsIGJlXG4gICAqICAgZW5hYmxlZCBhIG1vbWVudCBhZnRlciB0aGlzIG9uZS4gQ2hlY2tpbmcgZWFybGllciB3b3VsZCBzdWdnZXN0IGluc3RhbGxpbmcgc29tZXRoaW5nIHRoZSB1c2VyXG4gICAqICAgYWxyZWFkeSBoYXMuXG4gICAqIC0gU2V0dGluZ3MtbG9hZGVkLCBiZWNhdXNlIHtAbGluayBQbHVnaW5TdWdnZXN0aW9uQ29tcG9uZW50Q29uc3RydWN0b3JQYXJhbXMuaXNTdWdnZXN0aW9uRGVjbGluZWR9XG4gICAqICAgcmVhZHMgYSBzZXR0aW5nIG9mIHRoZSBob3N0LCBhbmQgdGhlIGhvc3QncyBzZXR0aW5ncyBjb21wb25lbnQgaXMgYSBTSUJMSU5HIHdob3NlIG93biBhc3luYyBsb2FkIGlzXG4gICAqICAgc3RpbGwgaW4gZmxpZ2h0IGhlcmUuIE9uIGEgbGF5b3V0IHRoYXQgaXMgYWxyZWFkeSByZWFkeSBcdTIwMTQgYSBydW50aW1lIGVuYWJsZSBmcm9tIHRoZSBDb21tdW5pdHlcbiAgICogICBQbHVnaW5zIHRhYiwgb3IgYSByZS1lbmFibGUgYWZ0ZXIgYW4gdXBkYXRlIFx1MjAxNCB0aGUgbGF5b3V0LXJlYWR5IGNhbGxiYWNrIGZpcmVzIGltbWVkaWF0ZWx5LCBzbyB0aGVcbiAgICogICByZWFkIHdvdWxkIHNlZSB0aGUgZGVmYXVsdCBgZmFsc2VgIGFuZCBhc2sgYWdhaW4gYSB1c2VyIHdobyBoYXMgYWxyZWFkeSBkZWNsaW5lZC5cbiAgICovXG4gIHB1YmxpYyBvdmVycmlkZSBvbmxvYWQoKTogdm9pZCB7XG4gICAgdGhpcy5hZGRDaGlsZChcbiAgICAgIG5ldyBDYWxsYmFja0xheW91dFJlYWR5Q29tcG9uZW50KHRoaXMuYXBwLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMucGx1Z2luU2V0dGluZ3NDb21wb25lbnQud2hlbkxvYWRlZEZyb21GaWxlKCk7XG4gICAgICAgIGlmICh0aGlzLmlzVW5sb2FkZWQoKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2hvd1N1Z2dlc3Rpb25Ob3RpY2UoKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXJzIHRoZSBzdWdnZXN0aW9uIGJhbm5lciBpbnRvIGEgc2V0dGluZ3MtdGFiIGNvbnRhaW5lciwgd2l0aCBhIGJ1dHRvbiB0aGF0IGluc3RhbGxzIGFuZCBlbmFibGVzXG4gICAqIHRoZSBzdWdnZXN0ZWQgcGx1Z2luLlxuICAgKlxuICAgKiBSZW5kZXJzIG5vdGhpbmcgd2hlbiB0aGUgc3VnZ2VzdGVkIHBsdWdpbiBpcyBhbHJlYWR5IGVuYWJsZWQuIFVubGlrZSB0aGUgbm90aWNlLCB0aGUgYmFubmVyIGlnbm9yZXMgYVxuICAgKiBwcmV2aW91cyBkZWNsaW5lIFx1MjAxNCB0aGUgdXNlciBpcyBsb29raW5nIGF0IHRoZXNlIHNldHRpbmdzIHJpZ2h0IG5vdywgd2hpY2ggaXMgYSBmcmVzaGVyIHNpZ25hbCB0aGFuIGFuXG4gICAqIGFuc3dlciB0aGV5IGdhdmUgZWFybGllci5cbiAgICpcbiAgICogQHBhcmFtIGNvbnRhaW5lckVsIC0gVGhlIGVsZW1lbnQgdG8gcmVuZGVyIHRoZSBiYW5uZXIgaW50by5cbiAgICovXG4gIHB1YmxpYyByZW5kZXJCYW5uZXIoY29udGFpbmVyRWw6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgY29uc3Qgc3RhdGUgPSB0aGlzLmdldFN1Z2dlc3RlZFBsdWdpblN0YXRlKCk7XG4gICAgaWYgKHN0YXRlID09PSBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5FbmFibGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgYmFubmVyRWwgPSBjb250YWluZXJFbC5jcmVhdGVEaXYoe1xuICAgICAgY2xzOiBbQ3NzQ2xhc3MuTGlicmFyeU5hbWUsIENzc0NsYXNzLlBsdWdpblN1Z2dlc3Rpb25CYW5uZXJdXG4gICAgfSk7XG4gICAgYmFubmVyRWwuY3JlYXRlRGl2KHsgdGV4dDogdGhpcy5yZWFzb24gfSk7XG5cbiAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJhbm5lckVsKVxuICAgICAgLnNldEJ1dHRvblRleHQodGhpcy5nZXRBY3Rpb25CdXR0b25UZXh0KHN0YXRlKSlcbiAgICAgIC5zZXRDdGEoKVxuICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5pbnN0YWxsQW5kRW5hYmxlU3VnZ2VzdGVkUGx1Z2luKCk7XG4gICAgICB9KSk7XG4gIH1cblxuICBwcml2YXRlIGdldEFjdGlvbkJ1dHRvblRleHQoc3RhdGU6IFN1Z2dlc3RlZFBsdWdpblN0YXRlKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdCgoJCkgPT5cbiAgICAgIHN0YXRlID09PSBTdWdnZXN0ZWRQbHVnaW5TdGF0ZS5JbnN0YWxsZWRCdXREaXNhYmxlZFxuICAgICAgICA/ICQub2JzaWRpYW5EZXZVdGlscy5wbHVnaW5TdWdnZXN0aW9uLmVuYWJsZVxuICAgICAgICA6ICQub2JzaWRpYW5EZXZVdGlscy5wbHVnaW5TdWdnZXN0aW9uLmluc3RhbGxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBzaG93U3VnZ2VzdGlvbk5vdGljZSgpOiB2b2lkIHtcbiAgICBjb25zdCBzdGF0ZSA9IHRoaXMuZ2V0U3VnZ2VzdGVkUGx1Z2luU3RhdGUoKTtcbiAgICBpZiAoc3RhdGUgPT09IFN1Z2dlc3RlZFBsdWdpblN0YXRlLkVuYWJsZWQgfHwgdGhpcy5pc1N1Z2dlc3Rpb25EZWNsaW5lZCgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZnJhZ21lbnQgPSBjcmVhdGVGcmFnbWVudCgoZnJhZ21lbnRFbCkgPT4ge1xuICAgICAgZnJhZ21lbnRFbC5jcmVhdGVEaXYoeyB0ZXh0OiB0aGlzLnJlYXNvbiB9KTtcbiAgICAgIGNvbnN0IGJ1dHRvbnNFbCA9IGZyYWdtZW50RWwuY3JlYXRlRGl2KCk7XG5cbiAgICAgIG5ldyBCdXR0b25Db21wb25lbnQoYnV0dG9uc0VsKVxuICAgICAgICAuc2V0QnV0dG9uVGV4dCh0aGlzLmdldEFjdGlvbkJ1dHRvblRleHQoc3RhdGUpKVxuICAgICAgICAuc2V0Q3RhKClcbiAgICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmluc3RhbGxBbmRFbmFibGVTdWdnZXN0ZWRQbHVnaW4oKTtcbiAgICAgICAgfSkpO1xuXG4gICAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJ1dHRvbnNFbClcbiAgICAgICAgLnNldEJ1dHRvblRleHQodCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpblN1Z2dlc3Rpb24ubm90Tm93KSlcbiAgICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnNldFN1Z2dlc3Rpb25EZWNsaW5lZCh0cnVlKTtcbiAgICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5wbHVnaW5Ob3RpY2VDb21wb25lbnQuc2hvd05vdGljZShmcmFnbWVudCwgeyBzaG91bGRIaWRlT25DbGljazogZmFsc2UgfSk7XG4gIH1cbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7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
|
|
@@ -5,10 +5,21 @@
|
|
|
5
5
|
* Component that suggests installing another community plugin the host plugin needs in order to offer
|
|
6
6
|
* some of its behavior.
|
|
7
7
|
*
|
|
8
|
-
* A suggestion is not a dependency
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* A suggestion is not a dependency — but a dependency is now a thing this library HAS, so the choice
|
|
9
|
+
* between them is a real one. Use a suggestion when the other plugin ADDS something: the host keeps
|
|
10
|
+
* working without it, simply unable to offer whatever that plugin owns, and this component asks once
|
|
11
|
+
* whether the user would like it installed. Use `PluginGateComponent` when the host's advertised
|
|
12
|
+
* behavior is not there at all without the other plugin.
|
|
13
|
+
*
|
|
14
|
+
* This file used to argue the stronger position — that requiring another plugin should not exist, because
|
|
15
|
+
* "inventing one by refusing to load would punish the user for something they never agreed to". That was
|
|
16
|
+
* wrong about which option punishes the user, and the counter-case is worth keeping rather than quietly
|
|
17
|
+
* deleting. A load-bearing plugin the user cannot identify is not a neutral outcome: months later they
|
|
18
|
+
* meet it in their plugin list, nothing in Obsidian's manifest format says anything depends on it, they
|
|
19
|
+
* remove it, and the damage surfaces weeks after that with no way to connect the two. Beside that, a
|
|
20
|
+
* mandatory dependency that stays enabled-but-inert, names what it is waiting for, installs it in one
|
|
21
|
+
* click and resumes without a restart is not a punishment — it is the same information, delivered while
|
|
22
|
+
* the user can still act on it.
|
|
12
23
|
*
|
|
13
24
|
* The ask is surfaced twice, deliberately, because the two placements answer different questions:
|
|
14
25
|
* a notice on load ("you are missing something you probably want") and a settings-tab banner ("the
|
|
@@ -19,24 +30,16 @@ import type { App } from 'obsidian' with { 'resolution-mode': 'import' };
|
|
|
19
30
|
import type { Promisable } from 'type-fest' with { 'resolution-mode': 'import' };
|
|
20
31
|
import type { PluginNoticeComponent } from './plugin-notice-component.cjs';
|
|
21
32
|
import type { PluginSettingsComponentBase } from './plugin-settings-component.cjs';
|
|
33
|
+
import { InstalledPluginState } from '../plugin/plugin-install-state.cjs';
|
|
22
34
|
import { ComponentEx } from './component-ex.cjs';
|
|
23
35
|
/**
|
|
24
36
|
* How the suggested plugin is currently present in the vault.
|
|
37
|
+
*
|
|
38
|
+
* The same three states a mandatory dependency is in, so this is {@link InstalledPluginState} under the
|
|
39
|
+
* name this component has always used — one enum, so a caller holding a state from either component can
|
|
40
|
+
* compare it against either name.
|
|
25
41
|
*/
|
|
26
|
-
export declare
|
|
27
|
-
/**
|
|
28
|
-
* Installed and enabled — there is nothing to suggest.
|
|
29
|
-
*/
|
|
30
|
-
Enabled = "enabled",
|
|
31
|
-
/**
|
|
32
|
-
* Installed but disabled. Only an enable is needed, so no download happens.
|
|
33
|
-
*/
|
|
34
|
-
InstalledButDisabled = "installedButDisabled",
|
|
35
|
-
/**
|
|
36
|
-
* Not installed at all.
|
|
37
|
-
*/
|
|
38
|
-
NotInstalled = "notInstalled"
|
|
39
|
-
}
|
|
42
|
+
export declare const SuggestedPluginState: typeof InstalledPluginState;
|
|
40
43
|
/**
|
|
41
44
|
* Parameters for the {@link PluginSuggestionComponent} constructor.
|
|
42
45
|
*/
|
|
@@ -92,6 +95,10 @@ export interface PluginSuggestionComponentConstructorParams {
|
|
|
92
95
|
*/
|
|
93
96
|
readonly suggestedPluginName: string;
|
|
94
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* How the suggested plugin is currently present in the vault.
|
|
100
|
+
*/
|
|
101
|
+
export type SuggestedPluginState = InstalledPluginState;
|
|
95
102
|
/**
|
|
96
103
|
* Suggests installing another community plugin, via a load-time notice and a settings-tab banner.
|
|
97
104
|
*/
|