obsidian-dev-utils 94.2.0 → 94.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/CHANGELOG.md +14 -0
- package/dist/lib/cjs/generated-during-build.cjs +1 -1
- package/dist/lib/cjs/script-utils/demo-vault-buttons.cjs +358 -0
- package/dist/lib/cjs/script-utils/demo-vault-buttons.d.cts +112 -0
- package/dist/lib/cjs/script-utils/demo-vault-coverage.cjs +13 -8
- package/dist/lib/cjs/script-utils/demo-vault-coverage.d.cts +15 -6
- package/dist/lib/cjs/script-utils/index.cjs +4 -1
- package/dist/lib/cjs/script-utils/index.d.cts +1 -0
- package/dist/lib/cjs/script-utils/test-runners/vitest-config.cjs +8 -2
- package/dist/lib/cjs/script-utils/test-runners/vitest-config.d.cts +5 -0
- package/dist/lib/esm/generated-during-build.mjs +1 -1
- package/dist/lib/esm/script-utils/demo-vault-buttons.d.mts +112 -0
- package/dist/lib/esm/script-utils/demo-vault-buttons.mjs +249 -0
- package/dist/lib/esm/script-utils/demo-vault-coverage.d.mts +15 -6
- package/dist/lib/esm/script-utils/demo-vault-coverage.mjs +13 -8
- package/dist/lib/esm/script-utils/index.d.mts +1 -0
- package/dist/lib/esm/script-utils/index.mjs +3 -1
- package/dist/lib/esm/script-utils/test-runners/vitest-config.d.mts +5 -0
- package/dist/lib/esm/script-utils/test-runners/vitest-config.mjs +8 -2
- package/package.json +4 -3
- package/script-utils/demo-vault-buttons/package.json +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 94.4.0
|
|
4
|
+
|
|
5
|
+
- docs(demo-vault): document the button-clicking suite and make it the fleet mechanism
|
|
6
|
+
- chore: update libs
|
|
7
|
+
- feat(script-utils): add a demo-vault button-clicking suite
|
|
8
|
+
- fix(vitest-config): exclude declaration files from coverage by default
|
|
9
|
+
- test(modals): assert the modal header X dismisses alert, confirm and prompt
|
|
10
|
+
- chore: update libs
|
|
11
|
+
|
|
12
|
+
## 94.3.0
|
|
13
|
+
|
|
14
|
+
- feat(demo-vault-coverage): let a settings-less plugin register the suite
|
|
15
|
+
- docs: use NATO placeholders instead of foo, bar and baz
|
|
16
|
+
|
|
3
17
|
## 94.2.0
|
|
4
18
|
|
|
5
19
|
- feat(markdown): teach renderInternalLink the folder-note concept
|
|
@@ -125,7 +125,7 @@ __export(generated_during_build_exports, {
|
|
|
125
125
|
LIBRARY_VERSION: () => LIBRARY_VERSION
|
|
126
126
|
});
|
|
127
127
|
module.exports = __toCommonJS(generated_during_build_exports);
|
|
128
|
-
const LIBRARY_VERSION = "94.
|
|
128
|
+
const LIBRARY_VERSION = "94.4.0";
|
|
129
129
|
const LIBRARY_STYLES = ".obsidian-dev-utils.code-highlighter-component textarea, .obsidian-dev-utils.code-highlighter-component pre, .obsidian-dev-utils.code-highlighter-component code {\n font-family: var(--font-monospace);\n line-height: var(--line-height-normal);\n margin: 0;\n}\n.obsidian-dev-utils.code-highlighter-component textarea, .obsidian-dev-utils.code-highlighter-component code {\n font-size: var(--code-size);\n}\n.obsidian-dev-utils.code-highlighter-component textarea {\n background: transparent;\n color: transparent;\n z-index: 2;\n width: 20em;\n height: 10em;\n}\n.obsidian-dev-utils.code-highlighter-component pre {\n position: absolute;\n pointer-events: none;\n border: var(--input-border-width) solid transparent;\n overflow: auto;\n inset: 0;\n padding: var(--size-4-1) var(--size-4-2);\n z-index: 1;\n}\n.obsidian-dev-utils.code-highlighter-component pre::after {\n content: \"\";\n display: block;\n height: var(--bottom-gap, 0);\n}\n.obsidian-dev-utils.code-highlighter-component pre.is-placeholder {\n opacity: 0.6;\n}\n.obsidian-dev-utils.code-highlighter-component code {\n display: block;\n padding: 0;\n}\n\n.obsidian-dev-utils-lock-indicator {\n display: inline-flex;\n align-items: center;\n color: var(--text-muted);\n}\n.obsidian-dev-utils-lock-indicator .svg-icon {\n width: var(--icon-s);\n height: var(--icon-s);\n}\n\n@keyframes obsidian-dev-utils-lock-indicator-flash {\n 40% {\n color: var(--text-error);\n transform: scale(1.4);\n }\n}\n.obsidian-dev-utils-lock-indicator-flash {\n animation: obsidian-dev-utils-lock-indicator-flash 0.35s ease-in-out;\n}\n\n.obsidian-dev-utils input[type=url] {\n height: var(--input-height);\n}\n.obsidian-dev-utils input[type=month],\n.obsidian-dev-utils input[type=tel],\n.obsidian-dev-utils input[type=time],\n.obsidian-dev-utils input[type=url],\n.obsidian-dev-utils input[type=week] {\n -webkit-app-region: no-drag;\n background: var(--background-modifier-form-field);\n border: var(--input-border-width) solid var(--background-modifier-border);\n color: var(--text-normal);\n font-family: inherit;\n padding: var(--size-4-1) var(--size-4-2);\n font-size: var(--font-ui-small);\n border-radius: var(--input-radius);\n outline: none;\n}\n@media (hover: hover) {\n .obsidian-dev-utils input[type=month]:hover,\n .obsidian-dev-utils input[type=tel]:hover,\n .obsidian-dev-utils input[type=time]:hover,\n .obsidian-dev-utils input[type=url]:hover,\n .obsidian-dev-utils input[type=week]:hover {\n border-color: var(--background-modifier-border-hover);\n transition: box-shadow 0.15s ease-in-out, border 0.15s ease-in-out;\n }\n}\n.obsidian-dev-utils input[type=month]:active, .obsidian-dev-utils input[type=month]:focus,\n.obsidian-dev-utils input[type=tel]:active,\n.obsidian-dev-utils input[type=tel]:focus,\n.obsidian-dev-utils input[type=time]:active,\n.obsidian-dev-utils input[type=time]:focus,\n.obsidian-dev-utils input[type=url]:active,\n.obsidian-dev-utils input[type=url]:focus,\n.obsidian-dev-utils input[type=week]:active,\n.obsidian-dev-utils input[type=week]:focus {\n border-color: var(--background-modifier-border-focus);\n transition: box-shadow 0.15s ease-in-out, border 0.15s ease-in-out;\n}\n.obsidian-dev-utils input[type=month]:active, .obsidian-dev-utils input[type=month]:focus, .obsidian-dev-utils input[type=month]:focus-visible,\n.obsidian-dev-utils input[type=tel]:active,\n.obsidian-dev-utils input[type=tel]:focus,\n.obsidian-dev-utils input[type=tel]:focus-visible,\n.obsidian-dev-utils input[type=time]:active,\n.obsidian-dev-utils input[type=time]:focus,\n.obsidian-dev-utils input[type=time]:focus-visible,\n.obsidian-dev-utils input[type=url]:active,\n.obsidian-dev-utils input[type=url]:focus,\n.obsidian-dev-utils input[type=url]:focus-visible,\n.obsidian-dev-utils input[type=week]:active,\n.obsidian-dev-utils input[type=week]:focus,\n.obsidian-dev-utils input[type=week]:focus-visible {\n box-shadow: 0 0 0 2px var(--background-modifier-border-focus);\n}\n.obsidian-dev-utils input[type=month]::placeholder,\n.obsidian-dev-utils input[type=tel]::placeholder,\n.obsidian-dev-utils input[type=time]::placeholder,\n.obsidian-dev-utils input[type=url]::placeholder,\n.obsidian-dev-utils input[type=week]::placeholder {\n color: var(--text-faint);\n}\n.mod-rtl input[type=month],\n.mod-rtl input[type=time],\n.mod-rtl input[type=week],\n.is-rtl input[type=month],\n.is-rtl input[type=time],\n.is-rtl input[type=week],\n.rtl input[type=month],\n.rtl input[type=time],\n.rtl input[type=week] {\n direction: rtl;\n}\n.mod-rtl input[type=month]::-webkit-calendar-picker-indicator,\n.mod-rtl input[type=time]::-webkit-calendar-picker-indicator,\n.mod-rtl input[type=week]::-webkit-calendar-picker-indicator,\n.is-rtl input[type=month]::-webkit-calendar-picker-indicator,\n.is-rtl input[type=time]::-webkit-calendar-picker-indicator,\n.is-rtl input[type=week]::-webkit-calendar-picker-indicator,\n.rtl input[type=month]::-webkit-calendar-picker-indicator,\n.rtl input[type=time]::-webkit-calendar-picker-indicator,\n.rtl input[type=week]::-webkit-calendar-picker-indicator {\n right: var(--size-4-1);\n left: auto;\n}\n\n.obsidian-dev-utils input[type=month],\n.obsidian-dev-utils input[type=time],\n.obsidian-dev-utils input[type=week] {\n font-variant-numeric: tabular-nums;\n position: relative;\n}\n.obsidian-dev-utils input[type=month]::-webkit-datetime-edit-text,\n.obsidian-dev-utils input[type=time]::-webkit-datetime-edit-text,\n.obsidian-dev-utils input[type=week]::-webkit-datetime-edit-text {\n color: var(--text-faint);\n padding-inline-end: 0;\n}\n.obsidian-dev-utils input[type=month]::-webkit-calendar-picker-indicator,\n.obsidian-dev-utils input[type=time]::-webkit-calendar-picker-indicator,\n.obsidian-dev-utils input[type=week]::-webkit-calendar-picker-indicator {\n position: absolute;\n left: var(--size-4-1);\n right: auto;\n opacity: 0.5;\n}\n.obsidian-dev-utils input[type=month]::-webkit-datetime-edit-month-field:active, .obsidian-dev-utils input[type=month]::-webkit-datetime-edit-month-field:focus, .obsidian-dev-utils input[type=month]::-webkit-datetime-edit-day-field:active, .obsidian-dev-utils input[type=month]::-webkit-datetime-edit-day-field:focus, .obsidian-dev-utils input[type=month]::-webkit-datetime-edit-year-field:active, .obsidian-dev-utils input[type=month]::-webkit-datetime-edit-year-field:focus,\n.obsidian-dev-utils input[type=time]::-webkit-datetime-edit-month-field:active,\n.obsidian-dev-utils input[type=time]::-webkit-datetime-edit-month-field:focus,\n.obsidian-dev-utils input[type=time]::-webkit-datetime-edit-day-field:active,\n.obsidian-dev-utils input[type=time]::-webkit-datetime-edit-day-field:focus,\n.obsidian-dev-utils input[type=time]::-webkit-datetime-edit-year-field:active,\n.obsidian-dev-utils input[type=time]::-webkit-datetime-edit-year-field:focus,\n.obsidian-dev-utils input[type=week]::-webkit-datetime-edit-month-field:active,\n.obsidian-dev-utils input[type=week]::-webkit-datetime-edit-month-field:focus,\n.obsidian-dev-utils input[type=week]::-webkit-datetime-edit-day-field:active,\n.obsidian-dev-utils input[type=week]::-webkit-datetime-edit-day-field:focus,\n.obsidian-dev-utils input[type=week]::-webkit-datetime-edit-year-field:active,\n.obsidian-dev-utils input[type=week]::-webkit-datetime-edit-year-field:focus {\n background-color: var(--text-selection);\n color: var(--text-normal);\n cursor: text;\n}\n.mod-rtl .obsidian-dev-utils input[type=month], .is-rtl .obsidian-dev-utils input[type=month], .rtl .obsidian-dev-utils input[type=month],\n.mod-rtl .obsidian-dev-utils input[type=time],\n.is-rtl .obsidian-dev-utils input[type=time],\n.rtl .obsidian-dev-utils input[type=time],\n.mod-rtl .obsidian-dev-utils input[type=week],\n.is-rtl .obsidian-dev-utils input[type=week],\n.rtl .obsidian-dev-utils input[type=week] {\n direction: rtl;\n}\n.mod-rtl .obsidian-dev-utils input[type=month]::-webkit-calendar-picker-indicator, .is-rtl .obsidian-dev-utils input[type=month]::-webkit-calendar-picker-indicator, .rtl .obsidian-dev-utils input[type=month]::-webkit-calendar-picker-indicator,\n.mod-rtl .obsidian-dev-utils input[type=time]::-webkit-calendar-picker-indicator,\n.is-rtl .obsidian-dev-utils input[type=time]::-webkit-calendar-picker-indicator,\n.rtl .obsidian-dev-utils input[type=time]::-webkit-calendar-picker-indicator,\n.mod-rtl .obsidian-dev-utils input[type=week]::-webkit-calendar-picker-indicator,\n.is-rtl .obsidian-dev-utils input[type=week]::-webkit-calendar-picker-indicator,\n.rtl .obsidian-dev-utils input[type=week]::-webkit-calendar-picker-indicator {\n left: auto;\n right: var(--size-4-1);\n}\n\nbody:not(.is-ios):not(.is-android) .obsidian-dev-utils input[type=month],\nbody:not(.is-ios):not(.is-android) .obsidian-dev-utils input[type=time],\nbody:not(.is-ios):not(.is-android) .obsidian-dev-utils input[type=week] {\n padding-inline-start: var(--size-4-6);\n}\n\n.obsidian-dev-utils input[type=time]::-webkit-calendar-picker-indicator {\n margin-inline-start: 0;\n}\n\n.obsidian-dev-utilsprogress.loop {\n min-width: 200px;\n}\n\n@keyframes obsidian-dev-utils-minimized-modal-bar-pulse {\n 0%, 100% {\n box-shadow: var(--shadow-s);\n }\n 50% {\n box-shadow: 0 0 0 2px var(--interactive-accent);\n }\n}\n@keyframes obsidian-dev-utils-minimized-modal-bar-attention {\n 0% {\n box-shadow: 0 0 0 0 var(--interactive-accent);\n }\n 40% {\n box-shadow: 0 0 0 4px var(--interactive-accent);\n }\n 100% {\n box-shadow: var(--shadow-s);\n }\n}\n.obsidian-dev-utils.minimizable-modal .minimize-button {\n position: absolute;\n top: var(--size-4-2);\n right: calc(var(--size-4-2) + var(--size-4-9));\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--size-2-2);\n border: none;\n border-radius: var(--radius-s);\n background: transparent;\n color: var(--icon-color);\n cursor: pointer;\n box-shadow: none;\n}\n.obsidian-dev-utils.minimizable-modal .minimize-button:hover {\n background: var(--background-modifier-hover);\n color: var(--icon-color-hover);\n}\n.obsidian-dev-utils.minimized-modal-bar {\n position: fixed;\n right: var(--size-4-4);\n bottom: calc(var(--size-4-4) + var(--size-4-8));\n z-index: var(--layer-modal);\n display: flex;\n align-items: center;\n gap: var(--size-4-2);\n padding: var(--size-4-2) var(--size-4-3);\n border: 1px solid var(--background-modifier-border);\n border-radius: var(--radius-m);\n background: var(--background-secondary);\n box-shadow: var(--shadow-s);\n cursor: pointer;\n animation: obsidian-dev-utils-minimized-modal-bar-pulse 2s ease-in-out infinite;\n}\n.obsidian-dev-utils.minimized-modal-bar:hover {\n background-image: linear-gradient(var(--background-modifier-hover), var(--background-modifier-hover));\n}\n.obsidian-dev-utils.minimized-modal-bar.minimized-modal-bar-attention {\n animation: obsidian-dev-utils-minimized-modal-bar-attention 0.35s ease-out;\n}\n.obsidian-dev-utils.minimized-modal-bar .minimized-modal-bar-title {\n font-weight: var(--font-medium);\n}\n.obsidian-dev-utils.minimized-modal-bar .restore-button,\n.obsidian-dev-utils.minimized-modal-bar .cancel-button {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--size-2-2);\n border: none;\n border-radius: var(--radius-s);\n background: transparent;\n color: var(--icon-color);\n cursor: pointer;\n box-shadow: none;\n}\n.obsidian-dev-utils.minimized-modal-bar .restore-button:hover,\n.obsidian-dev-utils.minimized-modal-bar .cancel-button:hover {\n background: var(--background-modifier-hover);\n color: var(--icon-color-hover);\n}\n\n.obsidian-dev-utils.modal-container .ok-button {\n margin-right: 10px;\n margin-top: 20px;\n}\n\n.obsidian-dev-utils .multiple-dropdown-component select,\n.obsidian-dev-utils .multiple-dropdown-component select:focus,\n.obsidian-dev-utils .multiple-dropdown-component .dropdown {\n height: auto;\n padding-top: 3px;\n}\n.obsidian-dev-utils .multiple-dropdown-component select option:checked,\n.obsidian-dev-utils .multiple-dropdown-component select:focus option:checked,\n.obsidian-dev-utils .multiple-dropdown-component .dropdown option:checked {\n background-color: #1967d2;\n color: #fff;\n}\n\n.obsidian-dev-utils.plugin-notice-name {\n color: var(--text-accent);\n display: inline-block;\n font-weight: var(--font-bold);\n margin-bottom: var(--size-4-2);\n}\n.obsidian-dev-utils.plugin-notice-content {\n padding-right: var(--size-4-5);\n position: relative;\n}\n.obsidian-dev-utils.plugin-notice-content .obsidian-dev-utils.cancel-button {\n display: block;\n margin-top: var(--size-4-2);\n width: fit-content;\n}\n.obsidian-dev-utils.plugin-notice-content .obsidian-dev-utils.plugin-notice-close-button {\n position: absolute;\n right: var(--size-4-3);\n top: var(--size-4-3);\n}\n.obsidian-dev-utils.plugin-notice-requires-explicit-close.notice {\n padding: 0;\n}\n.obsidian-dev-utils.plugin-notice-requires-explicit-close.notice .obsidian-dev-utils.plugin-notice-content {\n padding: var(--size-4-3) var(--size-4-4);\n}\n\n.obsidian-dev-utils.plugin-settings-tab a:focus {\n outline: 2px solid var(--link-color);\n}\n\n.obsidian-dev-utils.popover {\n max-width: min(420px, 90vw);\n min-width: 320px;\n padding: var(--size-4-2) var(--size-4-3);\n position: absolute;\n z-index: var(--layer-menu);\n}\n.obsidian-dev-utils.popover .setting-item {\n align-items: center;\n border-top: none;\n gap: var(--size-4-2);\n padding: var(--size-2-1) 0;\n}\n.obsidian-dev-utils.popover .setting-item-info {\n margin-right: 0;\n}\n.obsidian-dev-utils.popover .setting-item-control {\n flex-grow: 1;\n justify-content: flex-end;\n}\n.obsidian-dev-utils.popover input[type=text] {\n width: 100%;\n}\n\n.obsidian-dev-utils.prompt-modal .text-box {\n width: 100%;\n}\n\nbody button:not(.clickable-icon) {\n color: var(--text-color);\n}\n\n.obsidian-dev-utils.tri-state-checkbox-component input[type=checkbox]:indeterminate {\n appearance: checkbox;\n}\n\n.obsidian-dev-utils :invalid:not(.untouched) {\n box-shadow: 0 0 0 2px var(--text-error);\n}\n.obsidian-dev-utils input.metadata-input-text:active:invalid:not(.untouched), .obsidian-dev-utils input.metadata-input-text:focus-visible:invalid:not(.untouched), .obsidian-dev-utils input.metadata-input-text:focus:invalid:not(.untouched),\n.obsidian-dev-utils input[type=date]:active:invalid:not(.untouched),\n.obsidian-dev-utils input[type=date]:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils input[type=date]:focus:invalid:not(.untouched),\n.obsidian-dev-utils input[type=datetime-local]:active:invalid:not(.untouched),\n.obsidian-dev-utils input[type=datetime-local]:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils input[type=datetime-local]:focus:invalid:not(.untouched),\n.obsidian-dev-utils input[type=email]:active:invalid:not(.untouched),\n.obsidian-dev-utils input[type=email]:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils input[type=email]:focus:invalid:not(.untouched),\n.obsidian-dev-utils input[type=number]:active:invalid:not(.untouched),\n.obsidian-dev-utils input[type=number]:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils input[type=number]:focus:invalid:not(.untouched),\n.obsidian-dev-utils input[type=password]:active:invalid:not(.untouched),\n.obsidian-dev-utils input[type=password]:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils input[type=password]:focus:invalid:not(.untouched),\n.obsidian-dev-utils input[type=search]:active:invalid:not(.untouched),\n.obsidian-dev-utils input[type=search]:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils input[type=search]:focus:invalid:not(.untouched),\n.obsidian-dev-utils input[type=text]:active:invalid:not(.untouched),\n.obsidian-dev-utils input[type=text]:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils input[type=text]:focus:invalid:not(.untouched),\n.obsidian-dev-utils textarea:active:invalid:not(.untouched),\n.obsidian-dev-utils textarea:focus-visible:invalid:not(.untouched),\n.obsidian-dev-utils textarea:focus:invalid:not(.untouched) {\n box-shadow: 0 0 0 2px var(--text-error);\n}\n.obsidian-dev-utils.setting-component-wrapper {\n position: relative;\n display: inline-flex;\n}\n.obsidian-dev-utils.overlay-validator {\n caret-color: transparent;\n cursor: default;\n position: absolute;\n background-color: transparent;\n border: none;\n outline: none;\n pointer-events: none;\n z-index: 9999;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n}\n.obsidian-dev-utils.tooltip.tooltip-validator {\n position: absolute;\n top: calc(100% + 8px);\n width: max-content;\n}\n\n/*# sourceMappingURL=data:application/json;charset=utf-8,%7B%22version%22:3,%22sourceRoot%22:%22%22,%22sources%22:%5B%22../src/styles/code-highlighter-component.scss%22,%22../src/styles/editor-lock.scss%22,%22../src/styles/input.scss%22,%22../src/styles/input-time.scss%22,%22../src/styles/loop.scss%22,%22../src/styles/minimizable-modal.scss%22,%22../src/styles/modal-container.scss%22,%22../src/styles/multiple-dropdown-component.scss%22,%22../src/styles/plugin-notice.scss%22,%22../src/styles/plugin-settings-tab.scss%22,%22../src/styles/popover.scss%22,%22../src/styles/prompt-modal.scss%22,%22../src/styles/tldraw-button-color-workaround.scss%22,%22../src/styles/tri-state-checkbox-component.scss%22,%22../src/styles/validation.scss%22%5D,%22names%22:%5B%5D,%22mappings%22:%22AAEI;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;;;ACvCN;EACE;EACA;EACA;;AAEA;EACE;EACA;;;AAMJ;EACE;IACE;IACA;;;AAIJ;EACE;;;ACvBA;EACE;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGE;EACE;AAAA;AAAA;AAAA;AAAA;IACE;IACA,YACE;;;AAMR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;EACA,YACE;;AAIJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;AAGF;AAAA;AAAA;AAAA;AAAA;EACE;;AASE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;EACA;;;AC7DV;AAAA;AAAA;EAGE;EACA;;AAEA;AAAA;AAAA;EACE;EACA;;AAGF;AAAA;AAAA;EACE;EACA;EACA;EACA;;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAEE;EACA;EACA;;AAIK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGP;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EACE;EACA;;;AAKF;AAAA;AAAA;EACE;;;AAMJ;EACE;;;ACjDJ;EACE;;;ACFJ;EACE;IAEE;;EAGF;IACE;;;AAIJ;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;;AAOA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AASN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAOA;EACE;;AAOF;EACE;;AAGF;EACE;;AAGF;AAAA;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;AAAA;EACE;EACA;;;ACxGJ;EACE;EACA;;;ACFF;AAAA;AAAA;EAGE;EACA;;AAEA;AAAA;AAAA;EACE;EACA;;;ACTN;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAKF;EACE;EACA;EACA;;AAOJ;EACE;;AAEA;EACE;;;AChCF;EACE;;;ACCJ;EAIE;EACA;EACA;EACA;EACA;;AAGA;EACE;EACA;EACA;EACA;;AAGF;EACE;;AAGF;EACE;EACA;;AAGF;EACE;;;AC9BF;EACE;;;ACON;EACE;;;ACTE;EACE;;;ACKJ;EAPA;;AAuBI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAvBJ;;AA6BA;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA%22,%22file%22:%22styles.css%22,%22sourcesContent%22:%5B%22.obsidian-dev-utils%20%7B%5Cn%20%20&.code-highlighter-component%20%7B%5Cn%20%20%20%20textarea,%20pre,%20code%20%7B%5Cn%20%20%20%20%20%20font-family:%20var(--font-monospace);%5Cn%20%20%20%20%20%20line-height:%20var(--line-height-normal);%5Cn%20%20%20%20%20%20margin:%200;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20textarea,%20code%20%7B%5Cn%20%20%20%20%20%20font-size:%20var(--code-size);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20textarea%20%7B%5Cn%20%20%20%20%20%20background:%20transparent;%5Cn%20%20%20%20%20%20color:%20transparent;%5Cn%20%20%20%20%20%20z-index:%202;%5Cn%20%20%20%20%20%20width:%2020em;%5Cn%20%20%20%20%20%20height:%2010em;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20pre%20%7B%5Cn%20%20%20%20%20%20position:%20absolute;%5Cn%20%20%20%20%20%20pointer-events:%20none;%5Cn%20%20%20%20%20%20border:%20var(--input-border-width)%20solid%20transparent;%5Cn%20%20%20%20%20%20overflow:%20auto;%5Cn%20%20%20%20%20%20inset:%200;%5Cn%20%20%20%20%20%20padding:%20var(--size-4-1)%20var(--size-4-2);%5Cn%20%20%20%20%20%20z-index:%201;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20pre::after%20%7B%5Cn%20%20%20%20%20%20content:%20%5C%22%5C%22;%5Cn%20%20%20%20%20%20display:%20block;%5Cn%20%20%20%20%20%20height:%20var(--bottom-gap,%200);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20pre.is-placeholder%20%7B%5Cn%20%20%20%20%20%20opacity:%200.6;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20code%20%7B%5Cn%20%20%20%20%20%20display:%20block;%5Cn%20%20%20%20%20%20padding:%200;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22//%20Lock%20indicators%20shown%20in%20the%20tab%20header%20and%20the%20status%20bar%20while%20a%20note%20is%20locked.%20These%20live%20in%5Cn//%20global%20Obsidian%20DOM%20(tab%20header%20/%20status%20bar),%20so%20they%20are%20styled%20with%20a%20global%20class%20rather%20than%5Cn//%20scoped%20under%20%60.obsidian-dev-utils%60.%5Cn.obsidian-dev-utils-lock-indicator%20%7B%5Cn%20%20display:%20inline-flex;%5Cn%20%20align-items:%20center;%5Cn%20%20color:%20var(--text-muted);%5Cn%5Cn%20%20.svg-icon%20%7B%5Cn%20%20%20%20width:%20var(--icon-s);%5Cn%20%20%20%20height:%20var(--icon-s);%5Cn%20%20%7D%5Cn%7D%5Cn%5Cn//%20Flashed%20on%20every%20lock%20indicator%20(tab%20header,%20view%20action,%20status%20bar)%20when%20the%20user%20attempts%20to%5Cn//%20type%20in%20a%20locked%20note,%20to%20make%20clear%20the%20note%20is%20read-only.%20Re-added%20per%20rejected%20keystroke.%5Cn@keyframes%20obsidian-dev-utils-lock-indicator-flash%20%7B%5Cn%20%2040%25%20%7B%5Cn%20%20%20%20color:%20var(--text-error);%5Cn%20%20%20%20transform:%20scale(1.4);%5Cn%20%20%7D%5Cn%7D%5Cn%5Cn.obsidian-dev-utils-lock-indicator-flash%20%7B%5Cn%20%20animation:%20obsidian-dev-utils-lock-indicator-flash%200.35s%20ease-in-out;%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20input%5Btype='url'%5D%20%7B%5Cn%20%20%20%20height:%20var(--input-height)%5Cn%20%20%7D%5Cn%5Cn%20%20input%5Btype='month'%5D,%5Cn%20%20input%5Btype='tel'%5D,%5Cn%20%20input%5Btype='time'%5D,%5Cn%20%20input%5Btype='url'%5D,%5Cn%20%20input%5Btype='week'%5D%20%7B%5Cn%20%20%20%20-webkit-app-region:%20no-drag;%5Cn%20%20%20%20background:%20var(--background-modifier-form-field);%5Cn%20%20%20%20border:%20var(--input-border-width)%20solid%20var(--background-modifier-border);%5Cn%20%20%20%20color:%20var(--text-normal);%5Cn%20%20%20%20font-family:%20inherit;%5Cn%20%20%20%20padding:%20var(--size-4-1)%20var(--size-4-2);%5Cn%20%20%20%20font-size:%20var(--font-ui-small);%5Cn%20%20%20%20border-radius:%20var(--input-radius);%5Cn%20%20%20%20outline:%20none;%5Cn%5Cn%20%20%20%20@at-root%20%7B%5Cn%20%20%20%20%20%20@media%20(hover:%20hover)%20%7B%5Cn%20%20%20%20%20%20%20%20&:hover%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20border-color:%20var(--background-modifier-border-hover);%5Cn%20%20%20%20%20%20%20%20%20%20transition:%5Cn%20%20%20%20%20%20%20%20%20%20%20%20box-shadow%200.15s%20ease-in-out,%5Cn%20%20%20%20%20%20%20%20%20%20%20%20border%200.15s%20ease-in-out;%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20&:active,%5Cn%20%20%20%20&:focus%20%7B%5Cn%20%20%20%20%20%20border-color:%20var(--background-modifier-border-focus);%5Cn%20%20%20%20%20%20transition:%5Cn%20%20%20%20%20%20%20%20box-shadow%200.15s%20ease-in-out,%5Cn%20%20%20%20%20%20%20%20border%200.15s%20ease-in-out;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20&:active,%5Cn%20%20%20%20&:focus,%5Cn%20%20%20%20&:focus-visible%20%7B%5Cn%20%20%20%20%20%20box-shadow:%200%200%200%202px%20var(--background-modifier-border-focus);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20&::placeholder%20%7B%5Cn%20%20%20%20%20%20color:%20var(--text-faint);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20@at-root%20%7B%5Cn%20%20%20%20.mod-rtl,%5Cn%20%20%20%20.is-rtl,%5Cn%20%20%20%20.rtl%20%7B%5Cn%20%20%20%20%20%20&%20%7B%5Cn%20%20%20%20%20%20%20%20input%5Btype='month'%5D,%5Cn%20%20%20%20%20%20%20%20input%5Btype='time'%5D,%5Cn%20%20%20%20%20%20%20%20input%5Btype='week'%5D%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20direction:%20rtl;%5Cn%5Cn%20%20%20%20%20%20%20%20%20%20&::-webkit-calendar-picker-indicator%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20right:%20var(--size-4-1);%5Cn%20%20%20%20%20%20%20%20%20%20%20%20left:%20auto;%5Cn%20%20%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20input%5Btype='month'%5D,%5Cn%20%20input%5Btype='time'%5D,%5Cn%20%20input%5Btype='week'%5D%20%7B%5Cn%20%20%20%20font-variant-numeric:%20tabular-nums;%5Cn%20%20%20%20position:%20relative;%5Cn%5Cn%20%20%20%20&::-webkit-datetime-edit-text%20%7B%5Cn%20%20%20%20%20%20color:%20var(--text-faint);%5Cn%20%20%20%20%20%20padding-inline-end:%200;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20&::-webkit-calendar-picker-indicator%20%7B%5Cn%20%20%20%20%20%20position:%20absolute;%5Cn%20%20%20%20%20%20left:%20var(--size-4-1);%5Cn%20%20%20%20%20%20right:%20auto;%5Cn%20%20%20%20%20%20opacity:%200.5;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20&::-webkit-datetime-edit-month-field,%5Cn%20%20%20%20&::-webkit-datetime-edit-day-field,%5Cn%20%20%20%20&::-webkit-datetime-edit-year-field%20%7B%5Cn%20%20%20%20%20%20&:active,%5Cn%20%20%20%20%20%20&:focus%20%7B%5Cn%20%20%20%20%20%20%20%20background-color:%20var(--text-selection);%5Cn%20%20%20%20%20%20%20%20color:%20var(--text-normal);%5Cn%20%20%20%20%20%20%20%20cursor:%20text;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20@at-root%20.mod-rtl%20&,%5Cn%20%20%20%20%20%20.is-rtl%20&,%5Cn%20%20%20%20%20%20.rtl%20&%20%7B%5Cn%20%20%20%20%20%20direction:%20rtl;%5Cn%5Cn%20%20%20%20%20%20&::-webkit-calendar-picker-indicator%20%7B%5Cn%20%20%20%20%20%20%20%20left:%20auto;%5Cn%20%20%20%20%20%20%20%20right:%20var(--size-4-1);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20@at-root%20%7B%5Cn%20%20%20%20%20%20body:not(.is-ios):not(.is-android)%20&%20%7B%5Cn%20%20%20%20%20%20%20%20padding-inline-start:%20var(--size-4-6);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20input%5Btype='time'%5D%20%7B%5Cn%20%20%20%20&::-webkit-calendar-picker-indicator%20%7B%5Cn%20%20%20%20%20%20margin-inline-start:%200;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20&progress.loop%20%7B%5Cn%20%20%20%20min-width:%20200px;%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22@keyframes%20obsidian-dev-utils-minimized-modal-bar-pulse%20%7B%5Cn%20%200%25,%5Cn%20%20100%25%20%7B%5Cn%20%20%20%20box-shadow:%20var(--shadow-s);%5Cn%20%20%7D%5Cn%5Cn%20%2050%25%20%7B%5Cn%20%20%20%20box-shadow:%200%200%200%202px%20var(--interactive-accent);%5Cn%20%20%7D%5Cn%7D%5Cn%5Cn@keyframes%20obsidian-dev-utils-minimized-modal-bar-attention%20%7B%5Cn%20%200%25%20%7B%5Cn%20%20%20%20box-shadow:%200%200%200%200%20var(--interactive-accent);%5Cn%20%20%7D%5Cn%5Cn%20%2040%25%20%7B%5Cn%20%20%20%20box-shadow:%200%200%200%204px%20var(--interactive-accent);%5Cn%20%20%7D%5Cn%5Cn%20%20100%25%20%7B%5Cn%20%20%20%20box-shadow:%20var(--shadow-s);%5Cn%20%20%7D%5Cn%7D%5Cn%5Cn.obsidian-dev-utils%20%7B%5Cn%20%20//%20The%20minimize%20button%20lives%20inside%20the%20modal%20container,%20left%20of%20Obsidian's%20close%20button.%5Cn%20%20&.minimizable-modal%20%7B%5Cn%20%20%20%20.minimize-button%20%7B%5Cn%20%20%20%20%20%20position:%20absolute;%5Cn%20%20%20%20%20%20top:%20var(--size-4-2);%5Cn%20%20%20%20%20%20right:%20calc(var(--size-4-2)%20+%20var(--size-4-9));%5Cn%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%20%20justify-content:%20center;%5Cn%20%20%20%20%20%20padding:%20var(--size-2-2);%5Cn%20%20%20%20%20%20border:%20none;%5Cn%20%20%20%20%20%20border-radius:%20var(--radius-s);%5Cn%20%20%20%20%20%20background:%20transparent;%5Cn%20%20%20%20%20%20color:%20var(--icon-color);%5Cn%20%20%20%20%20%20cursor:%20pointer;%5Cn%20%20%20%20%20%20box-shadow:%20none;%5Cn%5Cn%20%20%20%20%20%20&:hover%20%7B%5Cn%20%20%20%20%20%20%20%20background:%20var(--background-modifier-hover);%5Cn%20%20%20%20%20%20%20%20color:%20var(--icon-color-hover);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20//%20The%20minimized%20bar%20is%20appended%20to%20document.body.%20It%20floats%20at%20the%20bottom-right%20while%20minimized,%5Cn%20%20//%20and%20gently%20pulses%20an%20accent%20ring%20so%20the%20user%20does%20not%20forget%20about%20the%20minimized%20operation.%5Cn%20%20//%20It%20floats%20a%20status-bar's%20height%20above%20the%20bottom%20edge%20so%20it%20never%20covers%20the%20bottom-right%5Cn%20%20//%20status-bar%20items%20(e.g.%20the%20editor-lock%20unlock%20indicator,%20which%20lives%20in%20the%20same%20corner).%5Cn%20%20&.minimized-modal-bar%20%7B%5Cn%20%20%20%20position:%20fixed;%5Cn%20%20%20%20right:%20var(--size-4-4);%5Cn%20%20%20%20bottom:%20calc(var(--size-4-4)%20+%20var(--size-4-8));%5Cn%20%20%20%20z-index:%20var(--layer-modal);%5Cn%20%20%20%20display:%20flex;%5Cn%20%20%20%20align-items:%20center;%5Cn%20%20%20%20gap:%20var(--size-4-2);%5Cn%20%20%20%20padding:%20var(--size-4-2)%20var(--size-4-3);%5Cn%20%20%20%20border:%201px%20solid%20var(--background-modifier-border);%5Cn%20%20%20%20border-radius:%20var(--radius-m);%5Cn%20%20%20%20background:%20var(--background-secondary);%5Cn%20%20%20%20box-shadow:%20var(--shadow-s);%5Cn%20%20%20%20cursor:%20pointer;%5Cn%20%20%20%20animation:%20obsidian-dev-utils-minimized-modal-bar-pulse%202s%20ease-in-out%20infinite;%5Cn%5Cn%20%20%20%20//%20Layer%20the%20translucent%20hover%20tint%20over%20the%20opaque%20%60background%60%20(%60--background-secondary%60)%20via%5Cn%20%20%20%20//%20%60background-image%60%20instead%20of%20replacing%20the%20background-color.%20%60--background-modifier-hover%60%20is%5Cn%20%20%20%20//%20translucent,%20so%20setting%20it%20as%20%60background%60%20would%20let%20the%20editor%20content%20behind%20the%20floating%20bar%5Cn%20%20%20%20//%20bleed%20through%20and%20make%20the%20title%20unreadable.%20A%20gradient%20of%20the%20tint%20composited%20over%20the%20opaque%5Cn%20%20%20%20//%20base%20keeps%20the%20bar%20opaque%20while%20preserving%20the%20subtle%20hover%20highlight.%5Cn%20%20%20%20&:hover%20%7B%5Cn%20%20%20%20%20%20background-image:%20linear-gradient(var(--background-modifier-hover),%20var(--background-modifier-hover));%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20//%20A%20one-shot,%20more%20pronounced%20flash%20played%20when%20the%20user%20attempts%20a%20blocked%20action%20(a%20keystroke,%5Cn%20%20%20%20//%20right-click,%20or%20opening%20another%20modal)%20while%20this%20modal%20is%20minimized,%20so%20the%20block%20is%20not%5Cn%20%20%20%20//%20silent.%20Its%20higher%20specificity%20overrides%20the%20gentle%20infinite%20idle%20pulse%20while%20it%20plays;%20the%5Cn%20%20%20%20//%20class%20is%20removed%20on%20%60animationend%60,%20restoring%20the%20idle%20pulse.%5Cn%20%20%20%20&.minimized-modal-bar-attention%20%7B%5Cn%20%20%20%20%20%20animation:%20obsidian-dev-utils-minimized-modal-bar-attention%200.35s%20ease-out;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20.minimized-modal-bar-title%20%7B%5Cn%20%20%20%20%20%20font-weight:%20var(--font-medium);%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20.restore-button,%5Cn%20%20%20%20.cancel-button%20%7B%5Cn%20%20%20%20%20%20display:%20flex;%5Cn%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%20%20justify-content:%20center;%5Cn%20%20%20%20%20%20padding:%20var(--size-2-2);%5Cn%20%20%20%20%20%20border:%20none;%5Cn%20%20%20%20%20%20border-radius:%20var(--radius-s);%5Cn%20%20%20%20%20%20background:%20transparent;%5Cn%20%20%20%20%20%20color:%20var(--icon-color);%5Cn%20%20%20%20%20%20cursor:%20pointer;%5Cn%20%20%20%20%20%20box-shadow:%20none;%5Cn%5Cn%20%20%20%20%20%20&:hover%20%7B%5Cn%20%20%20%20%20%20%20%20background:%20var(--background-modifier-hover);%5Cn%20%20%20%20%20%20%20%20color:%20var(--icon-color-hover);%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20&.modal-container%20%7B%5Cn%20%20%20%20.ok-button%20%7B%5Cn%20%20%20%20%20%20margin-right:%2010px;%5Cn%20%20%20%20%20%20margin-top:%2020px;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20.multiple-dropdown-component%20%7B%5Cn%20%20%20%20select,%5Cn%20%20%20%20select:focus,%5Cn%20%20%20%20.dropdown%20%7B%5Cn%20%20%20%20%20%20height:%20auto;%5Cn%20%20%20%20%20%20padding-top:%203px;%5Cn%5Cn%20%20%20%20%20%20option:checked%20%7B%5Cn%20%20%20%20%20%20%20%20background-color:%20%231967d2;%5Cn%20%20%20%20%20%20%20%20color:%20%23fff;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20&.plugin-notice-name%20%7B%5Cn%20%20%20%20color:%20var(--text-accent);%5Cn%20%20%20%20display:%20inline-block;%5Cn%20%20%20%20font-weight:%20var(--font-bold);%5Cn%20%20%20%20margin-bottom:%20var(--size-4-2);%5Cn%20%20%7D%5Cn%5Cn%20%20&.plugin-notice-content%20%7B%5Cn%20%20%20%20padding-right:%20var(--size-4-5);%5Cn%20%20%20%20position:%20relative;%5Cn%5Cn%20%20%20%20.obsidian-dev-utils.cancel-button%20%7B%5Cn%20%20%20%20%20%20display:%20block;%5Cn%20%20%20%20%20%20margin-top:%20var(--size-4-2);%5Cn%20%20%20%20%20%20width:%20fit-content;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20//%20The%20close%20button%20reuses%20Obsidian's%20%60modal-header-button%60%20+%20%60clickable-icon%60%20classes%20so%20it%20matches%5Cn%20%20%20%20//%20The%20native%20modal%20close%20button%20(box%20+%20hover);%20only%20its%20corner%20position%20is%20set%20here.%5Cn%20%20%20%20.obsidian-dev-utils.plugin-notice-close-button%20%7B%5Cn%20%20%20%20%20%20position:%20absolute;%5Cn%20%20%20%20%20%20right:%20var(--size-4-3);%5Cn%20%20%20%20%20%20top:%20var(--size-4-3);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20//%20Move%20the%20notice's%20own%20padding%20onto%20the%20content%20wrapper%20so%20the%20wrapper%20covers%20the%20whole%20clickable%5Cn%20%20//%20Area%20%E2%80%94%20otherwise%20a%20click%20landing%20on%20the%20notice's%20bare%20padding%20(outside%20the%20wrapper)%20would%20bypass%20the%5Cn%20%20//%20Stop-propagation%20guard%20and%20dismiss%20the%20hard-to-close%20notice.%5Cn%20%20&.plugin-notice-requires-explicit-close.notice%20%7B%5Cn%20%20%20%20padding:%200;%5Cn%5Cn%20%20%20%20.obsidian-dev-utils.plugin-notice-content%20%7B%5Cn%20%20%20%20%20%20padding:%20var(--size-4-3)%20var(--size-4-4);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20&.plugin-settings-tab%20%7B%5Cn%20%20%20%20a:focus%20%7B%5Cn%20%20%20%20%20%20outline:%202px%20solid%20var(--link-color);%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22//%20A%20popover%20is%20anchored%20at%20a%20point%20and%20appended%20to%20the%20document%20body,%20outside%20any%20plugin-scoped%5Cn//%20container,%20so%20it%20is%20positioned%20absolutely%20at%20the%20top%20level.%20It%20borrows%20Obsidian's%20%60.menu%60%20look,%5Cn//%20which%20already%20carries%20the%20popup%20background,%20border%20and%20shadow%20%E2%80%94%20only%20layout%20is%20set%20here.%5Cn.obsidian-dev-utils%20%7B%5Cn%20%20&.popover%20%7B%5Cn%20%20%20%20//%20Deliberately%20not%20%60calc(100vw%20-%2016px)%60:%20the%20SCSS%20compiler%20strips%20the%20%60calc(%60%20wrapper%20inside%5Cn%20%20%20%20//%20%60min()%60,%20which%20yields%20invalid%20CSS.%20A%20viewport%20percentage%20keeps%20a%20narrow%20window's%20popover%20on%5Cn%20%20%20%20//%20screen.%5Cn%20%20%20%20max-width:%20min(420px,%2090vw);%5Cn%20%20%20%20min-width:%20320px;%5Cn%20%20%20%20padding:%20var(--size-4-2)%20var(--size-4-3);%5Cn%20%20%20%20position:%20absolute;%5Cn%20%20%20%20z-index:%20var(--layer-menu);%5Cn%5Cn%20%20%20%20//%20Setting%20rows%20are%20built%20for%20a%20full-width%20settings%20tab;%20compact%20them%20for%20a%20popover.%5Cn%20%20%20%20.setting-item%20%7B%5Cn%20%20%20%20%20%20align-items:%20center;%5Cn%20%20%20%20%20%20border-top:%20none;%5Cn%20%20%20%20%20%20gap:%20var(--size-4-2);%5Cn%20%20%20%20%20%20padding:%20var(--size-2-1)%200;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20.setting-item-info%20%7B%5Cn%20%20%20%20%20%20margin-right:%200;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20.setting-item-control%20%7B%5Cn%20%20%20%20%20%20flex-grow:%201;%5Cn%20%20%20%20%20%20justify-content:%20flex-end;%5Cn%20%20%20%20%7D%5Cn%5Cn%20%20%20%20input%5Btype='text'%5D%20%7B%5Cn%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cn%20%20&.prompt-modal%20%7B%5Cn%20%20%20%20.text-box%20%7B%5Cn%20%20%20%20%20%20width:%20100%25;%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%7D%5Cn%22,%22//%20The%20tldraw%20Obsidian%20plugin%20(tldraw/obsidian-plugin)%20ships%20an%20unscoped%20global%20rule%5Cn//%20%60button:not(.clickable-icon)%20%7B%20color:%20currentColor%20%7D%60%20that%20overrides%20Obsidian's%20own%5Cn//%20%60button:not(.clickable-icon)%20%7B%20color:%20var(--text-color)%20%7D%60%20app-wide.%20Obsidian%20sets%5Cn//%20%60--text-color%60%20contextually%20per%20button%20variant%20(%60--text-normal%60%20by%20default,%5Cn//%20%60--text-on-accent%60%20for%20%60.mod-cta%60,%20%60--text-error%60%20for%20%60.mod-warning%60),%20so%20tldraw's%5Cn//%20%60currentColor%60%20discards%20that%20and%20breaks%20button%20contrast%20outside%20tldraw%20%E2%80%94%20e.g.%5Cn//%20White-on-white%20action%20buttons%20inside%20a%20Notice.%20Re-assert%20Obsidian's%20own%20value%20with%20a%5Cn//%20%60body%60-prefixed%20selector%20(specificity%200,1,2)%20so%20it%20wins%20over%20tldraw's%20(0,1,1)%20while%5Cn//%20Staying%20correct%20for%20every%20button%20variant%20(it%20reuses%20the%20same%20contextual%20%60--text-color%60).%5Cn//%20Defensive%20workaround%20%E2%80%94%20remove%20once%20the%20upstream%20fix%20ships%20(tldraw/obsidian-plugin%23210).%5Cnbody%20button:not(.clickable-icon)%20%7B%5Cn%20%20color:%20var(--text-color);%5Cn%7D%5Cn%22,%22.obsidian-dev-utils%20%7B%5Cr%5Cn%20%20&.tri-state-checkbox-component%20%7B%5Cr%5Cn%20%20%20%20input%5Btype='checkbox'%5D:indeterminate%20%7B%5Cr%5Cn%20%20%20%20%20%20appearance:%20checkbox;%5Cr%5Cn%20%20%20%20%7D%5Cr%5Cn%20%20%7D%5Cr%5Cn%7D%5Cr%5Cn%22,%22@mixin%20invalid%20%7B%5Cn%20%20box-shadow:%200%200%200%202px%20var(--text-error);%5Cn%7D%5Cn%5Cn//%20An%20input%20the%20user%20has%20not%20interacted%20with%20yet%20carries%20%60.untouched%60%20(set%20by%20%60PromptModal%60),%20so%20a%20modal%20that%5Cn//%20opens%20invalid%20by%20design%20does%20not%20greet%20the%20user%20in%20red.%20Both%20blocks%20below%20must%20be%20gated:%20the%20input%20is%5Cn//%20focused%20on%20open,%20so%20the%20focus%20block%20alone%20would%20keep%20painting%20it.%5Cn.obsidian-dev-utils%20%7B%5Cn%20%20:invalid:not(.untouched)%20%7B%5Cn%20%20%20%20@include%20invalid;%5Cn%20%20%7D%5Cn%5Cn%20%20input.metadata-input-text,%5Cn%20%20input%5Btype='date'%5D,%5Cn%20%20input%5Btype='datetime-local'%5D,%5Cn%20%20input%5Btype='email'%5D,%5Cn%20%20input%5Btype='number'%5D,%5Cn%20%20input%5Btype='password'%5D,%5Cn%20%20input%5Btype='search'%5D,%5Cn%20%20input%5Btype='text'%5D,%5Cn%20%20textarea%20%7B%5Cn%20%20%20%20&:active,%5Cn%20%20%20%20&:focus-visible,%5Cn%20%20%20%20&:focus%20%7B%5Cn%20%20%20%20%20%20&:invalid:not(.untouched)%20%7B%5Cn%20%20%20%20%20%20%20%20@include%20invalid;%5Cn%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%20%7D%5Cn%5Cn%20%20&.setting-component-wrapper%20%7B%5Cn%20%20%20%20position:%20relative;%5Cn%20%20%20%20display:%20inline-flex;%5Cn%20%20%7D%5Cn%5Cn%20%20&.overlay-validator%20%7B%5Cn%20%20%20%20caret-color:%20transparent;%5Cn%20%20%20%20cursor:%20default;%5Cn%20%20%20%20position:%20absolute;%5Cn%20%20%20%20background-color:%20transparent;%5Cn%20%20%20%20border:%20none;%5Cn%20%20%20%20outline:%20none;%5Cn%20%20%20%20pointer-events:%20none;%5Cn%20%20%20%20z-index:%209999;%5Cn%20%20%20%20left:%200;%5Cn%20%20%20%20top:%200;%5Cn%20%20%20%20width:%20100%25;%5Cn%20%20%20%20height:%20100%25;%5Cn%20%20%7D%5Cn%5Cn%20%20&.tooltip.tooltip-validator%20%7B%5Cn%20%20%20%20position:%20absolute;%5Cn%20%20%20%20top:%20calc(100%25%20+%208px);%5Cn%20%20%20%20width:%20max-content;%5Cn%20%20%7D%5Cn%7D%5Cn%22%5D%7D */\n";
|
|
130
130
|
// Annotate the CommonJS export names for ESM import in node:
|
|
131
131
|
0 && (module.exports = {
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/*
|
|
2
|
+
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
3
|
+
if you want to view the source, please visit the github repository of this plugin
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
(function initCjs() {
|
|
7
|
+
// eslint-disable-next-line obsidianmd/no-global-this -- Actively use globalThis.
|
|
8
|
+
const globalThisRecord = globalThis;
|
|
9
|
+
globalThisRecord['__name'] ??= name;
|
|
10
|
+
const originalRequire = require;
|
|
11
|
+
if (originalRequire && !originalRequire.__isPatched) {
|
|
12
|
+
// eslint-disable-next-line no-global-assign, no-implicit-globals -- We need to patch the `require()` function.
|
|
13
|
+
require = Object.assign(
|
|
14
|
+
(id) => requirePatched(id),
|
|
15
|
+
originalRequire,
|
|
16
|
+
{
|
|
17
|
+
__isPatched: true
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const newFuncs = {
|
|
23
|
+
__extractDefault() {
|
|
24
|
+
return extractDefault;
|
|
25
|
+
},
|
|
26
|
+
process() {
|
|
27
|
+
const browserProcess = {
|
|
28
|
+
browser: true,
|
|
29
|
+
cwd() {
|
|
30
|
+
return '/';
|
|
31
|
+
},
|
|
32
|
+
env: {},
|
|
33
|
+
platform: 'android'
|
|
34
|
+
};
|
|
35
|
+
return browserProcess;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
for (const key of Object.keys(newFuncs)) {
|
|
40
|
+
globalThisRecord[key] ??= newFuncs[key]?.();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function extractDefault(module) {
|
|
44
|
+
return module && module.__esModule && 'default' in module ? module.default : module;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const OBSIDIAN_BUILT_IN_MODULE_NAMES = new Set([
|
|
48
|
+
'@codemirror/autocomplete',
|
|
49
|
+
'@codemirror/collab',
|
|
50
|
+
'@codemirror/commands',
|
|
51
|
+
'@codemirror/language',
|
|
52
|
+
'@codemirror/lint',
|
|
53
|
+
'@codemirror/search',
|
|
54
|
+
'@codemirror/state',
|
|
55
|
+
'@codemirror/text',
|
|
56
|
+
'@codemirror/view',
|
|
57
|
+
'@lezer/common',
|
|
58
|
+
'@lezer/highlight',
|
|
59
|
+
'@lezer/lr',
|
|
60
|
+
'obsidian']
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES = new Set([
|
|
64
|
+
'@codemirror/closebrackets',
|
|
65
|
+
'@codemirror/comment',
|
|
66
|
+
'@codemirror/fold',
|
|
67
|
+
'@codemirror/gutter',
|
|
68
|
+
'@codemirror/highlight',
|
|
69
|
+
'@codemirror/history',
|
|
70
|
+
'@codemirror/matchbrackets',
|
|
71
|
+
'@codemirror/panel',
|
|
72
|
+
'@codemirror/rangeset',
|
|
73
|
+
'@codemirror/rectangular-selection',
|
|
74
|
+
'@codemirror/stream-parser',
|
|
75
|
+
'@codemirror/tooltip']
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
function requirePatched(id) {
|
|
79
|
+
if (OBSIDIAN_BUILT_IN_MODULE_NAMES.has(id) || DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES.has(id)) {
|
|
80
|
+
return originalRequire?.(id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated, obsidianmd/no-global-this -- Need access to app. Actively use globalThis.
|
|
84
|
+
if (globalThis.app.isMobile) {
|
|
85
|
+
if (id === 'process' || id === 'node:process') {
|
|
86
|
+
// eslint-disable-next-line no-console -- Valid usage.
|
|
87
|
+
console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Fake process object is returned instead.`);
|
|
88
|
+
|
|
89
|
+
return process;
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
const module = originalRequire?.(id);
|
|
93
|
+
if (module) {
|
|
94
|
+
return extractDefault(module);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// eslint-disable-next-line no-console -- Valid usage.
|
|
99
|
+
console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Empty object is returned instead.`);
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
})();
|
|
103
|
+
|
|
104
|
+
"use strict";
|
|
105
|
+
var __create = Object.create;
|
|
106
|
+
var __defProp = Object.defineProperty;
|
|
107
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
108
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
109
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
110
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
111
|
+
var __export = (target, all) => {
|
|
112
|
+
for (var name in all)
|
|
113
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
114
|
+
};
|
|
115
|
+
var __copyProps = (to, from, except, desc) => {
|
|
116
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
117
|
+
for (let key of __getOwnPropNames(from))
|
|
118
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
119
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
120
|
+
}
|
|
121
|
+
return to;
|
|
122
|
+
};
|
|
123
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
124
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
125
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
126
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
127
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
128
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
129
|
+
mod
|
|
130
|
+
));
|
|
131
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
132
|
+
var demo_vault_buttons_exports = {};
|
|
133
|
+
__export(demo_vault_buttons_exports, {
|
|
134
|
+
CODE_SCRIPT_TOOLKIT_PLUGIN_ID: () => CODE_SCRIPT_TOOLKIT_PLUGIN_ID,
|
|
135
|
+
formatFailures: () => formatFailures,
|
|
136
|
+
listNotesWithButtons: () => listNotesWithButtons,
|
|
137
|
+
registerDemoVaultButtonSuite: () => registerDemoVaultButtonSuite
|
|
138
|
+
});
|
|
139
|
+
module.exports = __toCommonJS(demo_vault_buttons_exports);
|
|
140
|
+
var import_node_fs = require('node:fs');
|
|
141
|
+
var import_node_path = require('node:path');
|
|
142
|
+
var import_node_process = __toESM(__extractDefault(require('node:process')), 1);
|
|
143
|
+
var import_obsidian_integration_testing = require('obsidian-integration-testing');
|
|
144
|
+
var import_vitest_global_setup_plugin = require('obsidian-integration-testing/vitest-global-setup-plugin');
|
|
145
|
+
var import_vitest = require('vitest');
|
|
146
|
+
var import_root = require('./root.cjs');
|
|
147
|
+
const CODE_SCRIPT_TOOLKIT_PLUGIN_ID = "fix-require-modules";
|
|
148
|
+
const DEFAULT_BUTTON_RESULT_TIMEOUT_IN_MILLISECONDS = 15e3;
|
|
149
|
+
const DEFAULT_SETTLE_TIMEOUT_IN_MILLISECONDS = 2e4;
|
|
150
|
+
const POLL_INTERVAL_IN_MILLISECONDS = 100;
|
|
151
|
+
const OUTPUT_EXCERPT_LENGTH = 400;
|
|
152
|
+
const DEFAULT_EXCLUDED_NOTES = ["README.md"];
|
|
153
|
+
const CODE_BUTTON_FENCE_REG_EXP = /^\s*```code-button/gm;
|
|
154
|
+
function formatFailures(noteName, failures) {
|
|
155
|
+
if (failures.length === 0) {
|
|
156
|
+
return "";
|
|
157
|
+
}
|
|
158
|
+
const details = failures.map((failure) => ` - "${failure.caption}" [${failure.status}]: ${failure.output.replaceAll(/\s+/g, " ").trim()}`).join("\n");
|
|
159
|
+
return `${String(failures.length)} button(s) in ${noteName} did not run cleanly:
|
|
160
|
+
${details}`;
|
|
161
|
+
}
|
|
162
|
+
function listNotesWithButtons(demoVaultPath, excludedNotes) {
|
|
163
|
+
return (0, import_node_fs.readdirSync)(demoVaultPath, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md") && !excludedNotes.has(entry.name)).map((entry) => entry.name).sort().map((name) => ({
|
|
164
|
+
buttonCount: ((0, import_node_fs.readFileSync)((0, import_node_path.join)(demoVaultPath, name), "utf-8").match(CODE_BUTTON_FENCE_REG_EXP) ?? []).length,
|
|
165
|
+
name
|
|
166
|
+
})).filter((note) => note.buttonCount > 0);
|
|
167
|
+
}
|
|
168
|
+
function registerDemoVaultButtonSuite(options = {}) {
|
|
169
|
+
const rootFolder = options.rootFolder ?? (0, import_root.getRootFolder)() ?? import_node_process.default.cwd();
|
|
170
|
+
const demoVaultPath = (0, import_node_path.join)(rootFolder, "demo-vault");
|
|
171
|
+
const excludedNotes = new Set(options.excludedNotes ?? DEFAULT_EXCLUDED_NOTES);
|
|
172
|
+
const settleTimeoutInMilliseconds = options.settleTimeoutInMilliseconds ?? DEFAULT_SETTLE_TIMEOUT_IN_MILLISECONDS;
|
|
173
|
+
const buttonResultTimeoutInMilliseconds = options.buttonResultTimeoutInMilliseconds ?? DEFAULT_BUTTON_RESULT_TIMEOUT_IN_MILLISECONDS;
|
|
174
|
+
const notes = listNotesWithButtons(demoVaultPath, excludedNotes);
|
|
175
|
+
(0, import_vitest.describe)("demo-vault buttons", () => {
|
|
176
|
+
(0, import_vitest.beforeAll)(async () => {
|
|
177
|
+
const isCodeScriptToolkitLoaded = await checkCodeScriptToolkitLoaded(settleTimeoutInMilliseconds);
|
|
178
|
+
(0, import_vitest.expect)(isCodeScriptToolkitLoaded, "CodeScript Toolkit did not load, so no button could render").toBe(true);
|
|
179
|
+
});
|
|
180
|
+
(0, import_vitest.it)("has at least one note with a code button", () => {
|
|
181
|
+
(0, import_vitest.expect)(notes.length).toBeGreaterThan(0);
|
|
182
|
+
});
|
|
183
|
+
for (const note of notes) {
|
|
184
|
+
(0, import_vitest.it)(`runs every code button in ${note.name}`, async () => {
|
|
185
|
+
const captions = await openNoteAndListButtonCaptions(note, settleTimeoutInMilliseconds);
|
|
186
|
+
(0, import_vitest.expect)(captions.length, `${note.name} declares ${String(note.buttonCount)} button(s) but only ${String(captions.length)} rendered`).toBeGreaterThanOrEqual(note.buttonCount);
|
|
187
|
+
const failures = [];
|
|
188
|
+
for (const caption of captions) {
|
|
189
|
+
const result = await clickButton(note.name, caption, {
|
|
190
|
+
buttonResultTimeoutInMilliseconds,
|
|
191
|
+
settleTimeoutInMilliseconds
|
|
192
|
+
});
|
|
193
|
+
if (result.status !== "ok") {
|
|
194
|
+
failures.push(result);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
(0, import_vitest.expect)(failures, formatFailures(note.name, failures)).toEqual([]);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
async function checkCodeScriptToolkitLoaded(timeoutInMilliseconds) {
|
|
203
|
+
return (0, import_obsidian_integration_testing.evalInObsidian)({
|
|
204
|
+
async callback({ app, codeScriptToolkitPluginId, intervalInMilliseconds, lib: { waitUntil }, timeoutInMilliseconds: timeout }) {
|
|
205
|
+
if (typeof app.plugins.isEnabled === "function" && !app.plugins.isEnabled()) {
|
|
206
|
+
await app.plugins.setEnable(true);
|
|
207
|
+
}
|
|
208
|
+
if (!app.plugins.getPlugin(codeScriptToolkitPluginId)) {
|
|
209
|
+
await app.plugins.enablePlugin(codeScriptToolkitPluginId);
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
await waitUntil({
|
|
213
|
+
intervalInMilliseconds,
|
|
214
|
+
message: "CodeScript Toolkit never loaded",
|
|
215
|
+
predicate: () => app.plugins.getPlugin(codeScriptToolkitPluginId) !== null,
|
|
216
|
+
timeoutInMilliseconds: timeout
|
|
217
|
+
});
|
|
218
|
+
} catch {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
return true;
|
|
222
|
+
},
|
|
223
|
+
input: {
|
|
224
|
+
codeScriptToolkitPluginId: CODE_SCRIPT_TOOLKIT_PLUGIN_ID,
|
|
225
|
+
intervalInMilliseconds: POLL_INTERVAL_IN_MILLISECONDS,
|
|
226
|
+
timeoutInMilliseconds
|
|
227
|
+
},
|
|
228
|
+
vaultPath: (0, import_vitest_global_setup_plugin.getTemporaryVault)().path
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
async function clickButton(notePath, buttonCaption, timeouts) {
|
|
232
|
+
return (0, import_obsidian_integration_testing.evalInObsidian)({
|
|
233
|
+
async callback({
|
|
234
|
+
app,
|
|
235
|
+
buttonResultTimeoutInMilliseconds,
|
|
236
|
+
caption,
|
|
237
|
+
intervalInMilliseconds,
|
|
238
|
+
lib: { waitUntil },
|
|
239
|
+
obsidianModule,
|
|
240
|
+
outputExcerptLength,
|
|
241
|
+
settleTimeoutInMilliseconds
|
|
242
|
+
}) {
|
|
243
|
+
function view() {
|
|
244
|
+
return app.workspace.getActiveViewOfType(obsidianModule.MarkdownView);
|
|
245
|
+
}
|
|
246
|
+
function previewEl() {
|
|
247
|
+
return view()?.containerEl.querySelector(":scope .markdown-preview-view") ?? null;
|
|
248
|
+
}
|
|
249
|
+
function buttons() {
|
|
250
|
+
return [...view()?.containerEl.querySelectorAll(":scope .block-language-code-button button.mod-cta") ?? []];
|
|
251
|
+
}
|
|
252
|
+
function findButton() {
|
|
253
|
+
return buttons().find((candidate) => candidate.textContent === caption);
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
await waitUntil({
|
|
257
|
+
intervalInMilliseconds,
|
|
258
|
+
message: `code button "${caption}" never rendered`,
|
|
259
|
+
predicate: () => {
|
|
260
|
+
const scroller = previewEl();
|
|
261
|
+
if (scroller) {
|
|
262
|
+
scroller.scrollTop = scroller.scrollHeight;
|
|
263
|
+
}
|
|
264
|
+
return findButton() !== void 0;
|
|
265
|
+
},
|
|
266
|
+
timeoutInMilliseconds: settleTimeoutInMilliseconds
|
|
267
|
+
});
|
|
268
|
+
} catch {
|
|
269
|
+
return { caption, output: "", status: "timeout" };
|
|
270
|
+
}
|
|
271
|
+
const button = findButton();
|
|
272
|
+
if (!button) {
|
|
273
|
+
return { caption, output: "", status: "timeout" };
|
|
274
|
+
}
|
|
275
|
+
const block = button.closest(".block-language-code-button") ?? button.parentElement;
|
|
276
|
+
button.scrollIntoView();
|
|
277
|
+
button.click();
|
|
278
|
+
let status;
|
|
279
|
+
try {
|
|
280
|
+
await waitUntil({
|
|
281
|
+
intervalInMilliseconds,
|
|
282
|
+
message: `button "${caption}" never reported a result`,
|
|
283
|
+
predicate: () => /Executed (?:successfully|with error)/.test(block?.textContent ?? ""),
|
|
284
|
+
timeoutInMilliseconds: buttonResultTimeoutInMilliseconds
|
|
285
|
+
});
|
|
286
|
+
const text = block?.textContent ?? "";
|
|
287
|
+
if (text.includes("Executed with error")) {
|
|
288
|
+
status = "error";
|
|
289
|
+
} else if (text.includes("Executed successfully")) {
|
|
290
|
+
status = "ok";
|
|
291
|
+
} else {
|
|
292
|
+
status = "unknown";
|
|
293
|
+
}
|
|
294
|
+
} catch {
|
|
295
|
+
status = "timeout";
|
|
296
|
+
}
|
|
297
|
+
return { caption, output: (block?.textContent ?? "").slice(0, outputExcerptLength), status };
|
|
298
|
+
},
|
|
299
|
+
input: {
|
|
300
|
+
buttonResultTimeoutInMilliseconds: timeouts.buttonResultTimeoutInMilliseconds,
|
|
301
|
+
caption: buttonCaption,
|
|
302
|
+
intervalInMilliseconds: POLL_INTERVAL_IN_MILLISECONDS,
|
|
303
|
+
notePath,
|
|
304
|
+
outputExcerptLength: OUTPUT_EXCERPT_LENGTH,
|
|
305
|
+
settleTimeoutInMilliseconds: timeouts.settleTimeoutInMilliseconds
|
|
306
|
+
},
|
|
307
|
+
vaultPath: (0, import_vitest_global_setup_plugin.getTemporaryVault)().path
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
async function openNoteAndListButtonCaptions(note, settleTimeoutInMilliseconds) {
|
|
311
|
+
return (0, import_obsidian_integration_testing.evalInObsidian)({
|
|
312
|
+
async callback({ app, expectedButtonCount, intervalInMilliseconds, lib: { waitUntil }, notePath, obsidianModule, timeoutInMilliseconds }) {
|
|
313
|
+
function view() {
|
|
314
|
+
return app.workspace.getActiveViewOfType(obsidianModule.MarkdownView);
|
|
315
|
+
}
|
|
316
|
+
function previewEl() {
|
|
317
|
+
return view()?.containerEl.querySelector(":scope .markdown-preview-view") ?? null;
|
|
318
|
+
}
|
|
319
|
+
function captions() {
|
|
320
|
+
const rendered = [...view()?.containerEl.querySelectorAll(":scope .block-language-code-button button.mod-cta") ?? []].map((button) => button.textContent).filter((caption) => caption !== "");
|
|
321
|
+
return [...new Set(rendered)];
|
|
322
|
+
}
|
|
323
|
+
await app.workspace.openLinkText(notePath.replace(/\.md$/, ""), "", false);
|
|
324
|
+
await app.workspace.getLeaf(false).setViewState({ state: { file: notePath, mode: "preview" }, type: "markdown" });
|
|
325
|
+
try {
|
|
326
|
+
await waitUntil({
|
|
327
|
+
intervalInMilliseconds,
|
|
328
|
+
message: `"${notePath}" never mounted all ${String(expectedButtonCount)} of its buttons`,
|
|
329
|
+
predicate: () => {
|
|
330
|
+
const scroller = previewEl();
|
|
331
|
+
if (scroller) {
|
|
332
|
+
scroller.scrollTop = scroller.scrollHeight;
|
|
333
|
+
}
|
|
334
|
+
return captions().length >= expectedButtonCount;
|
|
335
|
+
},
|
|
336
|
+
timeoutInMilliseconds
|
|
337
|
+
});
|
|
338
|
+
} catch {
|
|
339
|
+
}
|
|
340
|
+
return captions();
|
|
341
|
+
},
|
|
342
|
+
input: {
|
|
343
|
+
expectedButtonCount: note.buttonCount,
|
|
344
|
+
intervalInMilliseconds: POLL_INTERVAL_IN_MILLISECONDS,
|
|
345
|
+
notePath: note.name,
|
|
346
|
+
timeoutInMilliseconds: settleTimeoutInMilliseconds
|
|
347
|
+
},
|
|
348
|
+
vaultPath: (0, import_vitest_global_setup_plugin.getTemporaryVault)().path
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
352
|
+
0 && (module.exports = {
|
|
353
|
+
CODE_SCRIPT_TOOLKIT_PLUGIN_ID,
|
|
354
|
+
formatFailures,
|
|
355
|
+
listNotesWithButtons,
|
|
356
|
+
registerDemoVaultButtonSuite
|
|
357
|
+
});
|
|
358
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL3NjcmlwdC11dGlscy9kZW1vLXZhdWx0LWJ1dHRvbnMudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQGZpbGVcbiAqXG4gKiBBIHZpdGVzdCBzdWl0ZSB0aGF0IG9wZW5zIGV2ZXJ5IG5vdGUgb2YgYSBwbHVnaW4ncyBpbi1yZXBvIGBkZW1vLXZhdWx0L2AsIGNsaWNrcyBlYWNoIGBjb2RlLWJ1dHRvbmBcbiAqIGluIGl0IGFnYWluc3QgYSByZWFsIE9ic2lkaWFuLCBhbmQgZmFpbHMgb24gYW55IGJ1dHRvbiB0aGF0IGVycm9ycyBvciBuZXZlciByZXBvcnRzIGEgcmVzdWx0LlxuICpcbiAqIEEgZGVtbyB2YXVsdCdzIGJ1dHRvbnMgYXJlIHRoZSBvbmUgcGFydCBvZiBpdCBubyBvdGhlciBnYXRlIGNhbiBjaGVjay4gYGxpbnQ6bWRgIHJlYWRzIHRoZSBtYXJrZG93bixcbiAqIHRoZSBjb3ZlcmFnZSBzdWl0ZSAoe0BsaW5rIC4vZGVtby12YXVsdC1jb3ZlcmFnZS50cyB8IGByZWdpc3RlckRlbW9WYXVsdENvdmVyYWdlU3VpdGVgfSkgY2hlY2tzIHRoZVxuICogYXV0aG9yaW5nIGNvbnZlbnRpb25zLCBhbmQgbmVpdGhlciBleGVjdXRlcyBhbnl0aGluZyBcdTIwMTQgYSBidXR0b24gd2hvc2UgYHJlcXVpcmUoJy9kZW1vU2V0dXAudHMnKWAgcGF0aFxuICogaXMgd3JvbmcsIG9yIHRoYXQgY2FsbHMgYW4gQVBJIHRoYXQgaGFzIHNpbmNlIGNoYW5nZWQgc2hhcGUsIGZhaWxzIGF0IGNsaWNrIHRpbWUgYW5kIG5vd2hlcmUgZWxzZS5cbiAqXG4gKiBUaGUgY29tcGFuaW9uIGhhbGYgXHUyMDE0IHNlZWRpbmcgdGhlIHRlbXAgdmF1bHQgd2l0aCB0aGUgZGVtby12YXVsdCB0cmVlLCBpdHMgYC5vYnNpZGlhbmAgY29uZmlnLCBhbmQgdGhlXG4gKiBDb2RlU2NyaXB0IFRvb2xraXQgYmluYXJ5IHRoYXQgdHVybnMgYGBgYCBgYGBjb2RlLWJ1dHRvbiBgYGBgIGZlbmNlcyBpbnRvIGJ1dHRvbnMgXHUyMDE0IGlzXG4gKiBgYnVpbGREZW1vVmF1bHRQb3B1bGF0ZWAgaW4gYG9ic2lkaWFuLWludGVncmF0aW9uLXRlc3RpbmdgOyBoYW5kIGl0cyByZXN1bHQgdG8gdGhlIHByb2plY3Qnc1xuICogYGdsb2JhbFNldHVwYCBhbmQgbmFtZSBDb2RlU2NyaXB0IFRvb2xraXQgaW4gYGVuYWJsZUNvbW11bml0eVBsdWdpbnNgLlxuICovXG5cbmltcG9ydCB7XG4gIHJlYWRkaXJTeW5jLFxuICByZWFkRmlsZVN5bmNcbn0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5pbXBvcnQgeyBldmFsSW5PYnNpZGlhbiB9IGZyb20gJ29ic2lkaWFuLWludGVncmF0aW9uLXRlc3RpbmcnO1xuaW1wb3J0IHsgZ2V0VGVtcG9yYXJ5VmF1bHQgfSBmcm9tICdvYnNpZGlhbi1pbnRlZ3JhdGlvbi10ZXN0aW5nL3ZpdGVzdC1nbG9iYWwtc2V0dXAtcGx1Z2luJztcbmltcG9ydCB7XG4gIGJlZm9yZUFsbCxcbiAgZGVzY3JpYmUsXG4gIGV4cGVjdCxcbiAgaXRcbn0gZnJvbSAndml0ZXN0JztcblxuaW1wb3J0IHsgZ2V0Um9vdEZvbGRlciB9IGZyb20gJy4vcm9vdC50cyc7XG5cbi8qKlxuICogQ29kZVNjcmlwdCBUb29sa2l0J3MgbWFuaWZlc3QgaWQuIEl0IGlzIHN0aWxsIHRoZSBwbHVnaW4ncyBvcmlnaW5hbCBgZml4LXJlcXVpcmUtbW9kdWxlc2AgaWQsIHdoaWNoXG4gKiBubyBsb25nZXIgbWF0Y2hlcyBpdHMgbmFtZSBcdTIwMTQgdGhlIGlkIGlzIHB1Ymxpc2hlZCwgc28gaXQgY2Fubm90IGJlIGNoYW5nZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBDT0RFX1NDUklQVF9UT09MS0lUX1BMVUdJTl9JRCA9ICdmaXgtcmVxdWlyZS1tb2R1bGVzJztcblxuLyoqXG4gKiBUaGUgb3V0Y29tZSBvZiBjbGlja2luZyBvbmUgYnV0dG9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlbW9WYXVsdEJ1dHRvblJlc3VsdCB7XG4gIC8qKlxuICAgKiBUaGUgYnV0dG9uJ3MgY2FwdGlvbiwgYXMgcmVuZGVyZWQuXG4gICAqL1xuICByZWFkb25seSBjYXB0aW9uOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSByZXN1bHQgbGluZSBDb2RlU2NyaXB0IFRvb2xraXQgcHJpbnRlZCB1bmRlciB0aGUgYnV0dG9uLCB0cnVuY2F0ZWQuXG4gICAqL1xuICByZWFkb25seSBvdXRwdXQ6IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgYnV0dG9uIHJlcG9ydGVkIHN1Y2Nlc3MsIHJlcG9ydGVkIGFuIGVycm9yLCBvciBuZXZlciByZXBvcnRlZCBhdCBhbGwuXG4gICAqL1xuICByZWFkb25seSBzdGF0dXM6ICdlcnJvcicgfCAnb2snIHwgJ3RpbWVvdXQnIHwgJ3Vua25vd24nO1xufVxuXG4vKipcbiAqIE9uZSBkZW1vLXZhdWx0IG5vdGUgYW5kIGhvdyBtYW55IGJ1dHRvbnMgaXRzIHNvdXJjZSBkZWNsYXJlcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZW1vVmF1bHROb3RlIHtcbiAgLyoqXG4gICAqIEhvdyBtYW55IGBjb2RlLWJ1dHRvbmAgZmVuY2VzIHRoZSBub3RlJ3Mgc291cmNlIGRlY2xhcmVzLlxuICAgKi9cbiAgcmVhZG9ubHkgYnV0dG9uQ291bnQ6IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIG5vdGUncyBmaWxlIG5hbWUsIHJlbGF0aXZlIHRvIHRoZSBkZW1vIHZhdWx0IHJvb3QuXG4gICAqL1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVGhlIG9wdGlvbnMgZm9yIHtAbGluayByZWdpc3RlckRlbW9WYXVsdEJ1dHRvblN1aXRlfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpc3RlckRlbW9WYXVsdEJ1dHRvblN1aXRlT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBIb3cgbG9uZywgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBhIGNsaWNrZWQgYnV0dG9uIHRvIHJlcG9ydCBhIHJlc3VsdC5cbiAgICpcbiAgICogQGRlZmF1bHQgYDE1MDAwYFxuICAgKi9cbiAgcmVhZG9ubHkgYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBOb3RlIGZpbGUgbmFtZXMgKHJlbGF0aXZlIHRvIHRoZSBkZW1vIHZhdWx0IHJvb3QpIHRvIHNraXAuXG4gICAqXG4gICAqIEBkZWZhdWx0IGBbJ1JFQURNRS5tZCddYFxuICAgKi9cbiAgcmVhZG9ubHkgZXhjbHVkZWROb3Rlcz86IHJlYWRvbmx5IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVwb3NpdG9yeSByb290IGhvbGRpbmcgYGRlbW8tdmF1bHQvYC5cbiAgICpcbiAgICogQGRlZmF1bHQgdGhlIHJlc29sdmVkIHJlcG8gcm9vdCwgZmFsbGluZyBiYWNrIHRvIGBwcm9jZXNzLmN3ZCgpYC5cbiAgICovXG4gIHJlYWRvbmx5IHJvb3RGb2xkZXI/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEhvdyBsb25nLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGEgbm90ZSdzIHByZXZpZXcgYW5kIGl0cyBidXR0b25zIHRvIG1vdW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCBgMjAwMDBgXG4gICAqL1xuICByZWFkb25seSBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHM/OiBudW1iZXI7XG59XG5cbi8qKlxuICogVGhlIHdhaXRpbmcgYnVkZ2V0cyBhIHNpbmdsZSBidXR0b24gY2xpY2sgaXMgYWxsb3dlZC5cbiAqL1xuaW50ZXJmYWNlIENsaWNrQnV0dG9uVGltZW91dHMge1xuICAvKipcbiAgICogSG93IGxvbmcgdG8gd2FpdCBmb3IgdGhlIGNsaWNrZWQgYnV0dG9uIHRvIHJlcG9ydCBhIHJlc3VsdC5cbiAgICovXG4gIHJlYWRvbmx5IGJ1dHRvblJlc3VsdFRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBIb3cgbG9uZyB0byB3YWl0IGZvciB0aGUgYnV0dG9uIGl0c2VsZiB0byBtb3VudC5cbiAgICovXG4gIHJlYWRvbmx5IHNldHRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xufVxuXG5jb25zdCBERUZBVUxUX0JVVFRPTl9SRVNVTFRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAxNV8wMDA7XG5jb25zdCBERUZBVUxUX1NFVFRMRV9USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDIwXzAwMDtcbmNvbnN0IFBPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTID0gMTAwO1xuY29uc3QgT1VUUFVUX0VYQ0VSUFRfTEVOR1RIID0gNDAwO1xuXG4vLyBgUkVBRE1FLm1kYCBpcyB0aGUgcmVwby1mYWNpbmcgcGFnZSBHaXRIdWIgcmVuZGVycywgbm90IGEgd2Fsa3Rocm91Z2guIGAwMCBTdGFydC5tZGAgaXMgZGVsaWJlcmF0ZWx5XG4vLyBOT1QgZXhjbHVkZWQ6IHNpbmNlIFQ0NzggdGhlIGxhbmRpbmcgbm90ZXMgY2FycnkgYnV0dG9ucyBvZiB0aGVpciBvd24uXG5jb25zdCBERUZBVUxUX0VYQ0xVREVEX05PVEVTID0gWydSRUFETUUubWQnXTtcblxuY29uc3QgQ09ERV9CVVRUT05fRkVOQ0VfUkVHX0VYUCA9IC9eXFxzKmBgYGNvZGUtYnV0dG9uL2dtO1xuXG4vLyBUaGUgcmVuZGVyZWQtYnV0dG9uIHNlbGVjdG9yIGlzIGA6c2NvcGUgLmJsb2NrLWxhbmd1YWdlLWNvZGUtYnV0dG9uIGJ1dHRvbi5tb2QtY3RhYC4gSXQgaXMgd3JpdHRlblxuLy8gT3V0IGF0IGVhY2ggdXNlIHNpdGUgcmF0aGVyIHRoYW4gaGVsZCBpbiBhIGNvbnN0YW50IGhlcmU6IGV2ZXJ5IGNsb3N1cmUgYmVsb3cgaXMgc2VyaWFsaXplZCB3aXRoXG4vLyBgdG9TdHJpbmcoKWAgYW5kIGV2YWx1YXRlZCBpbnNpZGUgT2JzaWRpYW4sIHdoZXJlIG5vdGhpbmcgZnJvbSB0aGlzIG1vZHVsZSdzIHNjb3BlIGV4aXN0cy5cblxuLyoqXG4gKiBCdWlsZHMgdGhlIGFzc2VydGlvbiBtZXNzYWdlIGZvciBhIG5vdGUncyBmYWlsaW5nIGJ1dHRvbnMuXG4gKlxuICogVGhlIGNhcHR1cmVkIG91dHB1dCBpcyBpbmNsdWRlZCBiZWNhdXNlIGEgYnV0dG9uJ3MgZmFpbHVyZSBpcyBhIHJ1bnRpbWUgb25lIFx1MjAxNCB0aGUgc3RhY2sgQ29kZVNjcmlwdFxuICogVG9vbGtpdCBwcmludHMgdW5kZXIgaXQgaXMgdGhlIG9ubHkgZGlhZ25vc2lzIHRoZXJlIGlzLlxuICpcbiAqIEBwYXJhbSBub3RlTmFtZSAtIFRoZSBub3RlIHRoZSBidXR0b25zIGJlbG9uZyB0by5cbiAqIEBwYXJhbSBmYWlsdXJlcyAtIFRoZSBmYWlsaW5nIGJ1dHRvbnMuXG4gKiBAcmV0dXJucyBUaGUgbWVzc2FnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdEZhaWx1cmVzKG5vdGVOYW1lOiBzdHJpbmcsIGZhaWx1cmVzOiByZWFkb25seSBEZW1vVmF1bHRCdXR0b25SZXN1bHRbXSk6IHN0cmluZyB7XG4gIGlmIChmYWlsdXJlcy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBjb25zdCBkZXRhaWxzID0gZmFpbHVyZXNcbiAgICAubWFwKChmYWlsdXJlKSA9PiBgICAtIFwiJHtmYWlsdXJlLmNhcHRpb259XCIgWyR7ZmFpbHVyZS5zdGF0dXN9XTogJHtmYWlsdXJlLm91dHB1dC5yZXBsYWNlQWxsKC9cXHMrL2csICcgJykudHJpbSgpfWApXG4gICAgLmpvaW4oJ1xcbicpO1xuICByZXR1cm4gYCR7U3RyaW5nKGZhaWx1cmVzLmxlbmd0aCl9IGJ1dHRvbihzKSBpbiAke25vdGVOYW1lfSBkaWQgbm90IHJ1biBjbGVhbmx5OlxcbiR7ZGV0YWlsc31gO1xufVxuXG4vKipcbiAqIExpc3RzIHRoZSBkZW1vIHZhdWx0J3MgdG9wLWxldmVsIG5vdGVzIHRoYXQgZGVjbGFyZSBhdCBsZWFzdCBvbmUgYGNvZGUtYnV0dG9uYC5cbiAqXG4gKiBPbmx5IHRoZSB2YXVsdCByb290IGlzIHdhbGtlZDogYE1hdGVyaWFscy9gIGhvbGRzIGZpeHR1cmVzIHRoZSB3YWxrdGhyb3VnaHMgYWN0IG9uLCBub3Qgd2Fsa3Rocm91Z2hzLlxuICpcbiAqIEBwYXJhbSBkZW1vVmF1bHRQYXRoIC0gVGhlIGRlbW8gdmF1bHQgcm9vdC5cbiAqIEBwYXJhbSBleGNsdWRlZE5vdGVzIC0gTm90ZSBmaWxlIG5hbWVzIHRvIHNraXAuXG4gKiBAcmV0dXJucyBUaGUgbm90ZXMsIHNvcnRlZCBieSBuYW1lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGlzdE5vdGVzV2l0aEJ1dHRvbnMoZGVtb1ZhdWx0UGF0aDogc3RyaW5nLCBleGNsdWRlZE5vdGVzOiBSZWFkb25seVNldDxzdHJpbmc+KTogRGVtb1ZhdWx0Tm90ZVtdIHtcbiAgcmV0dXJuIHJlYWRkaXJTeW5jKGRlbW9WYXVsdFBhdGgsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KVxuICAgIC5maWx0ZXIoKGVudHJ5KSA9PiBlbnRyeS5pc0ZpbGUoKSAmJiBlbnRyeS5uYW1lLmVuZHNXaXRoKCcubWQnKSAmJiAhZXhjbHVkZWROb3Rlcy5oYXMoZW50cnkubmFtZSkpXG4gICAgLm1hcCgoZW50cnkpID0+IGVudHJ5Lm5hbWUpXG4gICAgLnNvcnQoKVxuICAgIC5tYXAoKG5hbWUpID0+ICh7XG4gICAgICBidXR0b25Db3VudDogKHJlYWRGaWxlU3luYyhqb2luKGRlbW9WYXVsdFBhdGgsIG5hbWUpLCAndXRmLTgnKS5tYXRjaChDT0RFX0JVVFRPTl9GRU5DRV9SRUdfRVhQKSA/PyBbXSkubGVuZ3RoLFxuICAgICAgbmFtZVxuICAgIH0pKVxuICAgIC5maWx0ZXIoKG5vdGUpID0+IG5vdGUuYnV0dG9uQ291bnQgPiAwKTtcbn1cblxuLyogdjggaWdub3JlIHN0YXJ0IC0tIEV2ZXJ5IGFzc2VydGlvbiBiZWxvdyBydW5zIGFnYWluc3QgYSByZWFsIE9ic2lkaWFuIG92ZXIgQ0RQLCBkcml2ZW4gYnkgY2xvc3VyZXMgdGhpcyBwcm9jZXNzIHNlcmlhbGl6ZXMgYW5kIGFub3RoZXIgZXhlY3V0ZXMuIFRoZSB0ZXN0YWJsZSBwYXJ0cyBhcmUgbGlzdE5vdGVzV2l0aEJ1dHRvbnMgYW5kIGZvcm1hdEZhaWx1cmVzLCB3aGljaCBoYXZlIHRoZWlyIG93biB1bml0IHRlc3RzLiAqL1xuLyoqXG4gKiBSZWdpc3RlcnMgYSB2aXRlc3Qgc3VpdGUgdGhhdCBjbGlja3MgZXZlcnkgYGNvZGUtYnV0dG9uYCBpbiB0aGUgcmVwbydzIGRlbW8gdmF1bHQuXG4gKlxuICogT25lIGBpdGAgcGVyIG5vdGUsIGFuZCBvbmUgYGV2YWxJbk9ic2lkaWFuYCBwZXIgYnV0dG9uOiBhIHNpbmdsZSBjbG9zdXJlIHJ1bnMgYXMgb25lIENEUFxuICogYFJ1bnRpbWUuZXZhbHVhdGVgLCB3aGljaCB0aGUgaGFybmVzcyBjYXBzIGF0IDMwIHMsIHNvIGEgbm90ZSB3aXRoIGEgZG96ZW4gYnV0dG9ucyB3b3VsZCBvdGhlcndpc2VcbiAqIHRpbWUgb3V0IGFzIGEgd2hvbGUgcmF0aGVyIHRoYW4gcmVwb3J0aW5nIHdoaWNoIGJ1dHRvbiBmYWlsZWQuXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBUaGUge0BsaW5rIFJlZ2lzdGVyRGVtb1ZhdWx0QnV0dG9uU3VpdGVPcHRpb25zfS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyRGVtb1ZhdWx0QnV0dG9uU3VpdGUob3B0aW9uczogUmVnaXN0ZXJEZW1vVmF1bHRCdXR0b25TdWl0ZU9wdGlvbnMgPSB7fSk6IHZvaWQge1xuICBjb25zdCByb290Rm9sZGVyID0gb3B0aW9ucy5yb290Rm9sZGVyID8/IGdldFJvb3RGb2xkZXIoKSA/PyBwcm9jZXNzLmN3ZCgpO1xuICBjb25zdCBkZW1vVmF1bHRQYXRoID0gam9pbihyb290Rm9sZGVyLCAnZGVtby12YXVsdCcpO1xuICBjb25zdCBleGNsdWRlZE5vdGVzID0gbmV3IFNldChvcHRpb25zLmV4Y2x1ZGVkTm90ZXMgPz8gREVGQVVMVF9FWENMVURFRF9OT1RFUyk7XG4gIGNvbnN0IHNldHRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcyA9IG9wdGlvbnMuc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzID8/IERFRkFVTFRfU0VUVExFX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTO1xuICBjb25zdCBidXR0b25SZXN1bHRUaW1lb3V0SW5NaWxsaXNlY29uZHMgPSBvcHRpb25zLmJ1dHRvblJlc3VsdFRpbWVvdXRJbk1pbGxpc2Vjb25kcyA/PyBERUZBVUxUX0JVVFRPTl9SRVNVTFRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFM7XG5cbiAgY29uc3Qgbm90ZXMgPSBsaXN0Tm90ZXNXaXRoQnV0dG9ucyhkZW1vVmF1bHRQYXRoLCBleGNsdWRlZE5vdGVzKTtcblxuICBkZXNjcmliZSgnZGVtby12YXVsdCBidXR0b25zJywgKCkgPT4ge1xuICAgIGJlZm9yZUFsbChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBpc0NvZGVTY3JpcHRUb29sa2l0TG9hZGVkID0gYXdhaXQgY2hlY2tDb2RlU2NyaXB0VG9vbGtpdExvYWRlZChzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHMpO1xuICAgICAgLy8gV2l0aG91dCBpdCBldmVyeSBgY29kZS1idXR0b25gIGZlbmNlIHN0YXlzIGEgcGxhaW4gY29kZSBibG9jaywgc28gZXZlcnkgbm90ZSBiZWxvdyB3b3VsZCByZXBvcnRcbiAgICAgIC8vIFplcm8gYnV0dG9ucyBhbmQgcGFzcyB2YWN1b3VzbHkuIEZhaWwgaGVyZSBpbnN0ZWFkLCBvbmNlLCB3aXRoIHRoZSByZWFzb24uXG4gICAgICBleHBlY3QoaXNDb2RlU2NyaXB0VG9vbGtpdExvYWRlZCwgJ0NvZGVTY3JpcHQgVG9vbGtpdCBkaWQgbm90IGxvYWQsIHNvIG5vIGJ1dHRvbiBjb3VsZCByZW5kZXInKS50b0JlKHRydWUpO1xuICAgIH0pO1xuXG4gICAgLy8gQSB2YXVsdCB3aG9zZSBub3RlcyBkZWNsYXJlIG5vIGJ1dHRvbnMgaXMgYSByZWFsIGZhaWx1cmUgb2YgRzk4J3MgaW50ZXJhY3RpdmUgaGFsZiwgbm90IGEgcmVhc29uXG4gICAgLy8gVG8gcmVnaXN0ZXIgbm90aGluZyBhbmQgcmVwb3J0IGdyZWVuLlxuICAgIGl0KCdoYXMgYXQgbGVhc3Qgb25lIG5vdGUgd2l0aCBhIGNvZGUgYnV0dG9uJywgKCkgPT4ge1xuICAgICAgZXhwZWN0KG5vdGVzLmxlbmd0aCkudG9CZUdyZWF0ZXJUaGFuKDApO1xuICAgIH0pO1xuXG4gICAgZm9yIChjb25zdCBub3RlIG9mIG5vdGVzKSB7XG4gICAgICBpdChgcnVucyBldmVyeSBjb2RlIGJ1dHRvbiBpbiAke25vdGUubmFtZX1gLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGNhcHRpb25zID0gYXdhaXQgb3Blbk5vdGVBbmRMaXN0QnV0dG9uQ2FwdGlvbnMobm90ZSwgc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzKTtcbiAgICAgICAgLy8gUmVhZGluZyB2aWV3IG1vdW50cyBhIG5vdGUncyBsZWFkaW5nIHNlY3Rpb25zIG1vcmUgdGhhbiBvbmNlIHdoaWxlIGl0IHNldHRsZXMsIHNvIHRoZSBET00gY2FuXG4gICAgICAgIC8vIEhvbGQgc2V2ZXJhbCBlbGVtZW50cyBwZXIgZmVuY2UuIFRoZSBjYXB0aW9ucyBhcmUgZGVkdXBsaWNhdGVkLCBhbmQgdGhlIGFzc2VydGlvbiBpcyB0aGF0IGF0XG4gICAgICAgIC8vIExlYXN0IGFzIG1hbnkgRElTVElOQ1QgYnV0dG9ucyByZW5kZXJlZCBhcyB0aGUgc291cmNlIGRlY2xhcmVzIFx1MjAxNCBhIGZlbmNlIHRoYXQgc2lsZW50bHkgc3RheWVkXG4gICAgICAgIC8vIEEgcGxhaW4gY29kZSBibG9jayBpcyB0aGUgZmFpbHVyZSB0aGlzIGNhdGNoZXMuXG4gICAgICAgIGV4cGVjdChjYXB0aW9ucy5sZW5ndGgsIGAke25vdGUubmFtZX0gZGVjbGFyZXMgJHtTdHJpbmcobm90ZS5idXR0b25Db3VudCl9IGJ1dHRvbihzKSBidXQgb25seSAke1N0cmluZyhjYXB0aW9ucy5sZW5ndGgpfSByZW5kZXJlZGApXG4gICAgICAgICAgLnRvQmVHcmVhdGVyVGhhbk9yRXF1YWwobm90ZS5idXR0b25Db3VudCk7XG5cbiAgICAgICAgY29uc3QgZmFpbHVyZXM6IERlbW9WYXVsdEJ1dHRvblJlc3VsdFtdID0gW107XG4gICAgICAgIGZvciAoY29uc3QgY2FwdGlvbiBvZiBjYXB0aW9ucykge1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNsaWNrQnV0dG9uKG5vdGUubmFtZSwgY2FwdGlvbiwge1xuICAgICAgICAgICAgYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzLFxuICAgICAgICAgICAgc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHJlc3VsdC5zdGF0dXMgIT09ICdvaycpIHtcbiAgICAgICAgICAgIGZhaWx1cmVzLnB1c2gocmVzdWx0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBleHBlY3QoZmFpbHVyZXMsIGZvcm1hdEZhaWx1cmVzKG5vdGUubmFtZSwgZmFpbHVyZXMpKS50b0VxdWFsKFtdKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfSk7XG59XG5cbi8qIHY4IGlnbm9yZSBzdG9wICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBEcml2ZXMgYSByZWFsIE9ic2lkaWFuIG92ZXIgQ0RQOiB0aGUgY2xvc3VyZSBpcyBzZXJpYWxpemVkIGhlcmUgYW5kIGV4ZWN1dGVkIGluIGFub3RoZXIgcHJvY2Vzcywgc28gaXQgY2Fubm90IGJlIGV4ZXJjaXNlZCBieSBhIHVuaXQgdGVzdC4gKi9cbi8qKlxuICogVHVybnMgcmVzdHJpY3RlZCBtb2RlIG9mZiBhbmQgZW5hYmxlcyBDb2RlU2NyaXB0IFRvb2xraXQsIHdob3NlIGJpbmFyeSB0aGUgZ2xvYmFsIHNldHVwIHNlZWRlZC5cbiAqXG4gKiBAcGFyYW0gdGltZW91dEluTWlsbGlzZWNvbmRzIC0gSG93IGxvbmcgdG8gd2FpdCBmb3IgaXQgdG8gbG9hZC5cbiAqIEByZXR1cm5zIFdoZXRoZXIgQ29kZVNjcmlwdCBUb29sa2l0IGlzIGxvYWRlZC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY2hlY2tDb2RlU2NyaXB0VG9vbGtpdExvYWRlZCh0aW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICByZXR1cm4gZXZhbEluT2JzaWRpYW4oe1xuICAgIGFzeW5jIGNhbGxiYWNrKHsgYXBwLCBjb2RlU2NyaXB0VG9vbGtpdFBsdWdpbklkLCBpbnRlcnZhbEluTWlsbGlzZWNvbmRzLCBsaWI6IHsgd2FpdFVudGlsIH0sIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogdGltZW91dCB9KTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICBpZiAodHlwZW9mIGFwcC5wbHVnaW5zLmlzRW5hYmxlZCA9PT0gJ2Z1bmN0aW9uJyAmJiAhYXBwLnBsdWdpbnMuaXNFbmFibGVkKCkpIHtcbiAgICAgICAgYXdhaXQgYXBwLnBsdWdpbnMuc2V0RW5hYmxlKHRydWUpO1xuICAgICAgfVxuICAgICAgaWYgKCFhcHAucGx1Z2lucy5nZXRQbHVnaW4oY29kZVNjcmlwdFRvb2xraXRQbHVnaW5JZCkpIHtcbiAgICAgICAgYXdhaXQgYXBwLnBsdWdpbnMuZW5hYmxlUGx1Z2luKGNvZGVTY3JpcHRUb29sa2l0UGx1Z2luSWQpO1xuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgd2FpdFVudGlsKHtcbiAgICAgICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzLFxuICAgICAgICAgIG1lc3NhZ2U6ICdDb2RlU2NyaXB0IFRvb2xraXQgbmV2ZXIgbG9hZGVkJyxcbiAgICAgICAgICBwcmVkaWNhdGU6ICgpOiBib29sZWFuID0+IGFwcC5wbHVnaW5zLmdldFBsdWdpbihjb2RlU2NyaXB0VG9vbGtpdFBsdWdpbklkKSAhPT0gbnVsbCxcbiAgICAgICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IHRpbWVvdXRcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcbiAgICBpbnB1dDoge1xuICAgICAgY29kZVNjcmlwdFRvb2xraXRQbHVnaW5JZDogQ09ERV9TQ1JJUFRfVE9PTEtJVF9QTFVHSU5fSUQsXG4gICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzOiBQT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyxcbiAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kc1xuICAgIH0sXG4gICAgdmF1bHRQYXRoOiBnZXRUZW1wb3JhcnlWYXVsdCgpLnBhdGhcbiAgfSk7XG59XG5cbi8qIHY4IGlnbm9yZSBzdG9wICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBEcml2ZXMgYSByZWFsIE9ic2lkaWFuIG92ZXIgQ0RQOiB0aGUgY2xvc3VyZSBpcyBzZXJpYWxpemVkIGhlcmUgYW5kIGV4ZWN1dGVkIGluIGFub3RoZXIgcHJvY2Vzcywgc28gaXQgY2Fubm90IGJlIGV4ZXJjaXNlZCBieSBhIHVuaXQgdGVzdC4gKi9cbi8qKlxuICogQ2xpY2tzIG9uZSBidXR0b24gYW5kIHJlYWRzIHRoZSByZXN1bHQgbGluZSBDb2RlU2NyaXB0IFRvb2xraXQgd3JpdGVzIHVuZGVyIGl0LlxuICpcbiAqIEEgYnV0dG9uIHRoYXQgcmUtcmVuZGVycyBpdHMgb3duIG5vdGUgKGEgc2V0dGluZ3MgY2hhbmdlLCBhIHJlbG9hZCkgZGV0YWNoZXMgdGhlIGJsb2NrIGl0IGxpdmVzIGluLFxuICogc28gdGhlIGJsb2NrIGVsZW1lbnQgaXMgY2FwdHVyZWQgQkVGT1JFIHRoZSBjbGljayBhbmQgcmVhZCBhZnRlcndhcmRzIFx1MjAxNCBDb2RlU2NyaXB0IFRvb2xraXQgd3JpdGVzIHRoZVxuICogcmVzdWx0IGludG8gdGhhdCBzYW1lIGVsZW1lbnQgZXZlbiBvbmNlIGl0IGlzIGRldGFjaGVkLlxuICpcbiAqIEBwYXJhbSBub3RlUGF0aCAtIFRoZSBub3RlIGhvbGRpbmcgdGhlIGJ1dHRvbi5cbiAqIEBwYXJhbSBidXR0b25DYXB0aW9uIC0gVGhlIGJ1dHRvbidzIHJlbmRlcmVkIGNhcHRpb24sIHdoaWNoIGlzIGhvdyBpdCBpcyBhZGRyZXNzZWQuXG4gKiBAcGFyYW0gdGltZW91dHMgLSBUaGUgcmVuZGVyIGFuZCByZXN1bHQgYnVkZ2V0cy5cbiAqIEByZXR1cm5zIFRoZSB7QGxpbmsgRGVtb1ZhdWx0QnV0dG9uUmVzdWx0fS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY2xpY2tCdXR0b24oXG4gIG5vdGVQYXRoOiBzdHJpbmcsXG4gIGJ1dHRvbkNhcHRpb246IHN0cmluZyxcbiAgdGltZW91dHM6IENsaWNrQnV0dG9uVGltZW91dHNcbik6IFByb21pc2U8RGVtb1ZhdWx0QnV0dG9uUmVzdWx0PiB7XG4gIHJldHVybiBldmFsSW5PYnNpZGlhbih7XG4gICAgYXN5bmMgY2FsbGJhY2soe1xuICAgICAgYXBwLFxuICAgICAgYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzLFxuICAgICAgY2FwdGlvbixcbiAgICAgIGludGVydmFsSW5NaWxsaXNlY29uZHMsXG4gICAgICBsaWI6IHsgd2FpdFVudGlsIH0sXG4gICAgICBvYnNpZGlhbk1vZHVsZSxcbiAgICAgIG91dHB1dEV4Y2VycHRMZW5ndGgsXG4gICAgICBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHNcbiAgICB9KTogUHJvbWlzZTxEZW1vVmF1bHRCdXR0b25SZXN1bHQ+IHtcbiAgICAgIGZ1bmN0aW9uIHZpZXcoKTogSW5zdGFuY2VUeXBlPHR5cGVvZiBvYnNpZGlhbk1vZHVsZS5NYXJrZG93blZpZXc+IHwgbnVsbCB7XG4gICAgICAgIHJldHVybiBhcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUob2JzaWRpYW5Nb2R1bGUuTWFya2Rvd25WaWV3KTtcbiAgICAgIH1cbiAgICAgIGZ1bmN0aW9uIHByZXZpZXdFbCgpOiBIVE1MRWxlbWVudCB8IG51bGwge1xuICAgICAgICByZXR1cm4gdmlldygpPy5jb250YWluZXJFbC5xdWVyeVNlbGVjdG9yPEhUTUxFbGVtZW50PignOnNjb3BlIC5tYXJrZG93bi1wcmV2aWV3LXZpZXcnKSA/PyBudWxsO1xuICAgICAgfVxuICAgICAgZnVuY3Rpb24gYnV0dG9ucygpOiBIVE1MQnV0dG9uRWxlbWVudFtdIHtcbiAgICAgICAgcmV0dXJuIFsuLi52aWV3KCk/LmNvbnRhaW5lckVsLnF1ZXJ5U2VsZWN0b3JBbGw8SFRNTEJ1dHRvbkVsZW1lbnQ+KCc6c2NvcGUgLmJsb2NrLWxhbmd1YWdlLWNvZGUtYnV0dG9uIGJ1dHRvbi5tb2QtY3RhJykgPz8gW11dO1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBmaW5kQnV0dG9uKCk6IEhUTUxCdXR0b25FbGVtZW50IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIGJ1dHRvbnMoKS5maW5kKChjYW5kaWRhdGUpID0+IGNhbmRpZGF0ZS50ZXh0Q29udGVudCA9PT0gY2FwdGlvbik7XG4gICAgICB9XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHdhaXRVbnRpbCh7XG4gICAgICAgICAgaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcyxcbiAgICAgICAgICBtZXNzYWdlOiBgY29kZSBidXR0b24gXCIke2NhcHRpb259XCIgbmV2ZXIgcmVuZGVyZWRgLFxuICAgICAgICAgIHByZWRpY2F0ZTogKCk6IGJvb2xlYW4gPT4ge1xuICAgICAgICAgICAgY29uc3Qgc2Nyb2xsZXIgPSBwcmV2aWV3RWwoKTtcbiAgICAgICAgICAgIGlmIChzY3JvbGxlcikge1xuICAgICAgICAgICAgICBzY3JvbGxlci5zY3JvbGxUb3AgPSBzY3JvbGxlci5zY3JvbGxIZWlnaHQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZmluZEJ1dHRvbigpICE9PSB1bmRlZmluZWQ7XG4gICAgICAgICAgfSxcbiAgICAgICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IHNldHRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kc1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4geyBjYXB0aW9uLCBvdXRwdXQ6ICcnLCBzdGF0dXM6ICd0aW1lb3V0JyB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBidXR0b24gPSBmaW5kQnV0dG9uKCk7XG4gICAgICBpZiAoIWJ1dHRvbikge1xuICAgICAgICByZXR1cm4geyBjYXB0aW9uLCBvdXRwdXQ6ICcnLCBzdGF0dXM6ICd0aW1lb3V0JyB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBibG9jayA9IGJ1dHRvbi5jbG9zZXN0PEhUTUxFbGVtZW50PignLmJsb2NrLWxhbmd1YWdlLWNvZGUtYnV0dG9uJykgPz8gYnV0dG9uLnBhcmVudEVsZW1lbnQ7XG4gICAgICBidXR0b24uc2Nyb2xsSW50b1ZpZXcoKTtcbiAgICAgIGJ1dHRvbi5jbGljaygpO1xuXG4gICAgICBsZXQgc3RhdHVzOiBEZW1vVmF1bHRCdXR0b25SZXN1bHRbJ3N0YXR1cyddO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgd2FpdFVudGlsKHtcbiAgICAgICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzLFxuICAgICAgICAgIG1lc3NhZ2U6IGBidXR0b24gXCIke2NhcHRpb259XCIgbmV2ZXIgcmVwb3J0ZWQgYSByZXN1bHRgLFxuICAgICAgICAgIHByZWRpY2F0ZTogKCk6IGJvb2xlYW4gPT4gL0V4ZWN1dGVkICg/OnN1Y2Nlc3NmdWxseXx3aXRoIGVycm9yKS8udGVzdChibG9jaz8udGV4dENvbnRlbnQgPz8gJycpLFxuICAgICAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogYnV0dG9uUmVzdWx0VGltZW91dEluTWlsbGlzZWNvbmRzXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCB0ZXh0ID0gYmxvY2s/LnRleHRDb250ZW50ID8/ICcnO1xuICAgICAgICBpZiAodGV4dC5pbmNsdWRlcygnRXhlY3V0ZWQgd2l0aCBlcnJvcicpKSB7XG4gICAgICAgICAgc3RhdHVzID0gJ2Vycm9yJztcbiAgICAgICAgfSBlbHNlIGlmICh0ZXh0LmluY2x1ZGVzKCdFeGVjdXRlZCBzdWNjZXNzZnVsbHknKSkge1xuICAgICAgICAgIHN0YXR1cyA9ICdvayc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3RhdHVzID0gJ3Vua25vd24nO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgc3RhdHVzID0gJ3RpbWVvdXQnO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4geyBjYXB0aW9uLCBvdXRwdXQ6IChibG9jaz8udGV4dENvbnRlbnQgPz8gJycpLnNsaWNlKDAsIG91dHB1dEV4Y2VycHRMZW5ndGgpLCBzdGF0dXMgfTtcbiAgICB9LFxuICAgIGlucHV0OiB7XG4gICAgICBidXR0b25SZXN1bHRUaW1lb3V0SW5NaWxsaXNlY29uZHM6IHRpbWVvdXRzLmJ1dHRvblJlc3VsdFRpbWVvdXRJbk1pbGxpc2Vjb25kcyxcbiAgICAgIGNhcHRpb246IGJ1dHRvbkNhcHRpb24sXG4gICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzOiBQT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyxcbiAgICAgIG5vdGVQYXRoLFxuICAgICAgb3V0cHV0RXhjZXJwdExlbmd0aDogT1VUUFVUX0VYQ0VSUFRfTEVOR1RILFxuICAgICAgc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzOiB0aW1lb3V0cy5zZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHNcbiAgICB9LFxuICAgIHZhdWx0UGF0aDogZ2V0VGVtcG9yYXJ5VmF1bHQoKS5wYXRoXG4gIH0pO1xufVxuXG4vKipcbiAqIE9wZW5zIGEgbm90ZSBpbiByZWFkaW5nIHZpZXcgYW5kIGxpc3RzIHRoZSBjYXB0aW9ucyBvZiB0aGUgYnV0dG9ucyB0aGF0IG1vdW50ZWQsIGRlZHVwbGljYXRlZCBhbmQgaW5cbiAqIGRvY3VtZW50IG9yZGVyLlxuICpcbiAqIFR3byBxdWlya3Mgb2YgcmVhZGluZyB2aWV3IHNoYXBlIHRoaXMuIEl0IHJlbmRlcnMgbGF6aWx5IGFuZCB1bm1vdW50cyBzZWN0aW9ucyBmYXIgb2ZmLXNjcmVlbiwgc28gdGhlXG4gKiBwcmV2aWV3IGlzIHNjcm9sbGVkIHRvIHRoZSBib3R0b20gd2hpbGUgd2FpdGluZyBvciBhIG5vdGUncyBsYXN0IGJ1dHRvbnMgbmV2ZXIgbW91bnQgYXQgYWxsLiBBbmRcbiAqIHdoaWxlIGl0IHNldHRsZXMgaXQgY2FuIGhvbGQgU0VWRVJBTCBlbGVtZW50cyBwZXIgZmVuY2UgXHUyMDE0IHRoZSBzYW1lIGJ1dHRvbiB3YXMgb2JzZXJ2ZWQgcmVuZGVyZWQgdHdpY2VcbiAqIFx1MjAxNCBzbyB0aGUgY2FwdGlvbnMgYXJlIGRlZHVwbGljYXRlZDsgY2xpY2tpbmcgYnkgY2FwdGlvbiB0aGVuIGFkZHJlc3NlcyBlYWNoIGJ1dHRvbiBvbmNlIGhvd2V2ZXIgbWFueVxuICogY29waWVzIG9mIGl0IHRoZSBET00gaXMgaG9sZGluZy5cbiAqXG4gKiBAcGFyYW0gbm90ZSAtIFRoZSBub3RlIHRvIG9wZW4uXG4gKiBAcGFyYW0gc2V0dGxlVGltZW91dEluTWlsbGlzZWNvbmRzIC0gSG93IGxvbmcgdG8gd2FpdCBmb3IgdGhlIGJ1dHRvbnMgdG8gbW91bnQuXG4gKiBAcmV0dXJucyBUaGUgZGlzdGluY3QgYnV0dG9uIGNhcHRpb25zLlxuICovXG5hc3luYyBmdW5jdGlvbiBvcGVuTm90ZUFuZExpc3RCdXR0b25DYXB0aW9ucyhub3RlOiBEZW1vVmF1bHROb3RlLCBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgcmV0dXJuIGV2YWxJbk9ic2lkaWFuKHtcbiAgICBhc3luYyBjYWxsYmFjayh7IGFwcCwgZXhwZWN0ZWRCdXR0b25Db3VudCwgaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcywgbGliOiB7IHdhaXRVbnRpbCB9LCBub3RlUGF0aCwgb2JzaWRpYW5Nb2R1bGUsIHRpbWVvdXRJbk1pbGxpc2Vjb25kcyB9KTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgICAgZnVuY3Rpb24gdmlldygpOiBJbnN0YW5jZVR5cGU8dHlwZW9mIG9ic2lkaWFuTW9kdWxlLk1hcmtkb3duVmlldz4gfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIGFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlVmlld09mVHlwZShvYnNpZGlhbk1vZHVsZS5NYXJrZG93blZpZXcpO1xuICAgICAgfVxuICAgICAgZnVuY3Rpb24gcHJldmlld0VsKCk6IEhUTUxFbGVtZW50IHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB2aWV3KCk/LmNvbnRhaW5lckVsLnF1ZXJ5U2VsZWN0b3I8SFRNTEVsZW1lbnQ+KCc6c2NvcGUgLm1hcmtkb3duLXByZXZpZXctdmlldycpID8/IG51bGw7XG4gICAgICB9XG4gICAgICBmdW5jdGlvbiBjYXB0aW9ucygpOiBzdHJpbmdbXSB7XG4gICAgICAgIGNvbnN0IHJlbmRlcmVkID0gWy4uLnZpZXcoKT8uY29udGFpbmVyRWwucXVlcnlTZWxlY3RvckFsbDxIVE1MQnV0dG9uRWxlbWVudD4oJzpzY29wZSAuYmxvY2stbGFuZ3VhZ2UtY29kZS1idXR0b24gYnV0dG9uLm1vZC1jdGEnKSA/PyBbXV1cbiAgICAgICAgICAubWFwKChidXR0b24pID0+IGJ1dHRvbi50ZXh0Q29udGVudClcbiAgICAgICAgICAuZmlsdGVyKChjYXB0aW9uKSA9PiBjYXB0aW9uICE9PSAnJyk7XG4gICAgICAgIHJldHVybiBbLi4ubmV3IFNldChyZW5kZXJlZCldO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBhcHAud29ya3NwYWNlLm9wZW5MaW5rVGV4dChub3RlUGF0aC5yZXBsYWNlKC9cXC5tZCQvLCAnJyksICcnLCBmYWxzZSk7XG4gICAgICBhd2FpdCBhcHAud29ya3NwYWNlLmdldExlYWYoZmFsc2UpLnNldFZpZXdTdGF0ZSh7IHN0YXRlOiB7IGZpbGU6IG5vdGVQYXRoLCBtb2RlOiAncHJldmlldycgfSwgdHlwZTogJ21hcmtkb3duJyB9KTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgd2FpdFVudGlsKHtcbiAgICAgICAgICBpbnRlcnZhbEluTWlsbGlzZWNvbmRzLFxuICAgICAgICAgIG1lc3NhZ2U6IGBcIiR7bm90ZVBhdGh9XCIgbmV2ZXIgbW91bnRlZCBhbGwgJHtTdHJpbmcoZXhwZWN0ZWRCdXR0b25Db3VudCl9IG9mIGl0cyBidXR0b25zYCxcbiAgICAgICAgICBwcmVkaWNhdGU6ICgpOiBib29sZWFuID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHNjcm9sbGVyID0gcHJldmlld0VsKCk7XG4gICAgICAgICAgICBpZiAoc2Nyb2xsZXIpIHtcbiAgICAgICAgICAgICAgc2Nyb2xsZXIuc2Nyb2xsVG9wID0gc2Nyb2xsZXIuc2Nyb2xsSGVpZ2h0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGNhcHRpb25zKCkubGVuZ3RoID49IGV4cGVjdGVkQnV0dG9uQ291bnQ7XG4gICAgICAgICAgfSxcbiAgICAgICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHNcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gVGhlIGNhcHRpb25zIGFyZSByZXR1cm5lZCBlaXRoZXIgd2F5OyB0aGUgY2FsbGVyIGFzc2VydHMgb24gdGhlbSBhbmQgcmVwb3J0cyB0aGUgc2hvcnRmYWxsLlxuICAgICAgfVxuXG4gICAgICByZXR1cm4gY2FwdGlvbnMoKTtcbiAgICB9LFxuICAgIGlucHV0OiB7XG4gICAgICBleHBlY3RlZEJ1dHRvbkNvdW50OiBub3RlLmJ1dHRvbkNvdW50LFxuICAgICAgaW50ZXJ2YWxJbk1pbGxpc2Vjb25kczogUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMsXG4gICAgICBub3RlUGF0aDogbm90ZS5uYW1lLFxuICAgICAgdGltZW91dEluTWlsbGlzZWNvbmRzOiBzZXR0bGVUaW1lb3V0SW5NaWxsaXNlY29uZHNcbiAgICB9LFxuICAgIHZhdWx0UGF0aDogZ2V0VGVtcG9yYXJ5VmF1bHQoKS5wYXRoXG4gIH0pO1xufVxuXG4vKiB2OCBpZ25vcmUgc3RvcCAqL1xuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBaUJBLHFCQUdPO0FBQ1AsdUJBQXFCO0FBQ3JCLDBCQUFvQjtBQUNwQiwwQ0FBK0I7QUFDL0Isd0NBQWtDO0FBQ2xDLG9CQUtPO0FBRVAsa0JBQThCO0FBTXZCLE1BQU0sZ0NBQWdDO0FBcUY3QyxNQUFNLGdEQUFnRDtBQUN0RCxNQUFNLHlDQUF5QztBQUMvQyxNQUFNLGdDQUFnQztBQUN0QyxNQUFNLHdCQUF3QjtBQUk5QixNQUFNLHlCQUF5QixDQUFDLFdBQVc7QUFFM0MsTUFBTSw0QkFBNEI7QUFnQjNCLFNBQVMsZUFBZSxVQUFrQixVQUFvRDtBQUNuRyxNQUFJLFNBQVMsV0FBVyxHQUFHO0FBQ3pCLFdBQU87QUFBQSxFQUNUO0FBRUEsUUFBTSxVQUFVLFNBQ2IsSUFBSSxDQUFDLFlBQVksUUFBUSxRQUFRLE9BQU8sTUFBTSxRQUFRLE1BQU0sTUFBTSxRQUFRLE9BQU8sV0FBVyxRQUFRLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUNqSCxLQUFLLElBQUk7QUFDWixTQUFPLEdBQUcsT0FBTyxTQUFTLE1BQU0sQ0FBQyxpQkFBaUIsUUFBUTtBQUFBLEVBQTBCLE9BQU87QUFDN0Y7QUFXTyxTQUFTLHFCQUFxQixlQUF1QixlQUFxRDtBQUMvRyxhQUFPLDRCQUFZLGVBQWUsRUFBRSxlQUFlLEtBQUssQ0FB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
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/// <reference path="../library.d.cts" />
|
|
2
|
+
/**
|
|
3
|
+
* @file
|
|
4
|
+
*
|
|
5
|
+
* A vitest suite that opens every note of a plugin's in-repo `demo-vault/`, clicks each `code-button`
|
|
6
|
+
* in it against a real Obsidian, and fails on any button that errors or never reports a result.
|
|
7
|
+
*
|
|
8
|
+
* A demo vault's buttons are the one part of it no other gate can check. `lint:md` reads the markdown,
|
|
9
|
+
* the coverage suite ({@link ./demo-vault-coverage.ts | `registerDemoVaultCoverageSuite`}) checks the
|
|
10
|
+
* authoring conventions, and neither executes anything — a button whose `require('/demoSetup.ts')` path
|
|
11
|
+
* is wrong, or that calls an API that has since changed shape, fails at click time and nowhere else.
|
|
12
|
+
*
|
|
13
|
+
* The companion half — seeding the temp vault with the demo-vault tree, its `.obsidian` config, and the
|
|
14
|
+
* CodeScript Toolkit binary that turns ```` ```code-button ```` fences into buttons — is
|
|
15
|
+
* `buildDemoVaultPopulate` in `obsidian-integration-testing`; hand its result to the project's
|
|
16
|
+
* `globalSetup` and name CodeScript Toolkit in `enableCommunityPlugins`.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* CodeScript Toolkit's manifest id. It is still the plugin's original `fix-require-modules` id, which
|
|
20
|
+
* no longer matches its name — the id is published, so it cannot be changed.
|
|
21
|
+
*/
|
|
22
|
+
export declare const CODE_SCRIPT_TOOLKIT_PLUGIN_ID = "fix-require-modules";
|
|
23
|
+
/**
|
|
24
|
+
* The outcome of clicking one button.
|
|
25
|
+
*/
|
|
26
|
+
export interface DemoVaultButtonResult {
|
|
27
|
+
/**
|
|
28
|
+
* The button's caption, as rendered.
|
|
29
|
+
*/
|
|
30
|
+
readonly caption: string;
|
|
31
|
+
/**
|
|
32
|
+
* The result line CodeScript Toolkit printed under the button, truncated.
|
|
33
|
+
*/
|
|
34
|
+
readonly output: string;
|
|
35
|
+
/**
|
|
36
|
+
* Whether the button reported success, reported an error, or never reported at all.
|
|
37
|
+
*/
|
|
38
|
+
readonly status: 'error' | 'ok' | 'timeout' | 'unknown';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* One demo-vault note and how many buttons its source declares.
|
|
42
|
+
*/
|
|
43
|
+
export interface DemoVaultNote {
|
|
44
|
+
/**
|
|
45
|
+
* How many `code-button` fences the note's source declares.
|
|
46
|
+
*/
|
|
47
|
+
readonly buttonCount: number;
|
|
48
|
+
/**
|
|
49
|
+
* The note's file name, relative to the demo vault root.
|
|
50
|
+
*/
|
|
51
|
+
readonly name: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The options for {@link registerDemoVaultButtonSuite}.
|
|
55
|
+
*/
|
|
56
|
+
export interface RegisterDemoVaultButtonSuiteOptions {
|
|
57
|
+
/**
|
|
58
|
+
* How long, in milliseconds, to wait for a clicked button to report a result.
|
|
59
|
+
*
|
|
60
|
+
* @default `15000`
|
|
61
|
+
*/
|
|
62
|
+
readonly buttonResultTimeoutInMilliseconds?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Note file names (relative to the demo vault root) to skip.
|
|
65
|
+
*
|
|
66
|
+
* @default `['README.md']`
|
|
67
|
+
*/
|
|
68
|
+
readonly excludedNotes?: readonly string[];
|
|
69
|
+
/**
|
|
70
|
+
* The repository root holding `demo-vault/`.
|
|
71
|
+
*
|
|
72
|
+
* @default the resolved repo root, falling back to `process.cwd()`.
|
|
73
|
+
*/
|
|
74
|
+
readonly rootFolder?: string;
|
|
75
|
+
/**
|
|
76
|
+
* How long, in milliseconds, to wait for a note's preview and its buttons to mount.
|
|
77
|
+
*
|
|
78
|
+
* @default `20000`
|
|
79
|
+
*/
|
|
80
|
+
readonly settleTimeoutInMilliseconds?: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Builds the assertion message for a note's failing buttons.
|
|
84
|
+
*
|
|
85
|
+
* The captured output is included because a button's failure is a runtime one — the stack CodeScript
|
|
86
|
+
* Toolkit prints under it is the only diagnosis there is.
|
|
87
|
+
*
|
|
88
|
+
* @param noteName - The note the buttons belong to.
|
|
89
|
+
* @param failures - The failing buttons.
|
|
90
|
+
* @returns The message.
|
|
91
|
+
*/
|
|
92
|
+
export declare function formatFailures(noteName: string, failures: readonly DemoVaultButtonResult[]): string;
|
|
93
|
+
/**
|
|
94
|
+
* Lists the demo vault's top-level notes that declare at least one `code-button`.
|
|
95
|
+
*
|
|
96
|
+
* Only the vault root is walked: `Materials/` holds fixtures the walkthroughs act on, not walkthroughs.
|
|
97
|
+
*
|
|
98
|
+
* @param demoVaultPath - The demo vault root.
|
|
99
|
+
* @param excludedNotes - Note file names to skip.
|
|
100
|
+
* @returns The notes, sorted by name.
|
|
101
|
+
*/
|
|
102
|
+
export declare function listNotesWithButtons(demoVaultPath: string, excludedNotes: ReadonlySet<string>): DemoVaultNote[];
|
|
103
|
+
/**
|
|
104
|
+
* Registers a vitest suite that clicks every `code-button` in the repo's demo vault.
|
|
105
|
+
*
|
|
106
|
+
* One `it` per note, and one `evalInObsidian` per button: a single closure runs as one CDP
|
|
107
|
+
* `Runtime.evaluate`, which the harness caps at 30 s, so a note with a dozen buttons would otherwise
|
|
108
|
+
* time out as a whole rather than reporting which button failed.
|
|
109
|
+
*
|
|
110
|
+
* @param options - The {@link RegisterDemoVaultButtonSuiteOptions}.
|
|
111
|
+
*/
|
|
112
|
+
export declare function registerDemoVaultButtonSuite(options?: RegisterDemoVaultButtonSuiteOptions): void;
|