├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── icon.png
├── image
├── demo.gif
├── linked.png
├── marketplace.png
└── screenshot.png
├── package.json
├── public
├── highlightLinked.ts
├── index.html
└── index.ts
├── tsconfig.json
├── wmr.config.mjs
└── yarn.lock
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Release
4 |
5 | env:
6 | PLUGIN_NAME: logseq-plugin-link-unlinked
7 |
8 | # Controls when the workflow will run
9 | on:
10 | push:
11 | tags:
12 | - "*" # Push events to matching any tag format, i.e. 1.0, 20.15.10
13 |
14 | # Allows you to run this workflow manually from the Actions tab
15 | workflow_dispatch:
16 |
17 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
18 | jobs:
19 | release:
20 | # The type of runner that the job will run on
21 | runs-on: ubuntu-latest
22 |
23 | # Steps represent a sequence of tasks that will be executed as part of the job
24 | steps:
25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
26 | - uses: actions/checkout@v2
27 | - uses: actions/setup-node@v2
28 | with:
29 | node-version: "14.x"
30 |
31 | - name: Build
32 | id: build
33 | run: |
34 | yarn
35 | yarn build
36 | mkdir ${{ env.PLUGIN_NAME }}
37 | cp README.md package.json icon.png ${{ env.PLUGIN_NAME }}
38 | mv dist ${{ env.PLUGIN_NAME }}
39 | zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }}
40 | ls
41 | echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)"
42 |
43 | - name: Create Release
44 | id: create_release
45 | uses: actions/create-release@v1
46 | env:
47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48 | VERSION: ${{ github.ref }}
49 | with:
50 | tag_name: ${{ github.ref }}
51 | release_name: ${{ github.ref }}
52 | draft: false
53 | prerelease: false
54 |
55 | - name: Upload zip file
56 | id: upload_zip
57 | uses: actions/upload-release-asset@v1
58 | env:
59 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60 | with:
61 | upload_url: ${{ steps.create_release.outputs.upload_url }}
62 | asset_path: ./${{ env.PLUGIN_NAME }}.zip
63 | asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip
64 | asset_content_type: application/zip
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .cache
2 | node_modules
3 | dist
4 | stats.html
5 | yarn-error.log
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "always",
3 | "endOfLine": "lf",
4 | "semi": false,
5 | "singleQuote": false,
6 | "trailingComma": "all"
7 | }
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Seth Yuan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Link Unlinked References
2 |
3 | A plugin for logseq to highlight the keyword in unlinked reference, and provide a button to automatically link them.
4 |
5 | For the 'link-all' button, you may need to click it several times to complete the "real" link-all action, as it only simulates this by clicking all visible link buttons.
6 |
7 | You can also highlight the refs and tags in linked references (**need to enable manually in the settings**).
8 |
9 | #### Screenshot
10 | 
11 |
12 | Enable highlight in linked references.
13 |
14 |
15 |
16 | #### Demo
17 | 
18 |
19 | #### Marketplace
20 |
21 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usoonees/logseq-plugin-link-unlink/205a6464ae3f38dea5d3595d6bce276fea9bb093/icon.png
--------------------------------------------------------------------------------
/image/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usoonees/logseq-plugin-link-unlink/205a6464ae3f38dea5d3595d6bce276fea9bb093/image/demo.gif
--------------------------------------------------------------------------------
/image/linked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usoonees/logseq-plugin-link-unlink/205a6464ae3f38dea5d3595d6bce276fea9bb093/image/linked.png
--------------------------------------------------------------------------------
/image/marketplace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usoonees/logseq-plugin-link-unlink/205a6464ae3f38dea5d3595d6bce276fea9bb093/image/marketplace.png
--------------------------------------------------------------------------------
/image/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usoonees/logseq-plugin-link-unlink/205a6464ae3f38dea5d3595d6bce276fea9bb093/image/screenshot.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "logseq-plugin-link-unlinked",
3 | "version": "1.5.1",
4 | "main": "dist/index.html",
5 | "logseq": {
6 | "title": "Link Unlinked References",
7 | "id": "_usoon-logseq-link-unlinked",
8 | "icon": "./icon.png"
9 | },
10 | "scripts": {
11 | "start": "wmr",
12 | "build": "wmr build",
13 | "serve": "wmr serve"
14 | },
15 | "dependencies": {
16 | "@logseq/libs": "^0.0.10"
17 | },
18 | "devDependencies": {
19 | "wmr": "^3.7.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/public/highlightLinked.ts:
--------------------------------------------------------------------------------
1 | const selectRef = (name) => `.page-linked .page-ref[data-ref^="${name}"]`
2 | const selectDarkRef = (name) =>
3 | `.dark .page-linked .page-ref[data-ref^="${name}"]`
4 |
5 | function unHighlightRef(preNames) {
6 | const unsetSelector = preNames.map(selectRef).join(",")
7 | const unsetDarkSelector = preNames.map(selectDarkRef).join(",")
8 | logseq.provideStyle(`
9 | ${unsetSelector} {
10 | background-color: unset;
11 | }
12 |
13 | ${unsetDarkSelector} {
14 | background-color: unset;
15 | }
16 | `)
17 | }
18 |
19 | function highlightLinkRef(preNames, curNames) {
20 | unHighlightRef(preNames)
21 | const setSelector = curNames.map(selectRef).join(",")
22 | const setDarkSelector = curNames.map(selectDarkRef).join(",")
23 | logseq.provideStyle(`
24 | ${setSelector} {
25 | background-color: ${logseq.settings.highlightColor};
26 | }
27 |
28 | ${setDarkSelector} {
29 | background-color: ${logseq.settings.highlightColorDarkMode};
30 | }
31 | `)
32 | }
33 |
34 | const selectTag = (name) => `.page-linked a.tag[data-ref^="${name}"]`
35 | const selectDarkTag = (name) => `.dark .page-linked a.tag[data-ref^="${name}"]`
36 |
37 | // TODO: set tag color and background to previous
38 | function unHighlightTag(preNames) {
39 | const unsetTagSelector = preNames.map(selectTag).join(",")
40 | const unsetTagDarkSelector = preNames.map(selectDarkTag).join(",")
41 | logseq.provideStyle(`
42 | ${unsetTagSelector} {
43 | background-color: unset;
44 | color: unset;
45 | }
46 |
47 | ${unsetTagDarkSelector} {
48 | background-color: unset;
49 | color: unset;
50 | }`)
51 | }
52 |
53 | function highlighTagRef(preNames, curNames) {
54 | unHighlightTag(preNames)
55 | const setTagSelector = curNames.map(selectTag).join(",")
56 | const setTagDarkSelector = curNames.map(selectDarkTag).join(",")
57 | logseq.provideStyle(`
58 | ${setTagSelector} {
59 | background-color: yellow;
60 | color: #484576;
61 | }
62 |
63 | ${setTagDarkSelector} {
64 | background-color: #ffff0030;
65 | color: #ebdddd;
66 | }
67 | `)
68 | }
69 |
70 | export {highlighTagRef, unHighlightTag, highlightLinkRef, unHighlightRef}
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | logseq-plugin-paste-more
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/public/index.ts:
--------------------------------------------------------------------------------
1 | import "@logseq/libs"
2 | import {highlighTagRef, unHighlightTag, highlightLinkRef, unHighlightRef} from './highlightLinked'
3 |
4 | const doc = parent.document
5 | const highlightClass = "unlink-highlight"
6 |
7 | async function getPageNames() {
8 | const page = await logseq.Editor.getCurrentPage()
9 | if(!page){
10 | return
11 | }
12 | let pageNames = [page.name]
13 | if (page.alias) {
14 | for(const alias of page.alias){
15 | const aliasPage = await logseq.Editor.getPage(alias.id)
16 | pageNames.push(aliasPage.name)
17 | }
18 | }
19 |
20 | // return lowercase page names, and sort by page length
21 | return pageNames.sort((a, b) => b.length - a.length).map((name) => name.toLowerCase())
22 | }
23 |
24 | let prePageNames = []
25 | async function highlightLinked() {
26 | const curPageNames = await getPageNames()
27 | if(!curPageNames){
28 | return
29 | }
30 | // references
31 | if (logseq.settings.highlightLinkedRefs) {
32 | highlightLinkRef(prePageNames, curPageNames)
33 | } else {
34 | unHighlightRef(prePageNames)
35 | }
36 |
37 | // tags
38 | // if (logseq.settings.highlightLinkedTags) {
39 | // highlighTagRef(prePageNames, curPageNames)
40 | // } else {
41 | // unHighlightTag(prePageNames)
42 | // }
43 |
44 | prePageNames = curPageNames
45 | }
46 |
47 |
48 | logseq.useSettingsSchema([
49 | {
50 | key: "highlightColor",
51 | title: "Highlight Color",
52 | type: "string",
53 | default: "yellow", // default to false
54 | description: "",
55 | },
56 | {
57 | key: "highlightColorDarkMode",
58 | title: "Highlight Color in Dark Mode",
59 | type: "string",
60 | default: "#ffff0030",
61 | description: "",
62 | },
63 | {
64 | key: "highlightLinkedRefs",
65 | title: "Whether to highlight references in linked references",
66 | type: "boolean",
67 | default: false, // default to false
68 | description: "",
69 | },
70 | // {
71 | // key: "highlightLinkedTags",
72 | // title: "Whether to highlight tag in linked references",
73 | // type: "boolean",
74 | // default: false, // default to false
75 | // description: "",
76 | // },
77 | ])
78 |
79 | function provideStyle() {
80 | logseq.provideStyle(`
81 | button.link-button, button.link-all-button {
82 | float: right;
83 | padding-left: 5px;
84 | padding-right: 5px;
85 | border: 1px solid var(--ls-border-color);
86 | border-radius: 4px;
87 | opacity: 0.6;
88 | transition: .3s;
89 | }
90 | button.link-button:hover, button.link-all-button:hover {
91 | opacity: 1;
92 | }
93 | button.link-button::before, button.link-all-button::before {
94 | content: "\\eade";
95 | width: 16px;
96 | height: 16px;
97 | margin-right: 4px;
98 | display: inline-block;
99 | line-height: 1em;
100 | font-family: tabler-icons;
101 | }
102 | button.link-all-button {
103 | margin-left: auto;
104 | }
105 | span.${highlightClass} {
106 | background-color: ${logseq.settings.highlightColor};
107 | }
108 | .dark span.${highlightClass} {
109 | background-color: ${logseq.settings.highlightColorDarkMode};
110 | }
111 | `)
112 | }
113 |
114 | async function main() {
115 | provideStyle()
116 |
117 | logseq.onSettingsChanged(async () => {
118 | provideStyle()
119 | await highlightLinked()
120 | })
121 |
122 | logseq.App.onRouteChanged(() => {
123 | setTimeout(async () => {
124 | if(logseq.settings.highlightLinkedRefs){
125 | await highlightLinked()
126 | }
127 | }, 100)
128 | })
129 |
130 |
131 | let unlinkObserver, unlinkedRefsContainer
132 |
133 | const unlinkCallback = function (mutationsList, observer) {
134 | for (let i = 0; i < mutationsList.length; i++) {
135 | const addedNode = mutationsList[i].addedNodes[0]
136 | if (addedNode && addedNode.childNodes.length) {
137 | const blocks = addedNode.querySelectorAll(".block-content")
138 | if (blocks.length) {
139 | unlinkObserver.disconnect()
140 | for (let i = 0; i < blocks.length; i++) {
141 | addHighlight(blocks[i])
142 | }
143 | unlinkObserver.observe(unlinkedRefsContainer, obConfig)
144 | }
145 | }
146 | }
147 | }
148 |
149 | const obConfig = {
150 | childList: true,
151 | subtree: true,
152 | }
153 | unlinkObserver = new MutationObserver(unlinkCallback)
154 |
155 | function addObserverIfDesiredNodeAvailable() {
156 | unlinkedRefsContainer = doc.querySelector(".page-unlinked.references")
157 | if (!unlinkedRefsContainer) {
158 | setTimeout(addObserverIfDesiredNodeAvailable, 200)
159 | return
160 | }
161 | unlinkObserver.observe(unlinkedRefsContainer, obConfig)
162 | }
163 | addObserverIfDesiredNodeAvailable()
164 |
165 | logseq.App.onRouteChanged(() => {
166 | setTimeout(() => {
167 | addObserverIfDesiredNodeAvailable()
168 | }, 50) // wait for page load, otherwise would observer the previous page
169 | })
170 |
171 | logseq.beforeunload(async () => {
172 | unlinkObserver.disconnect()
173 | })
174 | }
175 |
176 |
177 | function addLinkAllButton() {
178 | let linkAllButton = doc.querySelector(".link-all-button");
179 | if (linkAllButton) {
180 | linkAllButton.style.display = "inline-block"
181 | return
182 | }
183 | // linkAllButton.addEventListener("click", linkAll);
184 | let unLinkTitle = doc.querySelector(".references.page-unlinked > .content > .flex > .content")
185 | let extended = unLinkTitle.nextElementSibling
186 |
187 | linkAllButton = doc.createElement("button");
188 | linkAllButton.setAttribute("class", "link-all-button");
189 | linkAllButton.innerHTML = "Link All";
190 | if(extended.className == "hidden"){
191 | linkAllButton.style.display = "none"
192 | }
193 | linkAllButton.addEventListener("click", (e) => {
194 | e.stopImmediatePropagation();
195 | const allUnlinkedButtons = doc.querySelectorAll(".link-button");
196 | allUnlinkedButtons.forEach((button) => {
197 | button.click();
198 | });
199 | });
200 | // 🌟 Create a span element
201 | let wrapperSpan = doc.createElement("span");
202 |
203 | // 🌟 Append the button to the span
204 | wrapperSpan.appendChild(linkAllButton);
205 |
206 | if (unLinkTitle) {
207 | unLinkTitle.insertBefore(wrapperSpan, unLinkTitle.firstChild);
208 | unLinkTitle.addEventListener("click", (e) => {
209 | setTimeout(() => {
210 | if(extended.className == "hidden"){
211 | linkAllButton.style.display = "none"
212 | return
213 | }
214 | if(!doc.querySelector(".link-button")) {
215 | console.log("no link button")
216 | return
217 | }
218 |
219 | linkAllButton.style.display = "inline-block"
220 | }, 100);
221 |
222 | });
223 | }
224 | }
225 |
226 | const contentSelector = ".inline, .is-paragraph, h1, h2, h3, h4, h5, h6"
227 | function addButton(blockEl, pageNames) {
228 | addLinkAllButton()
229 | let linkButton = blockEl.querySelector(".link-button")
230 | if (linkButton) {
231 | return
232 | }
233 | const blockID = blockEl.getAttribute("blockid")
234 | linkButton = doc.createElement("button")
235 | linkButton.setAttribute("class", "link-button")
236 | linkButton.innerHTML = "link"
237 | linkButton.addEventListener("click", async (e) => {
238 | const block = await logseq.Editor.getBlock(blockID)
239 | const content = block.content
240 | const reStr = "(" + pageNames.join("|") + ")"
241 | const re = new RegExp(reStr, "ig")
242 |
243 | /*
244 | page = cu
245 | 'cu #focus #f/ocus #cu cus focus [[cu]] [[focus]]'
246 | '[[cu]] #focus #f/ocus #cu [[cu]]s fo[[cu]]s [[cu]] [[focus]]'
247 | */
248 | const newContent = content.replace(re, (match, _, i) => {
249 | while (i >= 0) {
250 | if (/\s/.test(content[i]) || content[i] === "]") {
251 | break
252 | } else if (content[i] == "[" || content[i] == "#") {
253 | return match
254 | }
255 | i -= 1
256 | }
257 |
258 | return `[[${match}]]`
259 | })
260 | console.log("unlinked content: ", content, pageNames)
261 | console.log("linked content: ", newContent)
262 |
263 | // sometimes header and paragraph would cause block render error
264 | // so we need to step into edit mode first, and exit after 100ms
265 | await logseq.Editor.editBlock(blockID)
266 | await logseq.Editor.updateBlock(blockID, newContent)
267 |
268 | setTimeout(() => {
269 | logseq.Editor.exitEditingMode()
270 | }, 100);
271 |
272 | let highlights = blockEl.querySelectorAll(`.${highlightClass}`)
273 | for (let i = 0; i < highlights.length; i++) {
274 | // highlights[i].style.display = 'none'
275 | highlights[i].remove()
276 | }
277 | linkButton.style.display = "none"
278 | })
279 |
280 | blockEl.querySelector(contentSelector).appendChild(linkButton)
281 | }
282 |
283 | async function addHighlight(blockEl) {
284 | const contentElements = blockEl.querySelectorAll(contentSelector)
285 | const pageNames = await getPageNames()
286 | const reStr = "(" + pageNames.join("|") + ")"
287 | const re = new RegExp(reStr, "ig")
288 |
289 | contentElements.forEach((content) => {
290 | let child = content.firstChild
291 | let pureText = [] // pure text in first level of inline
292 | let formatText = [] // bold, italic, mark text in second level of inline
293 |
294 | while (child) {
295 | if (child.nodeType == 3) {
296 | pureText.push(child)
297 | }
298 |
299 | if (["B", "I", "EM", "STRONG", "MARK", "DEL"].includes(child.tagName)) {
300 | formatText.push({
301 | parent: child,
302 | children: [],
303 | })
304 | }
305 |
306 | child = child.nextSibling
307 | }
308 |
309 | for (let i = 0; i < formatText.length; i++) {
310 | child = formatText[i]["parent"].firstChild
311 | while (child) {
312 | if (child.nodeType == 3) {
313 | formatText[i]["children"].push(child)
314 | }
315 | child = child.nextSibling
316 | }
317 | }
318 |
319 | function newHighlightNode(child) {
320 | const text = child.textContent
321 | if (re.test(text)) {
322 | // const isPureText = content.tagName == "SPAN"
323 | addButton(blockEl, pageNames)
324 | }
325 | let domText = text.replace(
326 | re,
327 | `$1`,
328 | )
329 | let newDom = document.createElement("span")
330 | newDom.innerHTML = domText
331 | return newDom
332 | }
333 |
334 | pureText.forEach((child) => {
335 | content.replaceChild(newHighlightNode(child), child)
336 | })
337 |
338 | formatText.forEach((boldNode) => {
339 | boldNode["children"].forEach((c) => {
340 | boldNode["parent"].replaceChild(newHighlightNode(c), c)
341 | })
342 | })
343 | })
344 | }
345 |
346 | logseq.ready(main).catch(console.error)
347 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "jsx": "preserve",
5 | "jsxFactory": "preact.h",
6 | "jsxFragmentFactory": "preact.Fragment",
7 | "allowJs": true,
8 | "checkJs": true,
9 | // "strict": true,
10 | "noEmit": true,
11 | "moduleResolution": "node",
12 | "target": "ESNext",
13 | "module": "esnext",
14 | "resolveJsonModule": true,
15 | "allowSyntheticDefaultImports": true,
16 | "downlevelIteration": true
17 | },
18 | "include": ["node_modules/wmr/types.d.ts", "**/*"],
19 | "typeAcquisition": {
20 | "enable": true
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/wmr.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "wmr"
2 |
3 | // Full list of options: https://wmr.dev/docs/configuration
4 | export default defineConfig({
5 | /* Your configuration here */
6 | alias: {
7 | react: "preact/compat",
8 | "react-dom": "preact/compat",
9 | },
10 | publicPath: "",
11 | })
12 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@logseq/libs@^0.0.10":
6 | version "0.0.10"
7 | resolved "https://registry.npmmirror.com/@logseq/libs/-/libs-0.0.10.tgz#305d65b733ed16d157f57a1a0759e0233d1b1a81"
8 | integrity sha512-Ah5wAhLcgrlOtk/9nEe11UsqOzvpcEaEWDV+oFD3TIGTeP4mfv2HjDiPYPBGXuMZRgvsW6klQLzzaxMieksXXg==
9 | dependencies:
10 | csstype "3.1.0"
11 | debug "4.3.4"
12 | dompurify "2.3.8"
13 | eventemitter3 "4.0.7"
14 | fast-deep-equal "3.1.3"
15 | lodash-es "4.17.21"
16 | path "0.12.7"
17 | snake-case "3.0.4"
18 |
19 | csstype@3.1.0:
20 | version "3.1.0"
21 | resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
22 | integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
23 |
24 | debug@4.3.4:
25 | version "4.3.4"
26 | resolved "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
27 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
28 | dependencies:
29 | ms "2.1.2"
30 |
31 | dompurify@2.3.8:
32 | version "2.3.8"
33 | resolved "https://registry.npmmirror.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f"
34 | integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw==
35 |
36 | dot-case@^3.0.4:
37 | version "3.0.4"
38 | resolved "https://registry.npmmirror.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
39 | integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
40 | dependencies:
41 | no-case "^3.0.4"
42 | tslib "^2.0.3"
43 |
44 | eventemitter3@4.0.7:
45 | version "4.0.7"
46 | resolved "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
47 | integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
48 |
49 | fast-deep-equal@3.1.3:
50 | version "3.1.3"
51 | resolved "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
52 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
53 |
54 | inherits@2.0.3:
55 | version "2.0.3"
56 | resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
57 | integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
58 |
59 | lodash-es@4.17.21:
60 | version "4.17.21"
61 | resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
62 | integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
63 |
64 | lower-case@^2.0.2:
65 | version "2.0.2"
66 | resolved "https://registry.npmmirror.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
67 | integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
68 | dependencies:
69 | tslib "^2.0.3"
70 |
71 | ms@2.1.2:
72 | version "2.1.2"
73 | resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
74 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
75 |
76 | no-case@^3.0.4:
77 | version "3.0.4"
78 | resolved "https://registry.npmmirror.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
79 | integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
80 | dependencies:
81 | lower-case "^2.0.2"
82 | tslib "^2.0.3"
83 |
84 | path@0.12.7:
85 | version "0.12.7"
86 | resolved "https://registry.npmmirror.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
87 | integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==
88 | dependencies:
89 | process "^0.11.1"
90 | util "^0.10.3"
91 |
92 | process@^0.11.1:
93 | version "0.11.10"
94 | resolved "https://registry.npmmirror.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
95 | integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
96 |
97 | snake-case@3.0.4:
98 | version "3.0.4"
99 | resolved "https://registry.npmmirror.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
100 | integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
101 | dependencies:
102 | dot-case "^3.0.4"
103 | tslib "^2.0.3"
104 |
105 | tslib@^2.0.3:
106 | version "2.3.1"
107 | resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
108 | integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
109 |
110 | util@^0.10.3:
111 | version "0.10.4"
112 | resolved "https://registry.npmmirror.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
113 | integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
114 | dependencies:
115 | inherits "2.0.3"
116 |
117 | wmr@^3.7.2:
118 | version "3.7.2"
119 | resolved "https://registry.npmmirror.com/wmr/-/wmr-3.7.2.tgz#3d6dfb771fafc0e2119d4502aaea26ecd5963c19"
120 | integrity sha512-i+e/T8J067qP2pBgq6E2gaW9qMGK+D9eGue85YM0Vflc2UuzXBP3fSS5PzvyHEKuPHZWmcFBmZRs6DU9Lkr9og==
121 |
--------------------------------------------------------------------------------