chore(dashboard): Setup test and script for validating i18n (#9799)
**What** - Adds a test that validates that en.json and $schema.json matches, this will help us catch missing translations, and prevent us from forgetting to update the schema when we delete/add new keys. - Adds a script for validating translations against the translation schema. This can be used to validate that community PRs for i18n contain all the required keys. To use the script you can run `yarn i18n:validate <file name>` e.g. `yarn i18n:validate da.json` which will look for a da.json file in the translation folder, and validate it against the schema. We handle this with a script as we don't want to do so through a test. Doing it with a test would mean that if we update the schema, we would also have to update all translations files that we don't maintain ourselves. The purpose of the script is just to allow us to easily review community PRs and also as a tool for people opening PR's to check their translations agains the schema, as it will print missing/additional keys. - Also adds a script to generate a schema from the en.json file. After adding/deleting keys to en.json you should run `yarn i18n:generate`.
This commit is contained in:
committed by
GitHub
parent
300ef8dbb9
commit
e2058683f4
@@ -7,6 +7,9 @@
|
||||
"build": "tsup && node ./scripts/generate-types.js",
|
||||
"build:preview": "vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest --run",
|
||||
"i18n:validate": "node ./scripts/i18n/validate-translation.js",
|
||||
"i18n:schema": "node ./scripts/i18n/generate-schema.js",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
||||
},
|
||||
"main": "dist/app.js",
|
||||
@@ -80,6 +83,7 @@
|
||||
"@types/react": "^18.2.79",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
"@vitejs/plugin-react": "4.2.1",
|
||||
"ajv": "^8.17.1",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"postcss": "^8.4.33",
|
||||
"prettier": "^3.1.1",
|
||||
@@ -87,7 +91,8 @@
|
||||
"tsup": "^8.0.2",
|
||||
"typescript": "5.2.2",
|
||||
"vite": "^5.2.11",
|
||||
"vite-plugin-inspect": "^0.8.7"
|
||||
"vite-plugin-inspect": "^0.8.7",
|
||||
"vitest": "^2.1.4"
|
||||
},
|
||||
"packageManager": "yarn@3.2.1"
|
||||
}
|
||||
|
||||
49
packages/admin/dashboard/scripts/i18n/generate-schema.js
Normal file
49
packages/admin/dashboard/scripts/i18n/generate-schema.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
|
||||
const translationsDir = path.join(__dirname, "../../src/i18n/translations")
|
||||
const enPath = path.join(translationsDir, "en.json")
|
||||
const schemaPath = path.join(translationsDir, "$schema.json")
|
||||
|
||||
function generateSchemaFromObject(obj) {
|
||||
if (typeof obj !== "object" || obj === null) {
|
||||
return { type: typeof obj }
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return {
|
||||
type: "array",
|
||||
items: generateSchemaFromObject(obj[0] || "string"),
|
||||
}
|
||||
}
|
||||
|
||||
const properties = {}
|
||||
const required = []
|
||||
|
||||
Object.entries(obj).forEach(([key, value]) => {
|
||||
properties[key] = generateSchemaFromObject(value)
|
||||
required.push(key)
|
||||
})
|
||||
|
||||
return {
|
||||
type: "object",
|
||||
properties,
|
||||
required,
|
||||
additionalProperties: false,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const enJson = JSON.parse(fs.readFileSync(enPath, "utf-8"))
|
||||
|
||||
const schema = {
|
||||
$schema: "http://json-schema.org/draft-07/schema#",
|
||||
...generateSchemaFromObject(enJson),
|
||||
}
|
||||
|
||||
fs.writeFileSync(schemaPath, JSON.stringify(schema, null, 2))
|
||||
console.log("Schema generated successfully at:", schemaPath)
|
||||
} catch (error) {
|
||||
console.error("Error generating schema:", error.message)
|
||||
process.exit(1)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
const Ajv = require("ajv")
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const schema = require("../../src/i18n/translations/$schema.json")
|
||||
|
||||
const ajv = new Ajv({ allErrors: true })
|
||||
const validate = ajv.compile(schema)
|
||||
|
||||
// Get file name from command line arguments
|
||||
const fileName = process.argv[2]
|
||||
|
||||
if (!fileName) {
|
||||
console.error("Please provide a file name (e.g., en.json) as an argument.")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const filePath = path.join(__dirname, "../../src/i18n/translations", fileName)
|
||||
|
||||
try {
|
||||
const translations = JSON.parse(fs.readFileSync(filePath, "utf-8"))
|
||||
|
||||
if (!validate(translations)) {
|
||||
console.error(`\nValidation failed for ${fileName}:`)
|
||||
validate.errors?.forEach((error) => {
|
||||
if (error.keyword === "required") {
|
||||
const missingKeys = error.params.missingProperty
|
||||
console.error(
|
||||
` Missing required key: "${missingKeys}" at ${error.instancePath}`
|
||||
)
|
||||
} else if (error.keyword === "additionalProperties") {
|
||||
const extraKey = error.params.additionalProperty
|
||||
console.error(
|
||||
` Unexpected key: "${extraKey}" at ${error.instancePath}`
|
||||
)
|
||||
} else {
|
||||
console.error(` Error: ${error.message} at ${error.instancePath}`)
|
||||
}
|
||||
})
|
||||
process.exit(1)
|
||||
} else {
|
||||
console.log(`${fileName} matches the schema.`)
|
||||
process.exit(0)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error reading or parsing file: ${error.message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
import { describe, expect, test } from "vitest"
|
||||
|
||||
import schema from "../$schema.json"
|
||||
|
||||
const translationsDir = path.join(__dirname, "..")
|
||||
|
||||
function getRequiredKeysFromSchema(schema: any, prefix = ""): string[] {
|
||||
const keys: string[] = []
|
||||
|
||||
if (schema.type === "object" && schema.properties) {
|
||||
Object.entries(schema.properties).forEach(([key, value]: [string, any]) => {
|
||||
const newPrefix = prefix ? `${prefix}.${key}` : key
|
||||
if (value.type === "object") {
|
||||
keys.push(...getRequiredKeysFromSchema(value, newPrefix))
|
||||
} else {
|
||||
keys.push(newPrefix)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return keys.sort()
|
||||
}
|
||||
|
||||
function getTranslationKeys(obj: any, prefix = ""): string[] {
|
||||
const keys: string[] = []
|
||||
|
||||
Object.entries(obj).forEach(([key, value]) => {
|
||||
const newPrefix = prefix ? `${prefix}.${key}` : key
|
||||
if (value && typeof value === "object") {
|
||||
keys.push(...getTranslationKeys(value, newPrefix))
|
||||
} else {
|
||||
keys.push(newPrefix)
|
||||
}
|
||||
})
|
||||
|
||||
return keys.sort()
|
||||
}
|
||||
|
||||
describe("translation schema validation", () => {
|
||||
test("en.json should have all keys defined in schema", () => {
|
||||
const enPath = path.join(translationsDir, "en.json")
|
||||
const enTranslations = JSON.parse(fs.readFileSync(enPath, "utf-8"))
|
||||
|
||||
const schemaKeys = getRequiredKeysFromSchema(schema)
|
||||
const translationKeys = getTranslationKeys(enTranslations)
|
||||
|
||||
const missingInTranslations = schemaKeys.filter(
|
||||
(key) => !translationKeys.includes(key)
|
||||
)
|
||||
const extraInTranslations = translationKeys.filter(
|
||||
(key) => !schemaKeys.includes(key)
|
||||
)
|
||||
|
||||
if (missingInTranslations.length > 0) {
|
||||
console.error("\nMissing keys in en.json:", missingInTranslations)
|
||||
}
|
||||
if (extraInTranslations.length > 0) {
|
||||
console.error("\nExtra keys in en.json:", extraInTranslations)
|
||||
}
|
||||
|
||||
expect(missingInTranslations).toEqual([])
|
||||
expect(extraInTranslations).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -3,5 +3,6 @@
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": false,
|
||||
"composite": true
|
||||
}
|
||||
},
|
||||
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"]
|
||||
}
|
||||
|
||||
186
yarn.lock
186
yarn.lock
@@ -5612,6 +5612,7 @@ __metadata:
|
||||
"@types/react-dom": ^18.2.25
|
||||
"@uiw/react-json-view": ^2.0.0-alpha.17
|
||||
"@vitejs/plugin-react": 4.2.1
|
||||
ajv: ^8.17.1
|
||||
autoprefixer: ^10.4.17
|
||||
cmdk: ^0.2.0
|
||||
date-fns: ^3.6.0
|
||||
@@ -5638,6 +5639,7 @@ __metadata:
|
||||
typescript: 5.2.2
|
||||
vite: ^5.2.11
|
||||
vite-plugin-inspect: ^0.8.7
|
||||
vitest: ^2.1.4
|
||||
zod: 3.22.4
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@@ -14440,6 +14442,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/expect@npm:2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@vitest/expect@npm:2.1.4"
|
||||
dependencies:
|
||||
"@vitest/spy": 2.1.4
|
||||
"@vitest/utils": 2.1.4
|
||||
chai: ^5.1.2
|
||||
tinyrainbow: ^1.2.0
|
||||
checksum: cd20ec6f92479fe5d155221d7623cf506a84e10f537639c93b8a2ffba7314b65f0fcab3754ba31308a0381470fea2e3c53d283e5f5be2c592a69d7e817a85571
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/mocker@npm:2.1.3":
|
||||
version: 2.1.3
|
||||
resolution: "@vitest/mocker@npm:2.1.3"
|
||||
@@ -14460,6 +14474,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/mocker@npm:2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@vitest/mocker@npm:2.1.4"
|
||||
dependencies:
|
||||
"@vitest/spy": 2.1.4
|
||||
estree-walker: ^3.0.3
|
||||
magic-string: ^0.30.12
|
||||
peerDependencies:
|
||||
msw: ^2.4.9
|
||||
vite: ^5.0.0
|
||||
peerDependenciesMeta:
|
||||
msw:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
checksum: 3327ec34d05f25e17c0a083877e204a31ffc4150fb259e8f82191aa5328f456e81374b977e56db17c835bd29a7eaba249e011c21b27a52bf31fd4127104d4662
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/pretty-format@npm:2.0.5":
|
||||
version: 2.0.5
|
||||
resolution: "@vitest/pretty-format@npm:2.0.5"
|
||||
@@ -14487,6 +14520,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/pretty-format@npm:2.1.4, @vitest/pretty-format@npm:^2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@vitest/pretty-format@npm:2.1.4"
|
||||
dependencies:
|
||||
tinyrainbow: ^1.2.0
|
||||
checksum: dc20f04f64c95731bf9640fc53ae918d928ab93e70a56d9e03f201700098cdb041b50a8f6a5f30604d4a048c15f315537453f33054e29590a05d5b368ae6849d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/runner@npm:0.32.4":
|
||||
version: 0.32.4
|
||||
resolution: "@vitest/runner@npm:0.32.4"
|
||||
@@ -14508,6 +14550,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/runner@npm:2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@vitest/runner@npm:2.1.4"
|
||||
dependencies:
|
||||
"@vitest/utils": 2.1.4
|
||||
pathe: ^1.1.2
|
||||
checksum: be51bb7f63b6d524bed2b44bafa8022ac5019bc01a411497c8b607d13601dae40a592bad6b8e21096f02827bd256296354947525d038a2c04032fdaa9ca991f0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/snapshot@npm:0.32.4":
|
||||
version: 0.32.4
|
||||
resolution: "@vitest/snapshot@npm:0.32.4"
|
||||
@@ -14530,6 +14582,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/snapshot@npm:2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@vitest/snapshot@npm:2.1.4"
|
||||
dependencies:
|
||||
"@vitest/pretty-format": 2.1.4
|
||||
magic-string: ^0.30.12
|
||||
pathe: ^1.1.2
|
||||
checksum: 50e15398420870755e03d7d0cb7825642021e4974cb26760b8159f0c8273796732694b6a9a703a7cff88790ca4bb09f38bfc174396bcc7cbb93b96e5ac21d1d7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/spy@npm:0.32.4":
|
||||
version: 0.32.4
|
||||
resolution: "@vitest/spy@npm:0.32.4"
|
||||
@@ -14557,6 +14620,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/spy@npm:2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@vitest/spy@npm:2.1.4"
|
||||
dependencies:
|
||||
tinyspy: ^3.0.2
|
||||
checksum: a983efa140fa5211dc96a0c7c5110883c8095d00c45e711ecde1cc4a862560055b0e24907ae55970ab4a034e52265b7e8e70168f0da4b500b448d3d214eb045e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/utils@npm:0.32.4":
|
||||
version: 0.32.4
|
||||
resolution: "@vitest/utils@npm:0.32.4"
|
||||
@@ -14591,6 +14663,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/utils@npm:2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "@vitest/utils@npm:2.1.4"
|
||||
dependencies:
|
||||
"@vitest/pretty-format": 2.1.4
|
||||
loupe: ^3.1.2
|
||||
tinyrainbow: ^1.2.0
|
||||
checksum: fd632dbc2496d14bcc609230f1dad73039c9f52f4ca533d6b68fa1a04dd448e03510f2a8e4a368fd274cbb8902a6cd800140ab366dd055256beb2c0dcafcd9f2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitest/utils@npm:^2.0.5":
|
||||
version: 2.1.2
|
||||
resolution: "@vitest/utils@npm:2.1.2"
|
||||
@@ -14863,7 +14946,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ajv@npm:^8.12.0":
|
||||
"ajv@npm:^8.12.0, ajv@npm:^8.17.1":
|
||||
version: 8.17.1
|
||||
resolution: "ajv@npm:8.17.1"
|
||||
dependencies:
|
||||
@@ -16296,6 +16379,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chai@npm:^5.1.2":
|
||||
version: 5.1.2
|
||||
resolution: "chai@npm:5.1.2"
|
||||
dependencies:
|
||||
assertion-error: ^2.0.1
|
||||
check-error: ^2.1.1
|
||||
deep-eql: ^5.0.1
|
||||
loupe: ^3.1.0
|
||||
pathval: ^2.0.0
|
||||
checksum: 6c04ff8495b6e535df9c1b062b6b094828454e9a3c9493393e55b2f4dbff7aa2a29a4645133cad160fb00a16196c4dc03dc9bb37e1f4ba9df3b5f50d7533a736
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:*, chalk@npm:^5.0.0, chalk@npm:^5.2.0":
|
||||
version: 5.3.0
|
||||
resolution: "chalk@npm:5.3.0"
|
||||
@@ -17872,7 +17968,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"debug@npm:^4.3.5, debug@npm:^4.3.6":
|
||||
"debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:^4.3.7":
|
||||
version: 4.3.7
|
||||
resolution: "debug@npm:4.3.7"
|
||||
dependencies:
|
||||
@@ -19906,6 +20002,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"expect-type@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "expect-type@npm:1.1.0"
|
||||
checksum: 5af0febbe8fe18da05a6d51e3677adafd75213512285408156b368ca471252565d5ca6e59e4bddab25121f3cfcbbebc6a5489f8cc9db131cc29e69dcdcc7ae15
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"expect@npm:^29.0.0, expect@npm:^29.7.0":
|
||||
version: 29.7.0
|
||||
resolution: "expect@npm:29.7.0"
|
||||
@@ -24289,7 +24392,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loupe@npm:^3.1.0, loupe@npm:^3.1.1":
|
||||
"loupe@npm:^3.1.0, loupe@npm:^3.1.1, loupe@npm:^3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "loupe@npm:3.1.2"
|
||||
checksum: b13c02e3ddd6a9d5f8bf84133b3242de556512d824dddeea71cce2dbd6579c8f4d672381c4e742d45cf4423d0701765b4a6e5fbc24701def16bc2b40f8daa96a
|
||||
@@ -24438,7 +24541,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"magic-string@npm:^0.30.11":
|
||||
"magic-string@npm:^0.30.11, magic-string@npm:^0.30.12":
|
||||
version: 0.30.12
|
||||
resolution: "magic-string@npm:0.30.12"
|
||||
dependencies:
|
||||
@@ -31201,6 +31304,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinyexec@npm:^0.3.1":
|
||||
version: 0.3.1
|
||||
resolution: "tinyexec@npm:0.3.1"
|
||||
checksum: 11e7a7c5d8b3bddf8b5cbe82a9290d70a6fad84d528421d5d18297f165723cb53d2e737d8f58dcce5ca56f2e4aa2d060f02510b1f8971784f97eb3e9aec28f09
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinypool@npm:^0.5.0":
|
||||
version: 0.5.0
|
||||
resolution: "tinypool@npm:0.5.0"
|
||||
@@ -31208,7 +31318,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinypool@npm:^1.0.0":
|
||||
"tinypool@npm:^1.0.0, tinypool@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "tinypool@npm:1.0.1"
|
||||
checksum: 90939d6a03f1519c61007bf416632dc1f0b9c1a9dd673c179ccd9e36a408437384f984fc86555a5d040d45b595abc299c3bb39d354439e98a090766b5952e73d
|
||||
@@ -31229,7 +31339,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tinyspy@npm:^3.0.0":
|
||||
"tinyspy@npm:^3.0.0, tinyspy@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "tinyspy@npm:3.0.2"
|
||||
checksum: 55ffad24e346622b59292e097c2ee30a63919d5acb7ceca87fc0d1c223090089890587b426e20054733f97a58f20af2c349fb7cc193697203868ab7ba00bcea0
|
||||
@@ -32776,6 +32886,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-node@npm:2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "vite-node@npm:2.1.4"
|
||||
dependencies:
|
||||
cac: ^6.7.14
|
||||
debug: ^4.3.7
|
||||
pathe: ^1.1.2
|
||||
vite: ^5.0.0
|
||||
bin:
|
||||
vite-node: vite-node.mjs
|
||||
checksum: 4c09128f27ded3f681d2c034f0bb74856cef9cad9c437951bc7f95dab92fc95a5d1ee7f54e32067458ad1105e1f24975e8bc64aa7ed8f5b33449b4f5fea65919
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-plugin-inspect@npm:^0.8.7":
|
||||
version: 0.8.7
|
||||
resolution: "vite-plugin-inspect@npm:0.8.7"
|
||||
@@ -33037,6 +33161,56 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vitest@npm:^2.1.4":
|
||||
version: 2.1.4
|
||||
resolution: "vitest@npm:2.1.4"
|
||||
dependencies:
|
||||
"@vitest/expect": 2.1.4
|
||||
"@vitest/mocker": 2.1.4
|
||||
"@vitest/pretty-format": ^2.1.4
|
||||
"@vitest/runner": 2.1.4
|
||||
"@vitest/snapshot": 2.1.4
|
||||
"@vitest/spy": 2.1.4
|
||||
"@vitest/utils": 2.1.4
|
||||
chai: ^5.1.2
|
||||
debug: ^4.3.7
|
||||
expect-type: ^1.1.0
|
||||
magic-string: ^0.30.12
|
||||
pathe: ^1.1.2
|
||||
std-env: ^3.7.0
|
||||
tinybench: ^2.9.0
|
||||
tinyexec: ^0.3.1
|
||||
tinypool: ^1.0.1
|
||||
tinyrainbow: ^1.2.0
|
||||
vite: ^5.0.0
|
||||
vite-node: 2.1.4
|
||||
why-is-node-running: ^2.3.0
|
||||
peerDependencies:
|
||||
"@edge-runtime/vm": "*"
|
||||
"@types/node": ^18.0.0 || >=20.0.0
|
||||
"@vitest/browser": 2.1.4
|
||||
"@vitest/ui": 2.1.4
|
||||
happy-dom: "*"
|
||||
jsdom: "*"
|
||||
peerDependenciesMeta:
|
||||
"@edge-runtime/vm":
|
||||
optional: true
|
||||
"@types/node":
|
||||
optional: true
|
||||
"@vitest/browser":
|
||||
optional: true
|
||||
"@vitest/ui":
|
||||
optional: true
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
bin:
|
||||
vitest: vitest.mjs
|
||||
checksum: 96068ea6d40186c8ca946ee688ba3717dbd0947c56a2bcd625c14a5df25776342ff2f1eb326b06cb6f538d9568633b3e821991aa7c95a98e458be9fc2b3ca59e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"void-elements@npm:3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "void-elements@npm:3.1.0"
|
||||
|
||||
Reference in New Issue
Block a user