зеркало из https://github.com/github/docs.git
cache external link checking to disk file (#32082)
This commit is contained in:
Родитель
4aff99e80f
Коммит
46fbab792e
|
@ -6,6 +6,8 @@ import cheerio from 'cheerio'
|
|||
import coreLib from '@actions/core'
|
||||
import got, { RequestError } from 'got'
|
||||
import chalk from 'chalk'
|
||||
import { Low } from 'lowdb'
|
||||
import { JSONFile } from 'lowdb/node'
|
||||
|
||||
import shortVersions from '../../middleware/contextualizers/short-versions.js'
|
||||
import contextualize from '../../middleware/context.js'
|
||||
|
@ -31,6 +33,29 @@ Object.entries(STATIC_PREFIXES).forEach(([key, value]) => {
|
|||
}
|
||||
})
|
||||
|
||||
// By default, we don't cache external link checks to disk.
|
||||
// By setting this env var to something >0, it enables the disk-based
|
||||
// caching of external links.
|
||||
const EXTERNAL_LINK_CHECKER_MAX_AGE_MS =
|
||||
parseInt(process.env.EXTERNAL_LINK_CHECKER_MAX_AGE_DAYS || 0) * 24 * 60 * 60 * 1000
|
||||
const EXTERNAL_LINK_CHECKER_DB =
|
||||
process.env.EXTERNAL_LINK_CHECKER_DB || 'external-link-checker-db.json'
|
||||
|
||||
const adapter = new JSONFile(EXTERNAL_LINK_CHECKER_DB)
|
||||
const externalLinkCheckerDB = new Low(adapter)
|
||||
|
||||
// Given a number and a percentage, return the same number with a *percentage*
|
||||
// max change of making a bit larger or smaller.
|
||||
// E.g. `jitter(55, 10)` will return a value between `[55 - 55/10: 55 + 55/10]`
|
||||
// This is useful to avoid the caching timestamps all getting the same
|
||||
// numbers from the day it started which means that they don't ALL expire
|
||||
// on the same day but start to expire in a bit of a "random pattern" so
|
||||
// you don't get all or nothing.
|
||||
function jitter(base, percentage) {
|
||||
const r = percentage / 100
|
||||
const negative = Math.random() > 0.5 ? -1 : 1
|
||||
return base + base * Math.random() * r * negative
|
||||
}
|
||||
// Return a function that can as quickly as possible check if a certain
|
||||
// href input should be skipped.
|
||||
// Do this so we can use a `Set` and a `iterable.some()` for a speedier
|
||||
|
@ -186,12 +211,17 @@ async function main(core, octokit, uploadArtifact, opts = {}) {
|
|||
)
|
||||
}
|
||||
|
||||
await externalLinkCheckerDB.read()
|
||||
externalLinkCheckerDB.data ||= { urls: {} }
|
||||
|
||||
debugTimeStart(core, 'processPages')
|
||||
const flawsGroups = await Promise.all(
|
||||
pages.map((page) => processPage(core, page, pageMap, redirects, opts))
|
||||
pages.map((page) => processPage(core, page, pageMap, redirects, opts, externalLinkCheckerDB))
|
||||
)
|
||||
debugTimeEnd(core, 'processPages')
|
||||
|
||||
await externalLinkCheckerDB.write()
|
||||
|
||||
const flaws = flawsGroups.flat()
|
||||
|
||||
printGlobalCacheHitRatio(core)
|
||||
|
@ -518,12 +548,12 @@ function getPages(pageList, languages, filters, files, max) {
|
|||
.slice(0, max ? Math.min(max, pageList.length) : pageList.length)
|
||||
}
|
||||
|
||||
async function processPage(core, page, pageMap, redirects, opts) {
|
||||
async function processPage(core, page, pageMap, redirects, opts, db) {
|
||||
const { verbose, verboseUrl, bail } = opts
|
||||
|
||||
const allFlawsEach = await Promise.all(
|
||||
page.permalinks.map((permalink) => {
|
||||
return processPermalink(core, permalink, page, pageMap, redirects, opts)
|
||||
return processPermalink(core, permalink, page, pageMap, redirects, opts, db)
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -545,7 +575,7 @@ async function processPage(core, page, pageMap, redirects, opts) {
|
|||
return allFlaws
|
||||
}
|
||||
|
||||
async function processPermalink(core, permalink, page, pageMap, redirects, opts) {
|
||||
async function processPermalink(core, permalink, page, pageMap, redirects, opts, db) {
|
||||
const {
|
||||
level = 'critical',
|
||||
checkAnchors,
|
||||
|
@ -583,7 +613,8 @@ async function processPermalink(core, permalink, page, pageMap, redirects, opts)
|
|||
pageMap,
|
||||
checkAnchors,
|
||||
checkExternalLinks,
|
||||
{ verbose, patient }
|
||||
{ verbose, patient },
|
||||
db
|
||||
)
|
||||
|
||||
if (flaw) {
|
||||
|
@ -727,7 +758,8 @@ async function checkHrefLink(
|
|||
pageMap,
|
||||
checkAnchors = false,
|
||||
checkExternalLinks = false,
|
||||
{ verbose = false, patient = false } = {}
|
||||
{ verbose = false, patient = false } = {},
|
||||
db = null
|
||||
) {
|
||||
if (href === '#') {
|
||||
if (checkAnchors) {
|
||||
|
@ -781,13 +813,53 @@ async function checkHrefLink(
|
|||
if (linksToSkip(href)) {
|
||||
return
|
||||
}
|
||||
const { ok, ...info } = await checkExternalURL(core, href, { verbose, patient })
|
||||
const { ok, ...info } = await checkExternalURLCached(core, href, { verbose, patient }, db)
|
||||
if (!ok) {
|
||||
return { CRITICAL: `Broken external link (${JSON.stringify(info)})`, isExternal: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can't do this memoization within the checkExternalURL because it can
|
||||
// return a Promise since it already collates multiple URLs under the
|
||||
// same cache key.
|
||||
async function checkExternalURLCached(core, href, { verbose, patient }, db) {
|
||||
const cacheMaxAge = EXTERNAL_LINK_CHECKER_MAX_AGE_MS
|
||||
const timestamp = new Date().getTime()
|
||||
const url = href.split('#')[0]
|
||||
|
||||
if (cacheMaxAge) {
|
||||
const tooOld = timestamp - Math.floor(jitter(cacheMaxAge, 10))
|
||||
if (db && db.data.urls[url]) {
|
||||
if (db.data.urls[url].timestamp > tooOld) {
|
||||
if (verbose) {
|
||||
core.debug(`External URL ${url} in cache`)
|
||||
}
|
||||
return db.data.urls[url].result
|
||||
} else if (verbose) {
|
||||
core.info(`External URL ${url} in cache but too old`)
|
||||
// Delete it so the cache file don't bloat infinitely
|
||||
delete db.data.urls[url]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await checkExternalURL(core, href, { verbose, patient })
|
||||
|
||||
if (cacheMaxAge) {
|
||||
// By only cache storing successful results, we give the system a chance
|
||||
// to try 40xx and 50x errors another go.
|
||||
if (db && result.ok) {
|
||||
db.data.urls[url] = {
|
||||
timestamp,
|
||||
result,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
const _fetchCache = new Map()
|
||||
async function checkExternalURL(core, url, { verbose = false, patient = false } = {}) {
|
||||
if (!url.startsWith('https://')) throw new Error('Invalid URL')
|
||||
|
|
|
@ -54,6 +54,12 @@ jobs:
|
|||
if: ${{ github.repository == 'github/docs-internal' }}
|
||||
run: .github/actions-scripts/merge-early-access.sh
|
||||
|
||||
- name: Restore disk-cache file for external link checking
|
||||
uses: actions/cache@48af2dc4a9e8278b89d7fa154b955c30c6aaab09
|
||||
with:
|
||||
path: external-link-checker-db.json
|
||||
key: external-link-checker-${{ hashFiles('.github/actions/rendered-content-link-checker.js') }}
|
||||
|
||||
- name: Run link checker
|
||||
env:
|
||||
LEVEL: 'critical'
|
||||
|
@ -67,6 +73,10 @@ jobs:
|
|||
CREATE_REPORT: true
|
||||
CHECK_EXTERNAL_LINKS: true
|
||||
PATIENT: true
|
||||
# This means that we'll *re-check* external URLs once a week.
|
||||
# But mind you that the number has a 10% chance of "jitter"
|
||||
# to avoid a stampeding herd when they all expire some day.
|
||||
EXTERNAL_LINK_CHECKER_MAX_AGE_DAYS: 7
|
||||
timeout-minutes: 30
|
||||
run: node .github/actions/rendered-content-link-checker.js
|
||||
|
||||
|
|
|
@ -29,3 +29,4 @@ user-code/
|
|||
|
||||
# Logs from scripts
|
||||
script/logs/
|
||||
external-link-checker-db.json
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
"liquidjs": "9.22.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lowdb": "5.0.5",
|
||||
"lunr": "^2.3.9",
|
||||
"lunr-languages": "^1.9.0",
|
||||
"mdast-util-from-markdown": "^1.2.0",
|
||||
|
@ -3480,201 +3481,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.2.4.tgz",
|
||||
"integrity": "sha512-/gApFXWk5CCLFQJL5IYJXxPQuG5tz5nPX4l27A9Zm/+wJxiwFrRSP54AopDxIv4JRp/rGwcgk/lZS/0Clw8jYA=="
|
||||
},
|
||||
"node_modules/@next/swc-android-arm-eabi": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.4.tgz",
|
||||
"integrity": "sha512-P4YSFNpmXXSnn3P1qsOAqz+MX3On9fHrlc8ovb/CFJJoU+YLCR53iCEwfw39e0IZEgDA7ttgr108plF8mxaX0g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-android-arm64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.4.tgz",
|
||||
"integrity": "sha512-4o2n14E18O+8xHlf6dgJsWPXN9gmSmfIe2Z0EqKDIPBBkFt/2CyrH0+vwHnL2l7xkDHhOGfZYcYIWVUR5aNu0A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.4.tgz",
|
||||
"integrity": "sha512-DcUO6MGBL9E3jj5o86MUnTOy4WawIJJhyCcFYO4f51sbl7+uPIYIx40eo98A6NwJEXazCqq1hLeqOaNTAIvDiQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.4.tgz",
|
||||
"integrity": "sha512-IUlFMqeLjdIzDorrGC2Dt+2Ae3DbKQbRzCzmDq4/CP1+jJGeDXo/2AHnlE+WYnwQAC4KtAz6pbVnd3KstZWsVA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-freebsd-x64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.4.tgz",
|
||||
"integrity": "sha512-475vwyWcjnyDVDWLgAATP0HI8W1rwByc+uXk1B6KkAVFhkoDgH387LW0uNqxavK+VxCzj3avQXX/58XDvxtSlg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.4.tgz",
|
||||
"integrity": "sha512-qZW+L3iG3XSGtlOPmD5RRWXyk6ZNdscLV0BQjuDvP+exTg+uixqHXOHz0/GVATIJEBQOF0Kew7jAXVXEP+iRTQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.4.tgz",
|
||||
"integrity": "sha512-fEPRjItWYaKyyG9N+2HIA59OBHIhk7WC+Rh+LwXsh0pQe870Ykpek3KQs0umjsrEGe57NyMomq3f80/N8taDvA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.4.tgz",
|
||||
"integrity": "sha512-rnCTzXII0EBCcFn9P5s/Dho2kPUMSX/bP0iOAj8wEI/IxUEfEElbin89zJoNW30cycHu19xY8YP4K2+hzciPzQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.4.tgz",
|
||||
"integrity": "sha512-PhXX6NSuIuhHInxPY2VkG2Bl7VllsD3Cjx+pQcS1wTym7Zt7UoLvn05PkRrkiyIkvR+UXnqPUM3TYiSbnemXEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.4.tgz",
|
||||
"integrity": "sha512-GmC/QROiUZpFirHRfPQqMyCXZ+5+ndbBZrMvL74HtQB/CKXB8K1VM+rvy9Gp/5OaU8Rxp48IcX79NOfI2LiXlA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.4.tgz",
|
||||
"integrity": "sha512-9XKoCXbNZuaMRPtcKQz3+hgVpkMosaLlcxHFXT8/j4w61k7/qvEbrkMDS9WHNrD/xVcLycwhPRgXcns2K1BdBQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.4.tgz",
|
||||
"integrity": "sha512-hEyRieZKH9iw4AzvXaQ+Fyb98k0G/o9QcRGxA1/O/O/elf1+Qvuwb15phT8GbVtIeNziy66XTPOhKKfdr8KyUg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.4.tgz",
|
||||
"integrity": "sha512-5Pl1tdMJWLy4rvzU1ecx0nHWgDPqoYuvYoXE/5X0Clu9si/yOuBIj573F2kOTY7mu0LX2wgCJVSnyK0abHBxIw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
@ -5650,9 +5456,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/babel-loader": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.0.1.tgz",
|
||||
"integrity": "sha512-szYjslOXFlj/po5KfrVmiuBAcI6GVHFuAgC96Qd6mMPHdwl4lmAJkYtvjQ1RxxPjgdkKjd3LQgXDE4jxEutNuw==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.0.tgz",
|
||||
"integrity": "sha512-Antt61KJPinUMwHwIIz9T5zfMgevnfZkEVWYDWlG888fgdvRRGD0JTuf/fFozQnfT+uq64sk1bmdHDy/mOEWnA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"find-cache-dir": "^3.3.2",
|
||||
|
@ -9564,20 +9370,6 @@
|
|||
"devOptional": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"license": "MIT"
|
||||
|
@ -14245,6 +14037,20 @@
|
|||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lowdb": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/lowdb/-/lowdb-5.0.5.tgz",
|
||||
"integrity": "sha512-7EWKmIMhNKA8TXFhL8t0p6N2LC53l3ZqsWQGSksGhhjrcms9rbKlyrAh2PzSGK5v0KPJ2W5VItBnC3NDRzOnzQ==",
|
||||
"dependencies": {
|
||||
"steno": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/lower-case": {
|
||||
"version": "2.0.2",
|
||||
"dev": true,
|
||||
|
@ -18737,6 +18543,17 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/steno": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/steno/-/steno-3.0.0.tgz",
|
||||
"integrity": "sha512-uZtn7Ht9yXLiYgOsmo8btj4+f7VxyYheMt8g6F1ANjyqByQXEE2Gygjgenp3otHH1TlHsS4JAaRGv5wJ1wvMNw==",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-combiner": {
|
||||
"version": "0.0.4",
|
||||
"dev": true,
|
||||
|
@ -23139,84 +22956,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.2.4.tgz",
|
||||
"integrity": "sha512-/gApFXWk5CCLFQJL5IYJXxPQuG5tz5nPX4l27A9Zm/+wJxiwFrRSP54AopDxIv4JRp/rGwcgk/lZS/0Clw8jYA=="
|
||||
},
|
||||
"@next/swc-android-arm-eabi": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.4.tgz",
|
||||
"integrity": "sha512-P4YSFNpmXXSnn3P1qsOAqz+MX3On9fHrlc8ovb/CFJJoU+YLCR53iCEwfw39e0IZEgDA7ttgr108plF8mxaX0g==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-android-arm64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.2.4.tgz",
|
||||
"integrity": "sha512-4o2n14E18O+8xHlf6dgJsWPXN9gmSmfIe2Z0EqKDIPBBkFt/2CyrH0+vwHnL2l7xkDHhOGfZYcYIWVUR5aNu0A==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-arm64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.2.4.tgz",
|
||||
"integrity": "sha512-DcUO6MGBL9E3jj5o86MUnTOy4WawIJJhyCcFYO4f51sbl7+uPIYIx40eo98A6NwJEXazCqq1hLeqOaNTAIvDiQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-x64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.2.4.tgz",
|
||||
"integrity": "sha512-IUlFMqeLjdIzDorrGC2Dt+2Ae3DbKQbRzCzmDq4/CP1+jJGeDXo/2AHnlE+WYnwQAC4KtAz6pbVnd3KstZWsVA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-freebsd-x64": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.4.tgz",
|
||||
"integrity": "sha512-475vwyWcjnyDVDWLgAATP0HI8W1rwByc+uXk1B6KkAVFhkoDgH387LW0uNqxavK+VxCzj3avQXX/58XDvxtSlg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.2.4.tgz",
|
||||
"integrity": "sha512-qZW+L3iG3XSGtlOPmD5RRWXyk6ZNdscLV0BQjuDvP+exTg+uixqHXOHz0/GVATIJEBQOF0Kew7jAXVXEP+iRTQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.2.4.tgz",
|
||||
"integrity": "sha512-fEPRjItWYaKyyG9N+2HIA59OBHIhk7WC+Rh+LwXsh0pQe870Ykpek3KQs0umjsrEGe57NyMomq3f80/N8taDvA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-musl": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.2.4.tgz",
|
||||
"integrity": "sha512-rnCTzXII0EBCcFn9P5s/Dho2kPUMSX/bP0iOAj8wEI/IxUEfEElbin89zJoNW30cycHu19xY8YP4K2+hzciPzQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-x64-gnu": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.2.4.tgz",
|
||||
"integrity": "sha512-PhXX6NSuIuhHInxPY2VkG2Bl7VllsD3Cjx+pQcS1wTym7Zt7UoLvn05PkRrkiyIkvR+UXnqPUM3TYiSbnemXEw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-x64-musl": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.2.4.tgz",
|
||||
"integrity": "sha512-GmC/QROiUZpFirHRfPQqMyCXZ+5+ndbBZrMvL74HtQB/CKXB8K1VM+rvy9Gp/5OaU8Rxp48IcX79NOfI2LiXlA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.2.4.tgz",
|
||||
"integrity": "sha512-9XKoCXbNZuaMRPtcKQz3+hgVpkMosaLlcxHFXT8/j4w61k7/qvEbrkMDS9WHNrD/xVcLycwhPRgXcns2K1BdBQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.2.4.tgz",
|
||||
"integrity": "sha512-hEyRieZKH9iw4AzvXaQ+Fyb98k0G/o9QcRGxA1/O/O/elf1+Qvuwb15phT8GbVtIeNziy66XTPOhKKfdr8KyUg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-x64-msvc": {
|
||||
"version": "12.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.2.4.tgz",
|
||||
"integrity": "sha512-5Pl1tdMJWLy4rvzU1ecx0nHWgDPqoYuvYoXE/5X0Clu9si/yOuBIj573F2kOTY7mu0LX2wgCJVSnyK0abHBxIw==",
|
||||
"optional": true
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
@ -24768,9 +24507,9 @@
|
|||
}
|
||||
},
|
||||
"babel-loader": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.0.1.tgz",
|
||||
"integrity": "sha512-szYjslOXFlj/po5KfrVmiuBAcI6GVHFuAgC96Qd6mMPHdwl4lmAJkYtvjQ1RxxPjgdkKjd3LQgXDE4jxEutNuw==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.0.tgz",
|
||||
"integrity": "sha512-Antt61KJPinUMwHwIIz9T5zfMgevnfZkEVWYDWlG888fgdvRRGD0JTuf/fFozQnfT+uq64sk1bmdHDy/mOEWnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"find-cache-dir": "^3.3.2",
|
||||
|
@ -27509,13 +27248,6 @@
|
|||
"version": "1.0.0",
|
||||
"devOptional": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1"
|
||||
},
|
||||
|
@ -30861,6 +30593,14 @@
|
|||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"lowdb": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/lowdb/-/lowdb-5.0.5.tgz",
|
||||
"integrity": "sha512-7EWKmIMhNKA8TXFhL8t0p6N2LC53l3ZqsWQGSksGhhjrcms9rbKlyrAh2PzSGK5v0KPJ2W5VItBnC3NDRzOnzQ==",
|
||||
"requires": {
|
||||
"steno": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "2.0.2",
|
||||
"dev": true,
|
||||
|
@ -33757,6 +33497,11 @@
|
|||
"state-toggle": {
|
||||
"version": "1.0.3"
|
||||
},
|
||||
"steno": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/steno/-/steno-3.0.0.tgz",
|
||||
"integrity": "sha512-uZtn7Ht9yXLiYgOsmo8btj4+f7VxyYheMt8g6F1ANjyqByQXEE2Gygjgenp3otHH1TlHsS4JAaRGv5wJ1wvMNw=="
|
||||
},
|
||||
"stream-combiner": {
|
||||
"version": "0.0.4",
|
||||
"dev": true,
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
"liquidjs": "9.22.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lowdb": "5.0.5",
|
||||
"lunr": "^2.3.9",
|
||||
"lunr-languages": "^1.9.0",
|
||||
"mdast-util-from-markdown": "^1.2.0",
|
||||
|
|
Загрузка…
Ссылка в новой задаче