diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c8c5768 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +end_of_line = lf +indent_style = space +indent_size = 4 +max_line_length = 120 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false +max_line_length = 80 + +[*.{json,yml,yaml,prettierrc}] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d1f63d3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +* text=auto eol=lf + +*.png binary +*.jpg binary +*.jpeg binary +*.ico binary +*.tff binary +*.woff binary +*.woff2 binary diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..d58c964 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,55 @@ +name: Deploy Docs + +on: + push: + branches: [main] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm # or pnpm / yarn + - name: Setup Pages + uses: actions/configure-pages@v4 + - name: Install dependencies + run: npm ci + - name: Build with VitePress + run: npm run build:static + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: dist + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: build + runs-on: ubuntu-latest + name: Deploy + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e404c0f --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# build output +dist/ +# generated stuff +cache/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..f069afa --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "singleQuote": false, + "semi": false, + "trailingComma": "all", + "quoteProps": "as-needed", + "bracketSpacing": true, + "bracketSameLine": true, + "arrowParens": "always", + "endOfLine": "lf", + "useTabs": false, + "singleAttributePerLine": false +} diff --git a/main/WikiConfig.ts b/main/WikiConfig.ts new file mode 100644 index 0000000..0ea8efd --- /dev/null +++ b/main/WikiConfig.ts @@ -0,0 +1,35 @@ +import { z } from "zod"; +import fs from "fs"; +import path from "path"; + +const schema = z.object({ + wikis: z.array(z.object({ + name: z.string(), + })), +}) + +const jsonString = fs.readFileSync(path.resolve(__dirname, "../", "wikis.json"), "utf-8"); +const json = schema.parse(JSON.parse(jsonString)) +const wikis: Map = new Map() + +json.wikis.forEach((wiki) => { + wikis.set(wiki.name, wiki as WikiEntry) +}) + +export interface WikiEntry { + name: string +} + +export class WikiConfig { + constructor(private wikis: Map) {} + + hasWiki(name: string): boolean { + return this.wikis.has(name) + } + + forEach(onEach: (wiki: WikiEntry) => void) { + this.wikis.forEach(onEach) + } +} + +export default new WikiConfig(wikis) diff --git a/main/build_wikis.ts b/main/build_wikis.ts new file mode 100644 index 0000000..d75ef53 --- /dev/null +++ b/main/build_wikis.ts @@ -0,0 +1,64 @@ +import fs from "fs" +import path from "path" +import { execSync } from "child_process" +import WikiConfig, { WikiEntry } from "./WikiConfig" + +const ROOT_DIR = path.resolve(__dirname, "../") +const DIST_DIR = path.join(ROOT_DIR, "dist") +const WIKIS_DIR = path.join(ROOT_DIR, "wikis") + +function run() { + cleanDist() + buildWikis() +} +run() + +function cleanDist() { + console.log("Start cleaning wiki dist directory...") + if (fs.existsSync(DIST_DIR)) { + fs.rmSync(DIST_DIR, { recursive: true }) + } + + fs.mkdirSync(DIST_DIR) +} + +function buildWikis() { + console.log("Start building wikis...") + WikiConfig.forEach((wiki) => { + try { + buildWiki(wiki) + } catch (e) { + console.error(e) + } + }) +} + +function buildWiki(wiki: WikiEntry) { + console.log(`Start building ${wiki.name}...`) + const wikiPath = path.join(WIKIS_DIR, wiki.name) + if (!fs.existsSync(wikiPath)) { + throw new Error(`Wiki ${wiki.name} not found`) + } + + runBuild(wiki) + + const wikiDist = path.join(wikiPath, ".vitepress", "dist") + const targetDist = path.join(DIST_DIR, wiki.name) + moveWikiToDist(wikiDist, targetDist) +} + +function runBuild(wiki: WikiEntry) { + execSync(`npm run build wikis/${wiki.name}`, { cwd: ROOT_DIR, stdio: "inherit" }) +} + +function moveWikiToDist(wikiDist: string, targetDist: string) { + if (fs.existsSync(targetDist)) { + fs.rmSync(targetDist, { recursive: true }) + } + + fs.renameSync(wikiDist, targetDist) + + if (fs.existsSync(wikiDist)) { + fs.rmSync(wikiDist, { recursive: true }) + } +} diff --git a/main/defineAlmostWiki.ts b/main/defineAlmostWiki.ts new file mode 100644 index 0000000..bbf5ebc --- /dev/null +++ b/main/defineAlmostWiki.ts @@ -0,0 +1,38 @@ +import { DefaultTheme, UserConfig } from "vitepress" + +export function defineConfig(config: UserConfig): UserConfig { + config.title = "AlmostWiki" + + if (!config.themeConfig) { + config.themeConfig = {} + } + + config.themeConfig.socialLinks = [ + { + icon: "github", + link: "https://github.com/AlmostReliable", + }, + { + icon: "discord", + link: "https://discord.com/invite/ThFnwZCyYY", + }, + ] + + config.themeConfig.search = { + provider: "local", + options: { + detailedView: true, + miniSearch: { + searchOptions: { + maxFuzzy: 3, + }, + }, + }, + } + + config.themeConfig.outline = { + level: [2, 3], + } + + return config +} diff --git a/main/start_dev_server.ts b/main/start_dev_server.ts new file mode 100644 index 0000000..0428595 --- /dev/null +++ b/main/start_dev_server.ts @@ -0,0 +1,26 @@ +import fs from "fs" +import express from "express" +import path from "path" +import WikiConfig, { WikiEntry } from "./WikiConfig" + +const DIST_DIR = path.join(__dirname, "../dist") +if(!fs.existsSync(DIST_DIR)) throw new Error("Wiki dist directory not found") + +const app = express() +app.use(express.static(DIST_DIR)) + +app.use((req, res, next) => { + const urlPath = path.posix.normalize(req.path).replace(/^\//, "") + const wikiName = (urlPath.split("/")[0] ?? "").toLowerCase() + + if (!WikiConfig.hasWiki(wikiName)) { + return res.status(404).send("Wiki not found") + } + + next() +}) + +const port = 3000 +app.listen(port, () => { + console.log(`Server running on http://localhost:${port}`) +}) diff --git a/main/theme/index.ts b/main/theme/index.ts new file mode 100644 index 0000000..101caea --- /dev/null +++ b/main/theme/index.ts @@ -0,0 +1,16 @@ +// https://vitepress.dev/guide/custom-theme +import { h } from "vue" +import { useRoute, useRouter, type Theme } from "vitepress" +import DefaultTheme from "vitepress/theme" +import "./style.css" + +export default { + extends: DefaultTheme, + Layout: () => { + return h(DefaultTheme.Layout, null, { + // https://vitepress.dev/guide/extending-default-theme#layout-slots + }) + }, + enhanceApp({ app, router, siteData }) { + }, +} satisfies Theme diff --git a/main/theme/style.css b/main/theme/style.css new file mode 100644 index 0000000..9648022 --- /dev/null +++ b/main/theme/style.css @@ -0,0 +1,130 @@ +/** + * Customize default theme styling by overriding CSS variables: + * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css + */ + +/** + * Colors + * + * Each colors have exact same color scale system with 3 levels of solid + * colors with different brightness, and 1 soft color. + * + * - `XXX-1`: The most solid color used mainly for colored text. It must + * satisfy the contrast ratio against when used on top of `XXX-soft`. + * + * - `XXX-2`: The color used mainly for hover state of the button. + * + * - `XXX-3`: The color for solid background, such as bg color of the button. + * It must satisfy the contrast ratio with pure white (#ffffff) text on + * top of it. + * + * - `XXX-soft`: The color used for subtle background such as custom container + * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors + * on top of it. + * + * The soft color must be semi transparent alpha channel. This is crucial + * because it allows adding multiple "soft" colors on top of each other + * to create a accent, such as when having inline code block inside + * custom containers. + * + * - `default`: The color used purely for subtle indication without any + * special meanings attched to it such as bg color for menu hover state. + * + * - `brand`: Used for primary brand colors, such as link text, button with + * brand theme, etc. + * + * - `tip`: Used to indicate useful information. The default theme uses the + * brand color for this by default. + * + * - `warning`: Used to indicate warning to the users. Used in custom + * container, badges, etc. + * + * - `danger`: Used to show error, or dangerous message to the users. Used + * in custom container, badges, etc. + * -------------------------------------------------------------------------- */ + +:root { + --vp-c-default-1: var(--vp-c-gray-1); + --vp-c-default-2: var(--vp-c-gray-2); + --vp-c-default-3: var(--vp-c-gray-3); + --vp-c-default-soft: var(--vp-c-gray-soft); + + --vp-c-brand-1: var(--vp-c-indigo-1); + --vp-c-brand-2: var(--vp-c-indigo-2); + --vp-c-brand-3: var(--vp-c-indigo-3); + --vp-c-brand-soft: var(--vp-c-indigo-soft); + + --vp-c-tip-1: var(--vp-c-brand-1); + --vp-c-tip-2: var(--vp-c-brand-2); + --vp-c-tip-3: var(--vp-c-brand-3); + --vp-c-tip-soft: var(--vp-c-brand-soft); + + --vp-c-warning-1: var(--vp-c-yellow-1); + --vp-c-warning-2: var(--vp-c-yellow-2); + --vp-c-warning-3: var(--vp-c-yellow-3); + --vp-c-warning-soft: var(--vp-c-yellow-soft); + + --vp-c-danger-1: var(--vp-c-red-1); + --vp-c-danger-2: var(--vp-c-red-2); + --vp-c-danger-3: var(--vp-c-red-3); + --vp-c-danger-soft: var(--vp-c-red-soft); +} + +/** + * Component: Button + * -------------------------------------------------------------------------- */ + +:root { + --vp-button-brand-border: transparent; + --vp-button-brand-text: var(--vp-c-white); + --vp-button-brand-bg: var(--vp-c-brand-3); + --vp-button-brand-hover-border: transparent; + --vp-button-brand-hover-text: var(--vp-c-white); + --vp-button-brand-hover-bg: var(--vp-c-brand-2); + --vp-button-brand-active-border: transparent; + --vp-button-brand-active-text: var(--vp-c-white); + --vp-button-brand-active-bg: var(--vp-c-brand-1); +} + +/** + * Component: Home + * -------------------------------------------------------------------------- */ + +:root { + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff); + + --vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%); + --vp-home-hero-image-filter: blur(44px); +} + +@media (min-width: 640px) { + :root { + --vp-home-hero-image-filter: blur(56px); + } +} + +@media (min-width: 960px) { + :root { + --vp-home-hero-image-filter: blur(68px); + } +} + +/** + * Component: Custom Block + * -------------------------------------------------------------------------- */ + +:root { + --vp-custom-block-tip-border: transparent; + --vp-custom-block-tip-text: var(--vp-c-text-1); + --vp-custom-block-tip-bg: var(--vp-c-brand-soft); + --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); +} + +/** + * Component: Algolia + * -------------------------------------------------------------------------- */ + +.DocSearch { + --docsearch-primary-color: var(--vp-c-brand-1) !important; +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3dfb4b5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2617 @@ +{ + "name": "almostwiki-vite", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "express": "^4.19.2", + "zod": "^3.23.8" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "prettier": "^3.2.5", + "ts-node": "^10.9.2", + "vitepress": "^1.2.2", + "vue": "^3.4.27" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", + "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", + "@algolia/autocomplete-shared": "1.9.3" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", + "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", + "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-shared": "1.9.3" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", + "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "dev": true, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.23.3.tgz", + "integrity": "sha512-vRHXYCpPlTDE7i6UOy2xE03zHF2C8MEFjPN2v7fRbqVpcOvAUQK81x3Kc21xyb5aSIpYCjWCZbYZuz8Glyzyyg==", + "dev": true, + "dependencies": { + "@algolia/cache-common": "4.23.3" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.23.3.tgz", + "integrity": "sha512-h9XcNI6lxYStaw32pHpB1TMm0RuxphF+Ik4o7tcQiodEdpKK+wKufY6QXtba7t3k8eseirEMVB83uFFF3Nu54A==", + "dev": true + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.23.3.tgz", + "integrity": "sha512-yvpbuUXg/+0rbcagxNT7un0eo3czx2Uf0y4eiR4z4SD7SiptwYTpbuS0IHxcLHG3lq22ukx1T6Kjtk/rT+mqNg==", + "dev": true, + "dependencies": { + "@algolia/cache-common": "4.23.3" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.23.3.tgz", + "integrity": "sha512-hpa6S5d7iQmretHHF40QGq6hz0anWEHGlULcTIT9tbUssWUriN9AUXIFQ8Ei4w9azD0hc1rUok9/DeQQobhQMA==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.23.3.tgz", + "integrity": "sha512-LBsEARGS9cj8VkTAVEZphjxTjMVCci+zIIiRhpFun9jGDUlS1XmhCW7CTrnaWeIuCQS/2iPyRqSy1nXPjcBLRA==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.23.3.tgz", + "integrity": "sha512-l6EiPxdAlg8CYhroqS5ybfIczsGUIAC47slLPOMDeKSVXYG1n0qGiz4RjAHLw2aD0xzh2EXZ7aRguPfz7UKDKw==", + "dev": true, + "dependencies": { + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.23.3.tgz", + "integrity": "sha512-3E3yF3Ocr1tB/xOZiuC3doHQBQ2zu2MPTYZ0d4lpfWads2WTKG7ZzmGnsHmm63RflvDeLK/UVx7j2b3QuwKQ2g==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/client-search": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.23.3.tgz", + "integrity": "sha512-P4VAKFHqU0wx9O+q29Q8YVuaowaZ5EM77rxfmGnkHUJggh28useXQdopokgwMeYw2XUht49WX5RcTQ40rZIabw==", + "dev": true, + "dependencies": { + "@algolia/client-common": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/logger-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.23.3.tgz", + "integrity": "sha512-y9kBtmJwiZ9ZZ+1Ek66P0M68mHQzKRxkW5kAAXYN/rdzgDN0d2COsViEFufxJ0pb45K4FRcfC7+33YB4BLrZ+g==", + "dev": true + }, + "node_modules/@algolia/logger-console": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.23.3.tgz", + "integrity": "sha512-8xoiseoWDKuCVnWP8jHthgaeobDLolh00KJAdMe9XPrWPuf1by732jSpgy2BlsLTaT9m32pHI8CRfrOqQzHv3A==", + "dev": true, + "dependencies": { + "@algolia/logger-common": "4.23.3" + } + }, + "node_modules/@algolia/recommend": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.23.3.tgz", + "integrity": "sha512-9fK4nXZF0bFkdcLBRDexsnGzVmu4TSYZqxdpgBW2tEyfuSSY54D4qSRkLmNkrrz4YFvdh2GM1gA8vSsnZPR73w==", + "dev": true, + "dependencies": { + "@algolia/cache-browser-local-storage": "4.23.3", + "@algolia/cache-common": "4.23.3", + "@algolia/cache-in-memory": "4.23.3", + "@algolia/client-common": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/logger-common": "4.23.3", + "@algolia/logger-console": "4.23.3", + "@algolia/requester-browser-xhr": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/requester-node-http": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.23.3.tgz", + "integrity": "sha512-jDWGIQ96BhXbmONAQsasIpTYWslyjkiGu0Quydjlowe+ciqySpiDUrJHERIRfELE5+wFc7hc1Q5hqjGoV7yghw==", + "dev": true, + "dependencies": { + "@algolia/requester-common": "4.23.3" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.23.3.tgz", + "integrity": "sha512-xloIdr/bedtYEGcXCiF2muajyvRhwop4cMZo+K2qzNht0CMzlRkm8YsDdj5IaBhshqfgmBb3rTg4sL4/PpvLYw==", + "dev": true + }, + "node_modules/@algolia/requester-node-http": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.23.3.tgz", + "integrity": "sha512-zgu++8Uj03IWDEJM3fuNl34s746JnZOWn1Uz5taV1dFyJhVM/kTNw9Ik7YJWiUNHJQXcaD8IXD1eCb0nq/aByA==", + "dev": true, + "dependencies": { + "@algolia/requester-common": "4.23.3" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.23.3.tgz", + "integrity": "sha512-Wjl5gttqnf/gQKJA+dafnD0Y6Yw97yvfY8R9h0dQltX1GXTgNs1zWgvtWW0tHl1EgMdhAyw189uWiZMnL3QebQ==", + "dev": true, + "dependencies": { + "@algolia/cache-common": "4.23.3", + "@algolia/logger-common": "4.23.3", + "@algolia/requester-common": "4.23.3" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@docsearch/css": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.0.tgz", + "integrity": "sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ==", + "dev": true + }, + "node_modules/@docsearch/js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.6.0.tgz", + "integrity": "sha512-QujhqINEElrkIfKwyyyTfbsfMAYCkylInLYMRqHy7PHc8xTBQCow73tlo/Kc7oIwBrCLf0P3YhjlOeV4v8hevQ==", + "dev": true, + "dependencies": { + "@docsearch/react": "3.6.0", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.0.tgz", + "integrity": "sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-core": "1.9.3", + "@algolia/autocomplete-preset-algolia": "1.9.3", + "@docsearch/css": "3.6.0", + "algoliasearch": "^4.19.1" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", + "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", + "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", + "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", + "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", + "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", + "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", + "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", + "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", + "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", + "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", + "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", + "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", + "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", + "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", + "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", + "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.6.1.tgz", + "integrity": "sha512-CqYyepN4SnBopaoXYwng4NO8riB5ask/LTCkhOFq+GNGtr2X+aKeD767eYdqYukeixEUvv4bXdyTYVaogj7KBw==", + "dev": true + }, + "node_modules/@shikijs/transformers": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.6.1.tgz", + "integrity": "sha512-m/h2Dh99XWvTzHL8MUQmEnrB+/gxDljIfgDNR00Zg941KENqORx8Hi9sKpGYjCgXoEJKASZlEMQdPnkHj9/8aQ==", + "dev": true, + "dependencies": { + "shiki": "1.6.1" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", + "dev": true, + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.6.tgz", + "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "dev": true + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", + "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.27.tgz", + "integrity": "sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.24.4", + "@vue/shared": "3.4.27", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz", + "integrity": "sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==", + "dev": true, + "dependencies": { + "@vue/compiler-core": "3.4.27", + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.27.tgz", + "integrity": "sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.24.4", + "@vue/compiler-core": "3.4.27", + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.10", + "postcss": "^8.4.38", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.27.tgz", + "integrity": "sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==", + "dev": true, + "dependencies": { + "@vue/compiler-dom": "3.4.27", + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.2.1.tgz", + "integrity": "sha512-6oNCtyFOrNdqm6GUkFujsCgFlpbsHLnZqq7edeM/+cxAbMyCWvsaCsIMUaz7AiluKLccCGEM8fhOsjaKgBvb7g==", + "dev": true, + "dependencies": { + "@vue/devtools-kit": "^7.2.1" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.2.1.tgz", + "integrity": "sha512-Wak/fin1X0Q8LLIfCAHBrdaaB+R6IdpSXsDByPHbQ3BmkCP0/cIo/oEGp9i0U2+gEqD4L3V9RDjNf1S34DTzQQ==", + "dev": true, + "dependencies": { + "@vue/devtools-shared": "^7.2.1", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.2.1.tgz", + "integrity": "sha512-PCJF4UknJmOal68+X9XHyVeQ+idv0LFujkTOIW30+GaMJqwFVN9LkQKX4gLqn61KkGMdJTzQ1bt7EJag3TI6AA==", + "dev": true, + "dependencies": { + "rfdc": "^1.3.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.27.tgz", + "integrity": "sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==", + "dev": true, + "dependencies": { + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.27.tgz", + "integrity": "sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==", + "dev": true, + "dependencies": { + "@vue/reactivity": "3.4.27", + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.27.tgz", + "integrity": "sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==", + "dev": true, + "dependencies": { + "@vue/runtime-core": "3.4.27", + "@vue/shared": "3.4.27", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.27.tgz", + "integrity": "sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==", + "dev": true, + "dependencies": { + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27" + }, + "peerDependencies": { + "vue": "3.4.27" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.27.tgz", + "integrity": "sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==", + "dev": true + }, + "node_modules/@vueuse/core": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz", + "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==", + "dev": true, + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/integrations": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-10.9.0.tgz", + "integrity": "sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q==", + "dev": true, + "dependencies": { + "@vueuse/core": "10.9.0", + "@vueuse/shared": "10.9.0", + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "*", + "axios": "*", + "change-case": "*", + "drauu": "*", + "focus-trap": "*", + "fuse.js": "*", + "idb-keyval": "*", + "jwt-decode": "*", + "nprogress": "*", + "qrcode": "*", + "sortablejs": "*", + "universal-cookie": "*" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/integrations/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz", + "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz", + "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==", + "dev": true, + "dependencies": { + "vue-demi": ">=0.14.7" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/algoliasearch": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.23.3.tgz", + "integrity": "sha512-Le/3YgNvjW9zxIQMRhUHuhiUjAlKY/zsdZpfq4dlLqg6mEm0nL6yk+7f2hDOtLpxsgE4jSzDmvHL7nXdBp5feg==", + "dev": true, + "dependencies": { + "@algolia/cache-browser-local-storage": "4.23.3", + "@algolia/cache-common": "4.23.3", + "@algolia/cache-in-memory": "4.23.3", + "@algolia/client-account": "4.23.3", + "@algolia/client-analytics": "4.23.3", + "@algolia/client-common": "4.23.3", + "@algolia/client-personalization": "4.23.3", + "@algolia/client-search": "4.23.3", + "@algolia/logger-common": "4.23.3", + "@algolia/logger-console": "4.23.3", + "@algolia/recommend": "4.23.3", + "@algolia/requester-browser-xhr": "4.23.3", + "@algolia/requester-common": "4.23.3", + "@algolia/requester-node-http": "4.23.3", + "@algolia/transporter": "4.23.3" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/focus-trap": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", + "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "dev": true, + "dependencies": { + "tabbable": "^6.2.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minisearch": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-6.3.0.tgz", + "integrity": "sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==", + "dev": true + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.21.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.21.0.tgz", + "integrity": "sha512-aQAIxtzWEwH8ou+OovWVSVNlFImL7xUCwJX3YMqA3U8iKCNC34999fFOnWjYNsylgfPgMexpbk7WYOLtKr/mxg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, + "node_modules/rollup": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", + "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.17.2", + "@rollup/rollup-android-arm64": "4.17.2", + "@rollup/rollup-darwin-arm64": "4.17.2", + "@rollup/rollup-darwin-x64": "4.17.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", + "@rollup/rollup-linux-arm-musleabihf": "4.17.2", + "@rollup/rollup-linux-arm64-gnu": "4.17.2", + "@rollup/rollup-linux-arm64-musl": "4.17.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", + "@rollup/rollup-linux-riscv64-gnu": "4.17.2", + "@rollup/rollup-linux-s390x-gnu": "4.17.2", + "@rollup/rollup-linux-x64-gnu": "4.17.2", + "@rollup/rollup-linux-x64-musl": "4.17.2", + "@rollup/rollup-win32-arm64-msvc": "4.17.2", + "@rollup/rollup-win32-ia32-msvc": "4.17.2", + "@rollup/rollup-win32-x64-msvc": "4.17.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/search-insights": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.13.0.tgz", + "integrity": "sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==", + "dev": true, + "peer": true + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shiki": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.6.1.tgz", + "integrity": "sha512-1Pu/A1rtsG6HZvQm4W0NExQ45e02og+rPog7PDaFDiMumZgOYnZIu4JtGQeAIfMwdbKSjJQoCUr79vDLKUUxWA==", + "dev": true, + "dependencies": { + "@shikijs/core": "1.6.1" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", + "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitepress": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.2.2.tgz", + "integrity": "sha512-uZ3nXR5NY4nYj3RJWCo5jev9qlNZAQo5SUXu1U0QSUx84cUm/o7hCTDVjZ4njVSVui+PsV1oAbdQOg8ygbaf4w==", + "dev": true, + "dependencies": { + "@docsearch/css": "^3.6.0", + "@docsearch/js": "^3.6.0", + "@shikijs/core": "^1.5.2", + "@shikijs/transformers": "^1.5.2", + "@types/markdown-it": "^14.1.1", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/devtools-api": "^7.2.0", + "@vue/shared": "^3.4.27", + "@vueuse/core": "^10.9.0", + "@vueuse/integrations": "^10.9.0", + "focus-trap": "^7.5.4", + "mark.js": "8.11.1", + "minisearch": "^6.3.0", + "shiki": "^1.5.2", + "vite": "^5.2.11", + "vue": "^3.4.27" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.27.tgz", + "integrity": "sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==", + "dev": true, + "dependencies": { + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-sfc": "3.4.27", + "@vue/runtime-dom": "3.4.27", + "@vue/server-renderer": "3.4.27", + "@vue/shared": "3.4.27" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..314b449 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "scripts": { + "dev": "vitepress dev", + "build": "vitepress build", + "preview": "vitepress preview", + "prettier:check": "prettier --check .", + "prettier:write": "prettier --write .", + "build:static": "ts-node main/build_wikis.ts", + "serve:static": "ts-node main/start_dev_server.ts" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "prettier": "^3.2.5", + "ts-node": "^10.9.2", + "vitepress": "^1.2.2", + "vue": "^3.4.27" + }, + "dependencies": { + "express": "^4.19.2", + "zod": "^3.23.8" + } +} diff --git a/wikis.json b/wikis.json new file mode 100644 index 0000000..2d72e52 --- /dev/null +++ b/wikis.json @@ -0,0 +1,10 @@ +{ + "wikis": [ + { + "name": "lootjs" + }, + { + "name": "morejs" + } + ] +} diff --git a/wikis/lootjs/.vitepress/config.mts b/wikis/lootjs/.vitepress/config.mts new file mode 100644 index 0000000..03fec6c --- /dev/null +++ b/wikis/lootjs/.vitepress/config.mts @@ -0,0 +1,47 @@ +import { defineConfig } from "../../../main/defineAlmostWiki"; + +export default defineConfig({ + srcDir: "./docs", + base: "/lootjs/", + themeConfig: { + sidebar: [ + { + text: "Intro", + items: [ + { text: "Getting Started", link: "/" }, + { text: "Event difference", link: "/difference" }, + ], + }, + { + text: "Loot Tables", + items: [ + { text: "Event Overview", link: "/loot-tables/event" }, + { text: "Modify your first loot table", link: "/loot-tables/modify-loot-table" }, + { text: "Create your first loot table", link: "/loot-tables/create-loot-table" }, + ], + }, + { + text: "Loot Modifiers", + items: [ + { text: "Event Overview", link: "/loot-modifiers/event" }, + ], + }, + { + text: "API", + items: [ + { text: "ItemFilter", link: "/api/item-filter" }, + { text: "LootTable", link: "/api/loot-table" }, + { text: "LootPool", link: "/api/loot-pool" }, + { text: "LootEntry", link: "/api/loot-entry" }, + { text: "LootEntryTransformer", link: "/api/loot-entries-transformer" }, + { text: "LootConditions", link: "/api/loot-condition" }, + { text: "LootFunctions", link: "/api/loot-function" }, + { text: "LootModifier", link: "/api/loot-modifier" }, + { text: "LootContext", link: "/api/loot-context" }, + { text: "NumberProvider", link: "/api/number-provider" }, + { text: "Bounds", link: "/api/bounds" }, + ], + }, + ], + }, +}) diff --git a/wikis/lootjs/.vitepress/theme/index.ts b/wikis/lootjs/.vitepress/theme/index.ts new file mode 100644 index 0000000..c70c4b6 --- /dev/null +++ b/wikis/lootjs/.vitepress/theme/index.ts @@ -0,0 +1,3 @@ +// https://vitepress.dev/guide/custom-theme +import Theme from "../../../../main/theme" +export default Theme diff --git a/wikis/lootjs/docs/api/bounds.md b/wikis/lootjs/docs/api/bounds.md new file mode 100644 index 0000000..84ae60f --- /dev/null +++ b/wikis/lootjs/docs/api/bounds.md @@ -0,0 +1,25 @@ +# Bounds + +While working with LootJS we often need to specify a bounding. For these cases we have `Bounds`. Bounds are similar to `NumberProvider` but with the difference, that bounds don't generate a random value but instead they test if the value is within the bounds. + +When a function requires either `Bounds` we can easily rely on automatically type wrapping by passing directly a `number` or `number[]` to the function. + +## Bounds + +- Syntax: + - `Bounds.exactly(value: number)` + - `Bounds.atLeast(value: number)` + - `Bounds.atMost(value: number)` + - `Bounds.between(min: number, max: number)` + +```js +const condition = LootCondition.distance(10) // exactly 10 +``` + +```js +const condition = LootCondition.distance([0, 10]) // between 0 and 10 +``` + +```js +const condition = LootCondition.distance(Bounds.atLeast(20)) // at least 20 +``` diff --git a/wikis/lootjs/docs/api/item-filter.md b/wikis/lootjs/docs/api/item-filter.md new file mode 100644 index 0000000..f61ffc0 --- /dev/null +++ b/wikis/lootjs/docs/api/item-filter.md @@ -0,0 +1,250 @@ +# ItemFilter + +Item filters are an essential utility in LootJS for filtering how items should be handled. It's mostly used when removing items or if we want to match specific conditions e. g the main hand of the player. + +Everywhere where you can use `ItemFilter` as an argument, you can also simply pass an item id as string or a tag. LootJS will automatically creates the `ItemFilter`. + +## `armor` + +Matches if the item is an armor item. +::: info +Some mods may create their own `armor` typed items without using the vanilla armor system. For these items, this filter will never match. +::: + +- Syntax: + - `ItemFilter.ARMOR` + +## `blockItem` + +Matches if the item is a block item. Block items are items that can be placed as a block. +::: item +Mods may use their own implementation of block items, so this filter may not match. +::: + +- Syntax: + - `ItemFilter.BLOCK_ITEM` + +## `custom` + +Creates a custom item filter. You can use it to create your own item filters. + +- Syntax: + - `ItemFilter.custom(filter: (item: ItemStack) => boolean)` + +```js +ItemFilter.custom((item) => item.id === "minecraft:apple") + +ItemFilter.custom((item) => { + if (item.hasTag("#c:ores")) { + return true + } + + return item.count > 16 +}) +``` + +## `damageable` + +Matches if the item can be damaged. + +- Syntax: + - `ItemFilter.DAMAGEABLE` + +## `damaged` + +Matches if the item is already damaged. + +- Syntax: + - `ItemFilter.DAMAGED` + +## `edible` + +Matches if the item can be eaten. + +- Syntax: + - `ItemFilter.EDIBLE` + +## `enchanted` + +Matches if the item is already enchanted. + +- Syntax: + - `ItemFilter.ENCHANTED` + +## `empty` + +Checks if the item is empty. + +- Syntax: + - `ItemFilter.EMPTY` + +## `equipmentSlot` + +Matches if item has a specific equipment slot. Existing slots: `"mainhand"`, `"offhand"`, `"head"`, `"chest"`, `"legs"`, `"feet"`. + +- Syntax: + - `ItemFilter.equipmentSlot(slot: string | EquipmentSlot)` + +```js +ItemFilter.equipmentSlot("mainhand") +``` + +## `equipmentSlotGroup` + +Matches if an item is in a specific equipment group. Existing groups: `"any"`, `"mainhand"`, `"offhand"`, `"hand"`, `"feet"`, `"legs"`, `"chest"`, `"head"`, `"armor"` + +- Syntax: + - `ItemFilter.equipmentSlotGroup(slot: string | EquipmentSlotGroup)` + +```js +ItemFilter.equipmentSlot("armor") +``` + +## `hasEnchantment` + +Used to check if given item matches the enchantments. + +- Syntax: + - `ItemFilter.hasEnchantment(filter)` + - `ItemFilter.hasEnchantment(filter, levelBound: Bounds)`, _see [Bounds]_ + +```js +ItemFilter.hasEnchantment("minecraft:fortune") + +// matches all enchantments from `minecraft` +ItemFilter.hasEnchantment("@minecraft") + +// matches if any of the enchantments are present +ItemFilter.hasEnchantment(["minecraft:fortune", "minecraft:mending"]) + +// matches if `unbreaking` is at least level 2 and at most level 3 +ItemFilter.hasEnchantment("minecraft:unbreaking", [2, 3]) +``` + +## `hasStoredEnchantment` + +Used to check if given book item matches the enchantments. In minecraft `books` do store the enchantments differently. + +- Syntax: + - `ItemFilter.hasStoredEnchantment(filter)` + - `ItemFilter.hasStoredEnchantment(filter, levelBound: Bounds)`, _see [Bounds]_ + +```js +ItemFilter.hasStoredEnchantment("minecraft:fortune") + +// matches all enchantments from `minecraft` +ItemFilter.hasStoredEnchantment("@minecraft") + +// matches if any of the enchantments are present +ItemFilter.hasStoredEnchantment(["minecraft:fortune", "minecraft:mending"]) + +// matches if `unbreaking` is at least level 2 and at most level 3 +ItemFilter.hasStoredEnchantment("minecraft:unbreaking", [2, 3]) +``` + +## `item` + +Matches if the item matches. This will not check for count but may check against components. + +- Syntax: + - `ItemFilter.item(item: ItemStack | string)` + - `ItemFilter.item(item: ItemStack | string, matchComponents: boolean)` + +```js +ItemFilter.item("minecraft:diamond") +``` + +## `not`/`negate` + +Inverts the filter. Matches if the filter does not match. + +- Syntax: + - `ItemFilter.not(filter: ItemFilter)` + - `myFilter.negate()` + +```js +ItemFilter.not(ItemFilter.hasEnchantment("minecraft:fortune")) + +ItemFilter.hasEnchantment("minecraft:fortune").negate() +``` + +## `tag` + +Matches if item has a specific tag. + +- Syntax: + - `ItemFilter.tag(tag: string)` + +```js +ItemFilter.tag("#c:ores") +``` + +## `toolAction` + +`NeoForge` adds something called `ToolAction`, which can be used to determine if an item can do specific things. Some mods uses this for multi-tools. + +It will match if all actions are present. + +- Syntax: + - `ItemFilter.toolAction(...action)` + - `ItemFilter.anyToolAction(...action)` + +```js +ItemFilter.toolAction("pickaxe_dig") + +// We can also match multiple actions. +ItemFilter.toolAction("pickaxe_dig", "shovel_dig") +``` + +```js +ItemFilter.anyToolAction("pickaxe_dig") + +// We can also match multiple actions. +ItemFilter.anyToolAction("pickaxe_dig", "shovel_dig") +``` + +## Groups + +### `allOf` + +Combines multiple item filters into one. Matches if all filters match. + +- Syntax: + - `ItemFilter.allOf(...filters: ItemFilter[])` + +```js +ItemFilter.allOf( + ItemFilter.hasEnchantment("minecraft:fortune"), + ItemFilter.equipmentSlotGroup("hand"), +) +``` + +### `anyOf` + +Combines multiple item filters into one. Matches if any filter matches. + +- Syntax: + - `ItemFilter.anyOf(...filters: ItemFilter[])` + +```js +ItemFilter.anyOf( + ItemFilter.hasEnchantment("minecraft:silk_touch"), + ItemFilter.equipmentSlotGroup("armor"), +) +``` + +### `all` + +Returns an item filter that matches everything. + +- Syntax: + - `ItemFilter.ALL` + +### `none` + +Returns an item filter that matches nothing. + +- Syntax: + - `ItemFilter.NONE` + +[Bounds]: /api/bounds diff --git a/wikis/lootjs/docs/api/loot-condition.md b/wikis/lootjs/docs/api/loot-condition.md new file mode 100644 index 0000000..8d5d27c --- /dev/null +++ b/wikis/lootjs/docs/api/loot-condition.md @@ -0,0 +1,547 @@ +# Conditions + +While conditions can be used in different ways, from now on the examples on this page will shown with `LootEntries` but they can easily be used in other places. + +## `matchTool` + +Matches the tool, the player used to destroy the block. This is only set when destroying blocks. When working with block loot, prefer `matchTool` over `matchMainHand`. + +- Syntax: + - `.matchTool(filter: ItemPredicate | ItemFilter | Item)`_, see [ItemFilter] & [ItemPredicate]_ + - `LootCondition.matchTool(filter: ItemPredicate | ItemFilter | Item)` + +## `matchMainHand` + +Matches the main hand item of the player by given [ItemFilter] or [Ingredient] + +- Syntax: + - `.matchMainHand(filter: ItemFilter | Item)`_, see [ItemFilter]_ + - `LootCondition.matchMainHand(filter: ItemFilter | Item)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchMainHand("#minecraft:pickaxes") +}) +``` + +## `matchOffHand` + +Matches the off hand item of the player by given [ItemFilter] or [Ingredient] + +- Syntax: + - `.matchOffHand(filter: ItemFilter | Item)`_, see [ItemFilter]_ + - `LootCondition.matchOffHand(filter: ItemFilter | Item)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchOffHand("#minecraft:pickaxes") +}) +``` + +## `matchEquip` + +Matches the equipment from a slot of the player by given [ItemFilter] or [Ingredient].
+Possible slots are: `"mainhand"`, `"offhand"`, `"head"`, `"chest"`, `"legs"`, `"feet"`. + +- Syntax: + - `.matchEquip(slot, filter: ItemFilter | Item)`_, see [ItemFilter]_ + - `LootCondition.matchEquip(slot, filter: ItemFilter | Item)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchEquip("mainhand", "#minecraft:pickaxes") +}) +``` + +## `survivesExplosion` + +Matches if the item survives an explosion. Calculated by probability of `random_number < (1 / explosion_radius)`, where `random_number` is a random generated number between 0 and 1. If no explosion happens, it will always survive. + +- Syntax: + - `.survivesExplosion()` + - `LootCondition.survivesExplosion()` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.survivesExplosion() +}) +``` + +## `checkTime` + +Compares the current day time (`24000 * day_count + day_time`) against given values. + +- Syntax: + - `.checkTime(min: number, max: number)` + - `.checkTime(period: number, min: number, max: number)` + - `LootCondition.checkTime(min: number, max: number)` + - `LootCondition.checkTime(period: number, min: number, max: number)`
+ If period is provided, `day_time` will be reduced modulo by given `period`. Setting this to _24000_ simulates a full day check. _Default is 24000, if not provided_ + +```js +LootEntry.of("minecraft:diamond").when((c) => { + // Will match if the current day time is between 0 and 9000. + c.checkTime(0, 9000) +}) +``` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + // Will match the first day of the week. (If we go with 7 days per minecraft "week") + c.checkTime(24000 * 7, 0, 24000) +}) +``` + +## `weatherCheck` + +Matches the current weather + +- Syntax: + - `.weatherCheck(isRaining: boolean | null, isThundering: boolean | null)` + - `LootCondition.weatherCheck(isRaining: boolean | null, isThundering: boolean | null)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.weatherCheck(true, false) // Matches if it is raining and not thundering +}) +``` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.weatherCheck(true, null) // Matches if it is raining +}) +``` + +## `randomChance` + +Matches if a random number between 0 and 1 is lower than the given value + +- Syntax: + - `.randomChance(chance: number)` + - `LootCondition.randomChance(chance: number)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.randomChance(0.5) // 50% chance +}) +``` + +## `randomTableBonus` + +Passes with probability picked from a list of probabilities, indexed by enchantment power. Mainly used for block drops, because a `tool` is required. + +- Syntax: + - `LootCondition.randomTableBonus(enchantment: Enchantment, probabilities: number[])` + +```js +LootEntry.of("minecraft:diamond").randomTableBonus( + "minecraft:fortune", + [0, 0.33, 0.66, 1.0], +) +``` + +## `randomChanceWithEnchantment` + +Passes with probability picked from a list of probabilities, indexed by enchantment power. Mainly used for fishing and entity drops, because an `attacker` is required. + +- Syntax: + - `.randomChanceWithEnchantment(chance: number, probabilities: number[])` + - `LootCondition.randomChanceWithEnchantment(chance: number, probabilities: number[])` + +```js +LootEntry.of("minecraft:diamond").randomChanceWithEnchantment( + "minecraft:looting", + [0, 0.33, 0.66, 1.0], +) +``` + +## `biome` + +Matches if the player is in the given biome + +- Syntax: + - `.biome(...biomes: id | tag)` + - `LootCondition.biome(...biomes: id | tag)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.biome("minecraft:jungle") +}) +``` + +## `anyBiome` + +Matches if the player is in one of the given biomes + +- Syntax: + - `.anyBiome(...biome: id | tag)` + - `LootCondition.anyBiome(...biome: id | tag)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.anyBiome("minecraft:jungle", "#minecraft:is_forest") +}) +``` + +## `anyDimension` + +Matches if the player is in one of the given dimensions + +- Syntax: + - `.anyDimension(...dimension: id | tag)` + - `LootCondition.anyDimension(...dimension: id | tag)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.anyDimension("minecraft:overworld") +}) +``` + +## `anyStructure` + +Matches if the player is in one of the given structures.
+If `exact` is set to `true`, it will check if the player is inside the structure parts (like houses in a village). Otherwise it will just check if the player is within the structure bounds. + +- Syntax: + - `.anyStructure(structure: (id | tag)[], exact: boolean)` + - `LootCondition.anyStructure(structure: (id | tag)[], exact: boolean)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.anyStructure(["minecraft:stronghold", "minecraft:village"], false) +}) +``` + +## `lightLevel` + +Matches if the player is in the given light level + +- Syntax: + - `.lightLevel(min: number, max: number)` + - `LootCondition.lightLevel(min: number, max: number)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.lightLevel(0, 15) +}) +``` + +## `luck` + +Matches if the player has the given luck level + +- Syntax: + - `.luck(level: Bounds)` + - `LootCondition.luck(level: Bounds)` + +## `killedByPlayer` + +Matches if an entity was killed by the player + +- Syntax: + - `.killedByPlayer()` + - `LootCondition.killedByPlayer()` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.killedByPlayer() +}) +``` + +## `matchEntity` + +Matches against the entity that died, opened the chest or destroyed the block. + +- Syntax: + - `.matchEntity(predicate: EntityPredicate)`_, see [EntityPredicate]_ + - `LootCondition.matchEntity(predicate: EntityPredicate)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchEntity(Predicates.entity().isCrouching(true)) +}) +``` + +## `matchDirectKiller` + +Matches against the direct entity which caused the death, e.g. the arrow entity, not the shooter. + +- Syntax: + - `.matchDirectKiller(predicate: EntityPredicate)`_, see [EntityPredicate]_ + - `LootCondition.matchDirectKiller(predicate: EntityPredicate)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchDirectKiller(Predicates.entity().isCrouching(true)) +}) +``` + +## `matchKiller` + +Matches against the entity which caused the death. + +- Syntax: + - `.matchKiller(predicate: EntityPredicate)`_, see [EntityPredicate]_ + - `LootCondition.matchKiller(predicate: EntityPredicate)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchKiller(Predicates.entity().isCrouching(true)) +}) +``` + +## `matchPlayer` + +Matches against the player. If a player kills another player, it will check against the killer. + +- Syntax: + - `.matchPlayer(predicate: EntityPredicate)`_, see [EntityPredicate]_ + - `LootCondition.matchPlayer(predicate: EntityPredicate)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchPlayer(Predicates.entity().isCrouching(true)) +}) +``` + +## `customPlayerCheck` + +Custom callback predicate to check the player. The callback **must** return either `true` or `false`. + +- Syntax: + - `.customPlayerCheck((player) => {})`_, where player is the actual player_ + - `LootCondition.customPlayerCheck((player) => {})` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.customPlayerCheck((player) => { + // We are working with the actual player here + return player.getMaxHealth() > 20 + }) +}) +``` + +## `customEntityCheck` + +Custom callback predicate to check the entity. The callback **must** return either `true` or `false`. + +- Syntax: + - `.customEntityCheck((entity) => {})`_, where entity is the actual entity_ + - `LootCondition.customEntityCheck((entity) => {})` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.customEntityCheck((entity) => { + // We are working with the actual entity here + return entity.getMaxHealth() > 20 + }) +}) +``` + +## `customKillerCheck` + +Custom callback predicate to check the killer. The callback **must** return either `true` or `false`. + +- Syntax: + - `.customKillerCheck((entity) => {})`_, where entity is the actual entity_ + - `LootCondition.customKillerCheck((entity) => {})` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.customKillerCheck((entity) => { + // We are working with the actual entity here + return entity.getMaxHealth() > 20 + }) +}) +``` + +## `customDirectKillerCheck` + +Custom callback predicate to check the direct killer. The callback **must** return either `true` or `false`. + +- Syntax: + - `.customDirectKillerCheck((entity) => {})`_, where entity is the actual entity_ + - `LootCondition.customDirectKillerCheck((entity) => {})` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.customDirectKillerCheck((entity) => { + // We are working with the actual entity here + return entity.getMaxHealth() > 20 + }) +}) +``` + +## `matchDamageSource` + +Matches if the damage source is of the given type + +- Syntax: + - `.matchDamageSource(predicate: DamageSourcePredicate)` _, see [DamageSourcePredicate]_ + - `LootCondition.matchDamageSource(predicate: DamageSourcePredicate)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchDamageSource( + Predicates.damageSource() + .is("minecraft:falling_block") + .isNot("minecraft:magic") + .direct(Predicates.entity().isCrouching(true)) + .source(Predicates.entity().isCrouching(true)), + ) +}) +``` + +## `distance` + +Matches if the player is within the given distance + +- Syntax: + - `.distance(distance: Bounds)`_, see [Bounds]_ + - `LootCondition.distance(distance: Bounds)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.distance(10) +}) +``` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.distance(0, 100) +}) +``` + +## `customDistance` + +Matches if the player is within the given distance + +- Syntax: + - `.customDistance(predicate: DistancePredicate)`_, see [DistancePredicate]_ + - `LootCondition.customDistance(predicate: DistancePredicate)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.customDistance(Predicate.distance().absolute(Bounds.atLeast(50))) +}) +``` + +## `blockEntity` + +Match the given block entity. Must return either `true` or `false`. + +- Syntax: + - `.blockEntity((blockEntity) => {})` + - `LootCondition.blockEntity((blockEntity) => {})` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.blockEntity((blockEntity) => { + // We are working with the actual block entity here. + // Return either true or false to match or not + }) +}) +``` + +## `matchAllOf` + +Will match if all the given conditions match. False otherwise. + +- Syntax: + - `.matchAllOf((container) => {})` + - `LootCondition.matchAllOf(condition1, condition2, ...)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchAllOf((conditions) => { + conditions.matchMainHand("#minecraft:pickaxes") + .randomChance(0.5) + .survivesExplosion() + .biome(#minecraft:forest); + }); +}); +``` + +Using `LootCondition.matchAllOf` directly to create the condition. + +```js +const ourAndCondition = LootCondition.matchAllOf( + LootCondition.matchMainHand("#minecraft:pickaxes"), + LootCondition.randomChance(0.5), + LootCondition.survivesExplosion(), + LootCondition.biome("#minecraft:forest"), +) + +LootEntry.of("minecraft:diamond").when((c) => { + c.addCondition(ourAndCondition) +}) +``` + +## `matchAnyOf` + +Will match if one of the given conditions match. False otherwise. + +- Syntax: + - `.matchAnyOf((container) => {})` + - `LootCondition.matchAnyOf(condition1, condition2, ...)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.matchAnyOf((conditions) => { + conditions + .matchMainHand("#minecraft:pickaxes") + .randomChance(0.5) + .survivesExplosion() + .biome("#minecraft:forest") + }) +}) +``` + +Using `LootCondition.matchAnyOf` directly to create the condition. + +```js +const ourOrCondition = LootCondition.matchAnyOf( + LootCondition.matchMainHand("#minecraft:pickaxes"), + LootCondition.randomChance(0.5), + LootCondition.survivesExplosion(), + LootCondition.biome("#minecraft:forest"), +) + +LootEntry.of("minecraft:diamond").when((c) => { + c.addCondition(ourOrCondition) +}) +``` + +## `jsonCondition` + +Create a condition directly from JSON. This is useful to load conditions from other mods. + +- Syntax: + - `.jsonCondition(json)` + - `LootCondition.fromJson(json)` + +```js +LootEntry.of("minecraft:diamond").when((c) => { + c.jsonCondition({ + condition: "minecraft:match_tool", + predicate: { + enchantments: [ + { + enchantment: "minecraft:silk_touch", + levels: { + min: 1, + }, + }, + ], + }, + }) +}) +``` + +[EntityPredicate]: /api/predicates#entity-predicate +[ItemPredicate]: /api/predicates#item-predicate +[DamageSourcePredicate]: /api/predicates#damagesource-predicate +[DistancePredicate]: /api/predicates#distance-predicate +[ItemFilter]: /api/item-filter +[Ingredient]: https://wiki.latvian.dev +[Bounds]: /api/bounds diff --git a/wikis/lootjs/docs/api/loot-context.md b/wikis/lootjs/docs/api/loot-context.md new file mode 100644 index 0000000..e9e82f7 --- /dev/null +++ b/wikis/lootjs/docs/api/loot-context.md @@ -0,0 +1,133 @@ +# LootContext + +A loot context contains all information of the current rolled loot table. You can retrieve information about the block which was destroyed, the entity which was killed, etc. + +## `getId` + +Get the id of the loot table which was rolled. + +- Syntax: + - `.getId()` + - `.id` + +## `isType` + +Checks the type of the loot table. Valid types are `chest`, `block`, `entity`, `fishing`, `archaeology`, `gift`, `vault`, `shearing`, `piglin_barter` + +- Syntax: + - `.isType(type: LootType)` + +## `getType` + +Get the type of the loot table which was rolled. + +- Syntax: + - `.getType()` + - `.type` + +## `getPosition` + +Get the position where the loot table was rolled. When opening a chest it's the position of the chest, when killing an entity it's the position of the entity, etc. + +- Syntax: + - `.getPosition()`, returns a `Vec3` with `x`, `y` and `z` values + - `.position` + +## `getEntity` + +May return `null`, depending on the type of the loot table. + +- Syntax: + - `.getEntity()` + - `.entity` + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("chest").customAction((context, loot) => { + console.log(context.entity) + }) +}) +``` + +## `getAttackingEntity` + +May return `null`, depending on the type of the loot table. + +- Syntax: + - `.getAttackingEntity()` + - `.attackingEntity` + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("entity").customAction((context, loot) => { + console.log(context.attackingEntity) + }) +}) +``` + +## `getDamageSource` + +May return `null`, depending on the type of the loot table. + +- Syntax: + - `.getDamageSource()` + - `.damageSource` + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("entity").customAction((context, loot) => { + console.log(context.damageSource) + }) +}) +``` + +## `getTool` + +- Syntax: + - `.getTool()` + - `.tool` + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("block").customAction((context, loot) => { + console.log(context.tool) + }) +}) +``` + +## `isExploded` + +- Syntax: + - `.isExploded()` + +## `getExplosionRadius` + +- Syntax: + - `.getExplosionRadius()` + - `.explosionRadius` + +## `getRandom` + +Can be used for further randomization. + +- Syntax: + - `.getRandom()` + - `.random` + +## `getLuck` + +- Syntax: + - `.getLuck()` + - `.luck` + +## `getLevel` + +- Syntax: + - `.getLevel()` + - `.level` + +## `getServer` + +- Syntax: + - `.getServer()` + - `.server` diff --git a/wikis/lootjs/docs/api/loot-entries-transformer.md b/wikis/lootjs/docs/api/loot-entries-transformer.md new file mode 100644 index 0000000..483f3fd --- /dev/null +++ b/wikis/lootjs/docs/api/loot-entries-transformer.md @@ -0,0 +1,149 @@ +# LootEntryTransformer + +`LootEntryTransformer` allows you to modify, replace or remove loot entries inside a loot table. It adds multiple functions to fit the needs of different use-cases. + +Every class that implements `LootEntryTransformer` can use all listed functions in this chapter. + +Following classes do implement `LootEntryTransformer`: + +- [`LootTable`](/api/loot-table) +- [`LootPool`](/api/loot-pool) +- [`CompositeLootEntry`](/api/loot-entry) + +With `CompositeLootEntry` it's possible to have nested entries as a `CompositeLootEntry` can contain multiple other `CompositeLootEntry`. For this all functions provide a `deep` parameter that will traverse all nested entries and take action on them. If you don't want this, you can just pass `false` to the function. If `deep` is not set, it will be set to `true` by default. + +As an example, using `removeItem` on a loot table will travers through all loot pools and through all entries inside them and remove all matching items. + +## `removeItem` + +Removes all `LootEntry` of type `LootItemEntry`. + +- Syntax: + - `.removeItem(filter: ItemFilter)`, _see [ItemFilter]_ + - `.removeItem(filter: ItemFilter, deepRemove: boolean)` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .removeItem(ItemFilter.hasEnchantment("minecraft:fortune")) +}) +``` + +We also can just use a simple item id. LootJS will automatically convert it into an `ItemFilter`. + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .removeItem("minecraft:diamond") +}) +``` + +## `removeTag` + +Removes all `LootEntry` of type `LootTagEntry`. + +- Syntax: + - `.removeTag(tag: string)` + - `.removeTag(tag: string, deepRemove: boolean)` + +```js +LootJS.lootTables((event) => { + event.modifyLootTypeTables("chest").removeTag("#c:ores") +}) +``` + +## `removeReference` + +Removes all `LootEntry` of type `TableReferenceLootEntry`. + +- Syntax: + - `.removeReference(filter: string | regex)` + - `.removeReference(filter: string | regex, deepRemove: boolean)` + +We remove junk from the fishing loot table, no one needs junk. + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:gameplay/fishing") + .removeReference("minecraft:gameplay/fishing/junk") +}) +``` + +## `removeEntry` + +Removes an entry through given filter. The filter has to **return** either `true` or `false`. When returning `true` the entry will be removed. + +- Syntax: + - `.removeEntry((entry) => { ... })`, + - `.removeEntry((entry) => { ... }, deepRemove: boolean)` + +```js +LootJS.lootTables((event) => { + // Let's remove all loot table reference entries + event.modifyLootTables(/.*/).removeEntry((entry) => entry.isReference()) +}) +``` + +## `replaceItem` + +Replaces all items that matches the filter with the given item. By replacing the item all loot conditions and item functions are kept. If you don't want this use [`modifyItem`](#) and create your own `LootEntry`. + +- Syntax: + - `.replaceItem(filter: ItemFilter, item: Item)`, _see [ItemFilter]_ + - `.replaceItem(filter: ItemFilter, item: Item, deepReplace: boolean)` + +```js +LootJS.lootTables((event) => { + event.modifyLootTypeTables("chest").replaceItem(ItemFilter.) +}) +``` + +## `modifyEntry` + +Modifies all loot entries. Requires to always **return** a loot entry again. You can either return a new [`LootEntry`](/api/loot-entry) or just **return** the old one. + +- Syntax: + - `.modifyEntry((entry: LootEntry) => { ... })` + - `.modifyEntry((entry: LootEntry) => { ... }, deepModify: boolean)` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .modifyEntry((entry) => { + if (entry.isItem() && entry.item.id === "minecraft:string") { + entry.setCount([5, 12]) + } + + // Remember to always return an entry! + return entry + }) +}) +``` + +## `modifyItem` + +Same as `modifyEntry` but will only iterates through `LootItemEntry`s. + +- Syntax: + - `.modifyItem((entry: LootItemEntry) => { ... })` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .modifyItem((itemEntry) => { + if (itemEntry.item.id === "minecraft:string") { + itemEntry.setCount([5, 12]) + } + + // Remember to always return an entry! + return itemEntry + }) +}) +``` + +[ItemFilter]: /api/item-filter diff --git a/wikis/lootjs/docs/api/loot-entry.md b/wikis/lootjs/docs/api/loot-entry.md new file mode 100644 index 0000000..c06e167 --- /dev/null +++ b/wikis/lootjs/docs/api/loot-entry.md @@ -0,0 +1,178 @@ +# LootEntry + +Loot entries are used to create outcome items in loot tables. They are separated into different types of entries. + +- Simple Entries: + - [ItemEntry]: _Adds an item to the pool roll_ + - [EmptyEntry]: _Adds an empty entry to the pool roll_ + - [TagEntry]: _Adds items from a tag to the pool roll_ + - [TableReferenceEntry]: _Drops the loot of another loot table_ + - **DynamicEntry**: _Internal use in Minecraft for Shulker Boxes. Does not work for other blocks. No need to use it ourself_ +- Composite Entries: + - [AlternativeEntry]: _Will only add the first child entry, where the conditions are met. This can be used to as simple if-else entry_ + - [SequenceEntry]: _Adds all child entries until one condition fails. After that no more items will be added to the pool roll._ + - [GroupEntry]: _All child entries will be added to the pool roll. Used for convenience, like applying one condition to multiple entries._ + +`LootEntry` is the base class for all entries. It offers some common functions for all entries. So when dealing with loot entries you always can use functions from `LootEntry`. + +- Methods: + - `.getType()` + - `.isSimple()` + - `.isItem()` + - `.isTag()` + - `.isReference()` + - `.isComposite()` + - `.isAlternative()` + - `.isSequence()` + - `.isGroup()` + - `.getConditions(): LootConditionsList` + - `.when((conditions: LootConditionsList) => { ... })` + +## Simple Entries + +Simple entries also can also contain [`Loot Functions`], which are executed when the entry will be rolled. + +- Methods: + - `.getFunctions(): LootFunctionsList` + - `.apply((functions: LootFunctionsList) => { ... })` + - `.getWeight()` + - `.setWeight(weight: number)` + - `.withWeight(weight: number)` + - `.getQuality()` + - `.setQuality(quality: number)` + - `.withQuality(quality: number)` + +Weight: Determines the chance to roll relative to other entries in the pool. The chance to roll is calculated as `weight / sum(weights of all entries)`. + +Quality: Modifies the entry weight based on the `killer_entity`'s attribute `generic.luck`. Calculated as `floor(weight + (quality * generic.luck))` + +```js +// `withWeight` and `withQuality` will return self, +// so we can easily chain them +const entry = LootEntry.of("minecraft:stick").withWeight(42).withQuality(3) +``` + +### ItemEntry + +- Syntax: + - `LootEntry.of(item)` + - `LootEntry.of(item, count: NumberProvider)`_, see [NumberProvider]_ +- Methods: + - `.getItem()` + - `.setItem(item: Item)` + - `.test(filter: ItemFilter)`_, see [ItemFilter]_ + +```js +LootEntry.of("minecraft:diamond") + +LootEntry.of("minecraft:diamond", [5, 10]) +``` + +```js +const entry = LootEntry.of("minecraft:diamond_sword") + +if (entry.test(ItemFilter.SWORD)) { + // do something +} +``` + +### EmptyEntry + +- Syntax: + - `LootEntry.empty()` + +```js +LootEntry.empty() +``` + +### TagEntry + +- Syntax: + - `LootEntry.tag(tag: string)` + - `LootEntry.tag(tag: string, expanded: boolean)` +- Methods: + - `.getTag()` + - `.setTag(tag: string)` + - `.setExpanded(expanded: boolean)` + - `.getExpanded()` + - `.isTag(tag: string): boolean` + +```js +LootEntry.tag("minecraft:pickaxes") + +LootEntry.tag("minecraft:pickaxes", true) +``` + +### TableReferenceEntry + +- Syntax: + - `LootEntry.reference(table: ResourceLocation | string)` +- Methods: + - `.getLocation()` + - `.setLocation(table: string)` + +```js +LootEntry.reference("minecraft:chests/abandoned_mineshaft") +``` + +## Composite Entries + +- Syntax: + - `LootEntry.alternative(...entries: LootEntry[])` + - `LootEntry.sequence(...entries: LootEntry[])` + - `LootEntry.group(...entries: LootEntry[])` +- Methods: + - `.getEntries(): LootEntryList` + - `.entries((entries: LootEntryList) => { ... })` + +```js +/** + * When Entry is rolled: + * If the randomChance for `diamond` succeeds, add `diamond`, skip rest. + * Otherwise continue with next child + */ +LootEntry.alternative( + LootEntry.of("minecraft:diamond").when((c) => c.randomChance(0.5)), + LootEntry.of("minecraft:emerald").when((c) => c.randomChance(0.5)), + LootEntry.of("minecraft:iron_ingot"), +) +``` + +```js +/** + * When Entry is rolled: + * Add all entries until one entry fails, then skip rest + */ +LootEntry.sequence( + LootEntry.of("minecraft:diamond").when((c) => c.randomChance(0.5)), + LootEntry.of("minecraft:emerald").when((c) => c.randomChance(0.2)), + LootEntry.of("minecraft:iron_ingot"), +) +``` + +```js +/** + * When Entry is rolled: + * Handle all children by their own. Just a convenience entry. + */ +LootEntry.group( + LootEntry.of("minecraft:diamond").when((c) => c.randomChance(0.5)), + LootEntry.of("minecraft:emerald").when((c) => c.randomChance(0.2)), + LootEntry.of("minecraft:iron_ingot"), +) +``` + +## Add conditions + +## Add functions + +[ItemEntry]: #item-entry +[EmptyEntry]: #empty-entry +[TagEntry]: #tag-entry +[TableReferenceEntry]: #table-reference-entry +[AlternativeEntry]: #alternative-entry +[SequenceEntry]: #sequence-entry +[GroupEntry]: #group-entry +[`Loot Functions`]: /api/loot-function +[NumberProvider]: /api/number-provider +[ItemFilter]: /api/item-filter diff --git a/wikis/lootjs/docs/api/loot-function.md b/wikis/lootjs/docs/api/loot-function.md new file mode 100644 index 0000000..b4c6dad --- /dev/null +++ b/wikis/lootjs/docs/api/loot-function.md @@ -0,0 +1,297 @@ +# Functions + +While loot functions can be used in different ways, from now on the examples on this page will shown with `LootEntries` but they can easily be used in other places. + +## `addAttributes` + +Add attribute modifiers to the item. In the callback, you can use multiple functions to add attributes. `Probability` can be used to have a random chance the attribute will be applied. + +If using simple, it will use the default equipment slot for the item. + +- `.simple(attribute, amount: NumberProvider)`_, see [NumberProvider]_ +- `.simple(probability, attribute, amount: NumberProvider)` +- `.forSlots(attribute, amount: NumberProvider, slots: EquipmentSlot[])` +- `.forSlots(probability, attribute, amount: NumberProvider, slots: EquipmentSlot[])` + +Possible attributes for vanilla can be found in the [Minecraft Wiki](https://minecraft.wiki/w/Attribute#Attributes_available_on_all_living_entities). Also mods may add own attributes, for that you should take a look at the corresponding mod page. + +Possible slots are: `"mainhand"`, `"offhand"`, `"head"`, `"chest"`, `"legs"`, `"feet"`. + +- Syntax: + - `.addAttributes(callback => {})` + - `LootFunction.addAttributes(callback => {})` + +```js +LootEntry.of("minecraft:potion").addAttributes((attr) => { + attr.simple("generic.max_health", 1) + attr.simple(0.99, "generic.max_health", 2) + attr.forSlots("generic.max_health", 3, [SLOT_MAINHAND]) + attr.forSlots(0.99, "generic.max_health", 4, [SLOT_OFFHAND]) +}) +``` + +## `addPotion` + +- Syntax: + - `.addPotion(potion)` + - `LootFunction.addPotion(potion)` + +```js +LootEntry.of("minecraft:potion").addPotion("minecraft:poison") +``` + +## `applyBonus` + +Applies a uniform bonus based on given multiplier. The item count will be increased between `0` and `multiplier * enchantmentLevel`.
+_Minecraft uses this for `sea_lantern` or `redstone_ore` as an example by applying `apply_bonus` with `uniform_bonus_count` as formula._ + +- Syntax: + - `.applyBonus(enchantment, multiplier: number)` + - `LootFunction.applyBonus(enchantment, multiplier: number)` + +## `applyOreBonus` + +Applies a bonus based on special formula Minecraft uses for ore drops:
+`count * max(1; randomInt(0, enchantmentLevel + 2))` + +- Syntax: + - `.applyOreBonus(enchantment)` + - `LootFunction.applyOreBonus(enchantment)` + +```js +// In vanilla minecraft often uses fortune here. Of course you can use any enchantment here. +LootEntry.of("minecraft:emerald_ore").applyOreBonus("minecraft:fortune") +``` + +## `applyBinomialDistributionBonus` + +Applies a bonus based on the binomial distribution, where `n = enchantmentLevel + extra` and `p = probability`. + +- Syntax: + - `.applyBinomialDistributionBonus(enchantment, p: number, extra: number)` + - `LootFunction.applyBinomialDistributionBonus(enchantment, p: number, extra: number)` + +```js +LootEntry.of("minecraft:emerald_ore").applyBinomialDistributionBonus( + "minecraft:fortune", + 0.2, + 3, +) +``` + +## `applyEnchantmentBonus` + +Applies a bonus, when player uses a specific enchantment. If no enchantment is provided, "minecraft:looting" is used as default. + +- Syntax: + - `.applyEnchantmentBonus(bonus: NumberProvider)`_, see [NumberProvider]_ + - `.applyEnchantmentBonus(enchantment: Enchantment, bonus: NumberProvider)` + - `LootFunction.applyEnchantmentBonus(bonus: NumberProvider)` + - `LootFunction.applyEnchantmentBonus(enchantment: Enchantment, bonus: NumberProvider)` + +```js +LootEntry.of("minecraft:emerald_ore").applyEnchantmentBonus([2, 5]) +``` + +```js +LootEntry.of("minecraft:emerald_ore").applyEnchantmentBonus("minecraft:fortune", [2, 5]) +``` + +## `setCount` + +::: tip Info +For `LootEntries` we often want to change the existing count instead of adding a new one. Because of that using `setCount` on a loot entry will replace the existing count function if one exists, otherwise it will add it. If you still wish to add multiple count functions you can use `.addFunction(LootFunction.setCount(count: NumberProvider))` + +**This behavior does not apply for `LootModifiers` through `LootJS.modifiers()` event!** +::: + +- Syntax: + - `.setCount(count: NumberProvider)`_, see [NumberProvider]_ + - `LootFunction.setCount(count: NumberProvider)` + +```js +LootEntry.of("minecraft:emerald_ore").setCount(20) +``` + +```js +LootEntry.of("minecraft:emerald_ore").setCount([2, 10]) +``` + +## `limitCount` + +Limits the item count between `min` and `max`. Min and max both can be optional by using `null` as value. + +- Syntax: + - `.limitCount(min: NumberProvider | null, max: NumberProvider | null)`_, see [NumberProvider]_ + - `LootFunction.limitCount(min: NumberProvider | null, max: NumberProvider | null)` + +```js +LootEntry.of("minecraft:emerald_ore").limitCount(2, 10) +``` + +```js +// Or this. Always have at least 10 but never more than [30, 35] +LootEntry.of("minecraft:emerald_ore").limitCount(10, [30, 35]) +``` + +## `setCustomData` + +Set the custom data tag of the item. + +- Syntax: + - `.setCustomData(nbt)` + +```js +LootEntry.of("minecraft:emerald_ore").setCustomData({ someCustomStuff: true }) +``` + +## `setName` + +- Syntax: + - `.setName(name: Component)` + - `LootFunction.setName(name: Component)` + +```js +LootEntry.of("minecraft:emerald_ore").setName( + Component.translatable("item.minecraft.emerald_ore"), +) +``` + +```js +LootEntry.of("minecraft:emerald_ore").setName("Emerald Ore with new name") +``` + +## `enchantRandomly` + +- Syntax: + - `.enchantRandomly()` + - `.enchantRandomly(enchantments: Enchantment | Tag | Enchantment[])` + - `LootFunction.enchantRandomly()` + - `LootFunction.enchantRandomly(enchantments: Enchantment | Tag | Enchantment[])` + +```js +LootEntry.of("minecraft:emerald_ore").enchantRandomly() +``` + +```js +LootEntry.of("minecraft:emerald_ore").enchantRandomly([ + "minecraft:fortune", + "minecraft:unbreaking", +]) +``` + +## `enchantWithLevels` + +- Syntax: + - `.enchantWithLevels(levelRange: NumberProvider)` + +```js +LootEntry.of("minecraft:netherite_sword").enchantWithLevels([20, 39]) +``` + +## `enchant` + +- Syntax: + - `.enchant(add: boolean, (builder) => { ... })` + - `.enchant((builder) => { ... })` + - `LootFunction.enchant(add: boolean, (builder) => { ... })` + - `LootFunction.enchant((builder) => { ... })` + +The builder has a method `.withEnchantment(enchantment: id, level: NumberProvider)` you can use to apply enchantments. + +```js +LootEntry.of("minecraft:netherite_sword").enchant((builder) => { + builder.withEnchantment("minecraft:sharpness", [4, 5]) + builder.withEnchantment("minecraft:unbreaking", 3) + builder.withEnchantment("minecraft:knockback", 2) + builder.withEnchantment("minecraft:mending", 1) +}) +``` + +## `addLore` + +- Syntax: + - `.addLore(lore: Component)` + - `LootFunction.addLore(lore: Component)` + +```js +LootEntry.of("minecraft:emerald_ore").addLore("Enchanted") +``` + +## `replaceLore` + +- Syntax: + - `.replaceLore(lore: Component)` + - `LootFunction.replaceLore(lore: Component)` + +```js +LootEntry.of("minecraft:emerald_ore").replaceLore("Enchanted") +``` + +## `damage` + +- Syntax: + - `.damage(damage: NumberProvider)`_, see [NumberProvider]_ + - `LootFunction.damage(damage: NumberProvider)` + +```js +LootEntry.of("minecraft:diamond_sword").damage(5) +``` + +```js +LootEntry.of("minecraft:diamond_sword").damage([5, 10]) +``` + +## `simulateExplosionDecay` + +- Syntax: + - `.simulateExplosionDecay()` + - `LootFunction.simulateExplosionDecay()` + +```js +LootEntry.of("minecraft:diamond_sword").simulateExplosionDecay() +``` + +## `smelt` + +- Syntax: + - `.smelt()` + - `LootFunction.smelt()` + +```js +LootEntry.of("minecraft:diamond_sword").smelt() +``` + +## `toggleTooltips` + +Allows to toggle rendering tooltips for specific DataComponents + +- Syntax: + - `.toggleTooltips(data: { componentId: boolean })` + - `LootFunction.toggleTooltips(data: { componentId: boolean })` + +```js +LootEntry.of("minecraft:diamond_boots").toggleTooltips({ + "minecraft:enchantments": false, + "minecraft:trim": true, +}) +``` + +## `jsonFunction` + +- Syntax: + - `.jsonFunction(json)` + - `LootFunction.fromJson(json)` + +```js +LootEntry.of("minecraft:diamond_sword").jsonFunction({ + function: "minecraft:limit_count", + limit: { + max: 5.0, + min: 1.0, + }, +}) +``` + +[NumberProvider]: /api/number-provider +[conditions]: /api/loot-condition diff --git a/wikis/lootjs/docs/api/loot-modifier.md b/wikis/lootjs/docs/api/loot-modifier.md new file mode 100644 index 0000000..09a3763 --- /dev/null +++ b/wikis/lootjs/docs/api/loot-modifier.md @@ -0,0 +1,271 @@ +# Loot Modifier + +Loot modifiers offers different actions which can be applied like adding loot, replacing it or even modify it. On this section you will find different actions you can use. + +Besides actions you can also apply any [loot condition](/api/loot-condition) and [loot function](/api/loot-function) to the loot modifier. + +## `addLoot` + +- Syntax: + - `.addLoot(item: string | Item | LootEntry)`, _see [LootEntry]_ + +```js +LootJS.modifiers((event) => { + event + .addTableModifier("minecraft:chests/simple_dungeon") + .addLoot("minecraft:gunpowder") +}) +``` + +```js +LootJS.modifiers((event) => { + // We can also use a loot entry. If all conditions from the entry matches, it will be added + event + .addTableModifier("minecraft:chests/simple_dungeon") + .addLoot(LootEntry.of("minecraft:diamond").randomChance(0.3)) +}) +``` + +```js +LootJS.modifiers((event) => { + // We can also use multiple ones + event + .addTableModifier("minecraft:chests/simple_dungeon") + .addLoot("minecraft:gunpowder", "minecraft:apple") +}) +``` + +## `addAlternativesLoot` + +According to the Minecraft Wiki: Will only add the first successful (conditions are met) item to the loot pool. If no item is successful, no item will be added. + +- Syntax: + - `.addAlternativesLoot(....items: string | Item | LootEntry)`, _see [LootEntry]_ + - + +```js +LootJS.modifiers((event) => { + /** + * First loot entry with a condition. Will drop if the player has fortune. + */ + const stickWhenFortune = LootEntry.of("minecraft:stick") + .applyOreBonus("minecraft:fortune") + .when((c) => + c.matchMainHand(ItemFilter.hasEnchantment("minecraft:fortune")), + ) + + /** + * Second loot entry with a condition. Will drop if the player has silk touch and the first entry doesn't match. + */ + const appleWhenSilkTouch = LootEntry.of("minecraft:apple").when((c) => + c.matchMainHand(ItemFilter.hasEnchantment("minecraft:silk_touch")), + ) + + /** + * No conditions just an item, so this will always drop if the other two don't. + */ + const ironIngot = "minecraft:iron_ingot" + + event + .addBlockLootModifier("minecraft:iron_ore") + .removeLoot(Ingredient.all) + .addAlternativesLoot(stickWhenFortune, appleWhenSilkTouch, ironIngot) +}) +``` + +## `addSequenceLoot` + +Will add multiple items which will be rolled one after another. According to the Minecraft Wiki, it will add all items until one condition fails. After that no more items will be added. + +- Syntax: + - `.addSequenceLoot(....items: string | Item | LootEntry)`, _see [LootEntry]_ + +```js +LootJS.modifiers((event) => { + /** + * First loot entry with a condition. Will drop if the player has fortune. + */ + const stickWhenFortune = LootEntry.of("minecraft:stick").when((c) => + c.matchMainHand(ItemFilter.hasEnchantment("minecraft:fortune")), + ) + + /** + * Second loot entry with a condition. Will drop if the player has silk touch. + */ + const appleWhenEfficiency = LootEntry.of("minecraft:apple").when((c) => + c.matchMainHand(ItemFilter.hasEnchantment("minecraft:efficiency")), + ) + + /** + * Simple item without conditions or anything else, will drop + */ + const flint = "minecraft:flint" + + /** + * Random chance is 0 so no diamond will ever drop. Just to show, that it will skip all other entries. + */ + const diamondNoDrop = LootEntry.of("minecraft:diamond").when((c) => + c.randomChance(0.0), + ) + + /** + * No conditions just an item, but this will not drop, because the previous entry failed. + */ + const ironIngot = "minecraft:iron_ingot" + + event + .addBlockLootModifier("minecraft:coal_ore") + .removeLoot(Ingredient.all) + .addSequenceLoot( + stickWhenFortune, + appleWhenEfficiency, + flint, + diamondNoDrop, + ironIngot, + ) +}) +``` + +## `removeLoot` + +Remove all `items` which matches the given [ItemFilter]. + +- Syntax: + - `.removeLoot(items: string | Item | LootEntry)`, _see [LootEntry]_ + +```js +LootJS.modifiers((event) => { + event + .addTableModifier("minecraft:chests/simple_dungeon") + .removeLoot("minecraft:string") +}) +``` + +```js +LootJS.modifiers((event) => { + event + .addTableModifier("minecraft:chests/simple_dungeon") + .removeLoot(ItemFilter.equipmentSlot("mainhand")) +}) +``` + +## `replaceLoot` + +Replaces all `items` which matches the given [ItemFilter] with a replacement. It's also possible to preserve the original count. + +- Syntax: + - `.replaceLoot(item: string | Item | LootEntry, replacement: string | Item | LootEntry)`, _see [LootEntry]_ + - `.replaceLoot(item: string | Item | LootEntry, replacement: string | Item | LootEntry, preserveCount?: boolean)` + +```js +LootJS.modifiers((event) => { + event + .addTableModifier("minecraft:chests/simple_dungeon") + .replaceLoot(ItemFilter.equipmentSlot("mainhand"), "minecraft:diamond") +}) +``` + +```js +LootJS.modifiers((event) => { + event + .addTableModifier("minecraft:chests/simple_dungeon") + .replaceLoot("#c:ores", "minecraft:gunpowder", true) +}) +``` + +## `modifyLoot` + +For every `item` in the current loot pool which matches the given [ItemFilter], a callback will be called. `LootJS` will pass the item into the callback to modify it and return the `item`. Make sure to always return an `item`! + +- Syntax: + - `.modifyLoot(items: string | Item | LootEntry, onModify: (item) => { ... })`, _see [LootEntry]_ + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("chest").modifyLoot(ItemFilter.ENCHANTED, (item) => { + // We will remove the enchantments component from the item + // So un-enchant it. + item.remove("minecraft:enchantments") + return item + }) +}) +``` + +## `triggerLightningStrike` + +Triggers a lightning strike at the position the loot is dropped at. The `items` will not be destroyed. + +- Syntax: + - `.triggerLightningStrike(shouldDamagePlayer: boolean)` + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("chest").triggerLightningStrike(false) +}) +``` + +## `dropExperience` + +Drops an `amount` of experience on the position where the loot will be dropped. + +- Syntax: + - `.dropExperience(amount: NumberProvider)`, _see [NumberProvider](/api/number-provider)_ + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("chest").triggerLightningStrike(false) +}) +``` + +## `pool` + +Creates a loot pool, which acts as a normal pool from a loot table. See [LootPool](/api/loot-pool) for more details. + +- Syntax: + - `.pool(onCreate: (pool) => { ... })`, _see [LootPool](/api/loot-pool)_ + +```js +LootJS.modifiers((event) => { + event.addTableModifier("minecraft:chests/simple_dungeon").pool((pool) => { + // Work with the pool + }) +}) +``` + +## `group` + +Creates a new nested loot modifier. You can also pre-filter it, so you can only work with a subset of items. + +- Syntax: + - `.group(onCreate: (modifier) => { ... })` + - `.group(filter: ItemFilter, onCreate: (modifier) => { ... })`, _see [ItemFilter]_ + +```js +LootJS.modifiers((event) => { + event + .addTableModifier("minecraft:chests/simple_dungeon") + .group((modifier) => { + // Work with the modifier + }) +}) +``` + +## `customAction` + +Adds a custom action to the loot modifier. The action gives you access to the [LootContext](/api/loot-context) and a list of items which can be used to modify the loot. + +- Syntax: + - `.customAction(action: (context, bucket) => { ... })` + +```js +LootJS.modifiers((event) => { + event.addTypeModifier("chest").customAction((context, loot) => { + if (loot.hasItem("#c:ores")) { + loot.addItem("minecraft:gunpowder") + } + }) +}) +``` + +[LootEntry]: /api/loot-entry +[ItemFilter]: /api/item-filter diff --git a/wikis/lootjs/docs/api/loot-pool.md b/wikis/lootjs/docs/api/loot-pool.md new file mode 100644 index 0000000..98d9298 --- /dev/null +++ b/wikis/lootjs/docs/api/loot-pool.md @@ -0,0 +1,200 @@ +# LootPool + +`LootPool` is used to define what items should be dropped through specific actions. It helps to group up loot in loot tables by using multiple different pools. + +As `LootPool` extends from [`LootEntriesTransformer`](/api/loot-entries-transformer), every function from it can be applied onto loot pools. + +## `getName` + +Get the name of the pool. May return `null` if no name is set. Some mods will give their injected pools a name, so you can use this to identify them. + +- Syntax: + - `.getName()` + +```js +LootJS.lootTables((event) => { + let name = event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .getName() +}) +``` + +## `name` + +Sets the name of the pool. + +- Syntax: + - `.name(name: string)` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .name("example_name") +}) +``` + +## `rolls` + +Sets the number of rolls of the pool. The default value is `1`. + +- Syntax: + - `.rolls(rolls: NumberProvider)`,_see [NumberProvider]_ + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .rolls([1, 5]) // Will roll between 1 and 5 times +}) +``` + +## `bonusRolls` + +Sets the number of bonus rolls of the pool. The default value is `0`. + +- Syntax: + - `.bonusRolls(rolls: NumberProvider)`,_see [NumberProvider]_ + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .bonusRolls(1) +}) +``` + +## `when` + +Set the conditions of the pool. If no condition met the pool will be skipped. See [`LootCondition`](/api/loot-condition) for more information. + +- Syntax: + - `.when((conditions) => {})` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .when((conditions) => { + conditions.randomChance(0.5) + }) +}) +``` + +## `getConditions` + +Returns a list of all conditions attached to the pool. Alternative to `when`. See [`LootCondition`](/api/loot-condition) for more information. + +- Syntax: + - `.getConditions()` + - `.conditions` + +```js +LootJS.lootTables((event) => { + let conditions = event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .getConditions() + conditions.add(LootCondition.randomChance(0.5)) +}) +``` + +## `apply` + +Set the item loot functions of the pool. See [`LootFunction`](/api/loot-function) for more information. + +- Syntax: + - `.apply((functions) => {})` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .apply((functions) => { + functions.setCount([1, 25]) + }) +}) +``` + +## `getFunctions` + +Returns a list of all loot item functions attached to the pool. Alternative to `apply`. See [`LootFunction`](/api/loot-function) for more information. + +- Syntax: + - `.getFunctions()` + - `.functions` + +```js +LootJS.lootTables((event) => { + let functions = event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .getFunctions() + functions.add(LootFunction.setCount([1, 25])) +}) +``` + +## `getEntries` + +Returns a list of all `LootEntry` in the pool. + +- Syntax: + - `.getEntries()` + - `.entries` + +```js +LootJS.lootTables((event) => { + let entries = event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .getEntries() + + entries.addEntry("minecraft:apple") +}) +``` + +## `addEntry` & `addItem` + +Adds a new `LootEntry` to the pool. See [`LootEntry`](/api/loot-entry) for more information. + +- Syntax: + - `.addEntry(entry: LootEntry)` + - `.addItem(item: Item)` + - `.addCustomEntry(json)` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .addEntry(LootEntry.of("minecraft:apple")) +}) +``` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .addEntry("minecraft:apple") // Loot JS will automatically convert it. +}) +``` + +Or you can directly use `addItem` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .firstPool() + .addItem("minecraft:apple") +}) +``` + +[`NumberProvider`](/api/number-provider) diff --git a/wikis/lootjs/docs/api/loot-table.md b/wikis/lootjs/docs/api/loot-table.md new file mode 100644 index 0000000..e83f299 --- /dev/null +++ b/wikis/lootjs/docs/api/loot-table.md @@ -0,0 +1,136 @@ +# LootTable + +Loot tables are used dictate what items should be dropped through specific actions. + +`LootTables` in LootJS extends from `LootEntriesTransformer`. See [`LootEntriesTransformer`](/api/loot-entries-transformer) for more information. + +## `firstPool` +Returns the first pool inside a loot table. If no pool exist, it will create one and return it. + +- Syntax: + - `.firstPool()` + - `.firstPool((pool) => {})` + +```js +LootJS.lootTables((event) => { + let pool = event.getLootTable("minecraft:chests/simple_dungeon").firstPool() +}) +``` + +```js +LootJS.lootTables((event) => { + event.getLootTable("minecraft:chests/simple_dungeon").firstPool((pool) => { + // modify the pool here + }) +}) +``` + +## `createPool` + +Creates a new pool and returns it. + +- Syntax: + - `.createPool()` + - `.createPool((pool) => {})` + +```js +LootJS.lootTables((event) => { + let pool = event + .getLootTable("minecraft:chests/simple_dungeon") + .createPool() +}) +``` + +```js +LootJS.lootTables((event) => { + event.getLootTable("minecraft:chests/simple_dungeon").createPool((pool) => { + // modify the pool here + }) +}) +``` + +## `getFunctions` + +Returns a list of all [item functions](/api/loot-function) attached to the loot table. + +- Syntax: + - `.getFunctions()` + +```js +LootJS.lootTables((event) => { + let functions = event + .getLootTable("minecraft:chests/simple_dungeon") + .getFunctions() +}) +``` + +## `onDrop` + +Adds a custom callback when the loot table is rolled. + +- Syntax: + - `.onDrop((context, loot) => {})` + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/simple_dungeon") + .onDrop((context, loot) => { + for (let item of loot) { + console.log(item) + } + }) +}) +``` + +## `getLocation` + +Get the loot table id + +- Syntax: + - `.getLocation()` + +```js +LootJS.lootTables((event) => { + let table = event.getLootTable("minecraft:chests/simple_dungeon") + let location = table.getLocation() // Would return `"minecraft:chests/simple_dungeon"` +}) +``` + +## `getLootType` + +- Syntax: + - `.getLootType()` + +```js +LootJS.lootTables((event) => { + let table = event.getLootTable("minecraft:chests/simple_dungeon") + let type = table.getLootType() // Would return `LootType.CHEST` +}) +``` + +## `clear` + +Clears the loot table. This will remove all item functions and pools from the table. + +- Syntax: + - `.clear()` + +```js +LootJS.lootTables((event) => { + event.getLootTable("minecraft:chests/simple_dungeon").clear() +}) +``` + +## `print` + +Logs the loot table. Can be used for debugging. + +- Syntax: + - `.print()` + +```js +LootJS.lootTables((event) => { + event.getLootTable("minecraft:chests/simple_dungeon").print() +}) +``` diff --git a/wikis/lootjs/docs/api/number-provider.md b/wikis/lootjs/docs/api/number-provider.md new file mode 100644 index 0000000..b54490f --- /dev/null +++ b/wikis/lootjs/docs/api/number-provider.md @@ -0,0 +1,55 @@ +# NumberProvider + +`NumberProvider`s are used in loot tables to create a random number depending on the loot context. Minecraft itself offers three number providers, but mods can add their own. + +To simplify the usage of number providers LootJS does register a type wrapper in KubeJS. + +## Constant Number + +Always create a constant number. + +- Syntax: + - `NumberProvider.constant(value: number)` + - Directly passing a `number` to the function + +```js +LootEntry.of("minecraft:stick").setCount(NumberProvider.constant(42)) + +LootEntry.of("minecraft:stick").setCount(42) +``` + +## Uniform Number + +Creates a random number between given `min` and `max`. Min and max also can be number providers, which allows nesting. + +- Syntax: + - `NumberProvider.uniform(min: number, max: number)` + - `NumberProvider.uniform(min: NumberProvider, max: number)` + - `NumberProvider.uniform(min: number, max: NumberProvider)` + - `NumberProvider.uniform(min: NumberProvider, max: NumberProvider)` + - Directly passing a `number[]` with two elements to the function + +```js +LootEntry.of("minecraft:stick").setCount(NumberProvider.uniform(2, 10)) + +LootEntry.of("minecraft:stick").setCount([2, 10]) + +LootEntry.of("minecraft:stick").setCount(NumberProvider.uniform(2, [10, 15]) // With nesting +``` + +## Binomial Distribution + +Minecraft also allows to use a [binomial distribution](https://en.wikipedia.org/wiki/Binomial_distribution) to create random numbers by providing `n` and `p`. + +- Syntax: + - `NumberProvider.binomial(n: number, p: number)` + - `NumberProvider.binomial(n: NumberProvider, p: number)` + - `NumberProvider.binomial(n: number, p: NumberProvider)` + - `NumberProvider.binomial(n: NumberProvider, p: NumberProvider)` + - Directly passing `{ n: number, p: number }` to the function + +```js +LootEntry.of("minecraft:stick").setCount(NumberProvider.binomial(10, 0.25)) + +LootEntry.of("minecraft:stick").setCount({ n: 10, p: 0.25 }) +``` diff --git a/wikis/lootjs/docs/api/predicates.md b/wikis/lootjs/docs/api/predicates.md new file mode 100644 index 0000000..e69de29 diff --git a/wikis/lootjs/docs/difference.md b/wikis/lootjs/docs/difference.md new file mode 100644 index 0000000..24a0028 --- /dev/null +++ b/wikis/lootjs/docs/difference.md @@ -0,0 +1,13 @@ +# `LootJS.lootTables` or `LootJS.modifiers` + +LootJS offers two core main events, `LootJS.lootTables()` and `LootJS.modifiers()`. + +# `LootJS.lootTables()`: + +Directly modifies the loot tables, which are loaded through datapacks. This allows to update the loot table without losing any information about rolls, conditions, loot functions etc. You can loop over different parts of the loot table and modify them. As `LootJS.lootTables()` modifies the loot tables directly, changes are reflected at recipe viewers mods such as [JER](https://www.curseforge.com/minecraft/mc-mods/just-enough-resources-jer) or [RER](https://www.curseforge.com/minecraft/mc-mods/roughly-enough-resources). + +# `LootJS.modifiers()`: + +Loot modifiers are dynamically invoked after a loot table is rolled. They don't hold any information on how the loot table is structures, modifiers only know the items that will be dropped. `LootJS.modifiers()` allows to directly modify the items that will be dropped. + +Another thing is the [Global Loot Modifier](https://docs.neoforged.net/docs/resources/server/glm/) system from NeoForge which allows mods to dynamically adds loot, when a specific loot table is rolled. This information does not exist inside a loot table, so using `LootJS.lootTables()` can't catch them. `LootJS.modifiers()` allows to modify them, as it runs after the NeoForge hook runs. diff --git a/wikis/lootjs/docs/event.md b/wikis/lootjs/docs/event.md new file mode 100644 index 0000000..8809318 --- /dev/null +++ b/wikis/lootjs/docs/event.md @@ -0,0 +1,213 @@ +# Event Overview + +The loot tables event contains multiple functions to modify or create new loot tables. The most common use is to add or remove items from existing loot tables, but it's also possible to remove existing conditions e. g changing the probability of an item. + +## `getLootTableIds` + +- Returns an array of all loot table ids as `ResourceLocation`. +- Example: + +```js +LootJS.lootTables((event) => { + let ids = event.getLootTableIds(); + + // or + + let filteredIds = event.getLootTableIds(/.*chests\/.*/); +}); +``` + +## `hasLootTable` + +Returns `true` if the loot table with the given id exists. + +- Example: + +```js +LootJS.lootTables((event) => { + let exists = event.hasLootTable("minecraft:chests/simple_dungeon"); +}); +``` +## `getLootTable` + +Returns a mutable loot table by the given id which can be modified. Will return `null` if no loot table with the given id exists. + +- Syntax: + - `.getLootTable(id)` +- Example: + +```js +LootJS.lootTables((event) => { + let table = event.getLootTable("minecraft:chests/simple_dungeon"); +}); +``` + +## `modifyLootTables` + +Modify all matching loot tables by given filter. + +- Syntax: + - `.modifyLootTables(filter)` +- Example: + +```js +LootJS.lootTables((event) => { + event.modifyLootTables(/.*chests\/.*/).createPool((pool) => { + // editing the pool + }); +}); +``` + +## `getBlockTable` + +Returns a mutable loot table for the given block which can be modified. Will return `null` if no loot table found. + +- Syntax: + - `.getBlockTable(block)` +- Example: + +```js +LootJS.lootTables((event) => { + let table = event.getBlockTable("minecraft:diamond_ore"); +}); +``` + +## `modifyBlockTables` + +Modify all matching block loot by given filter. + +- Syntax: + - `.modifyBlockTables(filter: Block | Block[] | tag)` +- Example: + +```js +LootJS.lootTables((event) => { + event.modifyBlockTables("minecraft:diamond_ore").createPool((pool) => { + // editing the pool + }); +}); +``` + +```js +LootJS.lootTables((event) => { + event.modifyBlockTables(["minecraft:diamond_ore", "minecraft:emerald_ore"]).createPool((pool) => { + // editing the pool + }); +}); +``` + +```js +LootJS.lootTables((event) => { + event.modifyBlockTables("#minecraft:logs").createPool((pool) => { + // editing the pool + }); +}); +``` + +## `getEntityTable` + +Returns a mutable loot table for the given entity which can be modified. Will return `null` if no loot table found. + +- Syntax: + - `.getEntityTable(entity)` +- Example: + +```js +LootJS.lootTables((event) => { + let table = event.getEntityTable("minecraft:sheep"); +}); +``` + +## `modifyEntityTables` + +Modify all matching entity loot by given filter. + +- Syntax: + - `.modifyEntityTables(filter: Entity | Entity[] | tag)` +- Example: + +```js +LootJS.lootTables((event) => { + event.modifyEntityTables("minecraft:sheep").createPool((pool) => { + // editing the pool + }); +}); +``` + +## `modifyLootTypeTables` + +Modify all matching loot tables by given type. Loot tables mostly have a type e.g `minecraft:blocks/bricks` in line 2. + +```json{2} +{ + "type": "minecraft:block", + "pools": [ + { + // ... + } + ], + "random_sequence": "minecraft:blocks/bricks" +} +``` + +- Syntax: + - `.modifyLootTypeTables(type: LootType | LootType[])` +- Example: + +```js +LootJS.lootTables((event) => { + event.modifyLootTypeTables(LootType.CHEST).createPool((pool) => { + // editing the pool + }); + + // As kubejs automatically type wraps Enums, we can just use the name of the enum + event.modifyLootTypeTables("chest").createPool((pool) => { + // editing the pool + }); + + // If we want to match multiple types, we can use an array + event.modifyLootTypeTables([LootType.CHEST, LootType.ENTITY]).createPool((pool) => { + // editing the pool + }); +}); +``` + +## `clearLootTables` + +Clear all loot tables matching the given filter. + +- Syntax: + - `.clearLootTables(filter: string | regex)` +- Example: + +```js +LootJS.lootTables((event) => { + event.clearLootTables(/.*chests/.*); +}); +``` + +Alternative to `clearLootTable` we can call `.clear()` on `MutableLootTables` ourself. + +## `create` + +Create a new loot table. + +- Syntax: + - `.create(id: string, type?: LootType)`_, default to `LootType.CHEST` if not provided_ +- Example: + +```js +LootJS.lootTables((event) => { + event.create("lootjs:table1", LootType.CHEST).createPool((pool) => { + // editing the pool + }); + + // We can skip the type argument if we want to use the default + event.create("lootjs:table2").createPool((pool) => { + // editing the pool + }); +}); +``` + +[ResourceLocationFilter]: ./test.md +[LootType]: ./test.md diff --git a/wikis/lootjs/docs/index.md b/wikis/lootjs/docs/index.md new file mode 100644 index 0000000..42c8afc --- /dev/null +++ b/wikis/lootjs/docs/index.md @@ -0,0 +1,13 @@ +# Getting Started + +::: info +First of all, this Wiki is for LootJS version 3.0 and above. For previous versions please refer to the [old wiki](https://github.com/AlmostReliable/lootjs/wiki). Everything in this wiki is not compatible with older versions of LootJS. +::: + +LootJS is a mod for [NeoForge](https://neoforged.net/) which let's you modify loot tables or dynamically add new loot through [KubeJS](https://kubejs.com/) and JavaScript. + +It does not come with any pre defined loot modifications. This is something which has to be done by the modpack developer. + +The mod contains two main events `LootJS.lootTables()` and `LootJS.modifiers()` and is server sided, so every script you make has to be inside `server_scripts`, otherwise it will be ignored. + +For editing your scripts we highly suggest to use an editor which offers syntax highlighting and error checking for JavaScript. It is recommended to use [VSCode](https://code.visualstudio.com/). diff --git a/wikis/lootjs/docs/loot-modifiers/event.md b/wikis/lootjs/docs/loot-modifiers/event.md new file mode 100644 index 0000000..d7a532e --- /dev/null +++ b/wikis/lootjs/docs/loot-modifiers/event.md @@ -0,0 +1,140 @@ +# Loot Modification Event + +Event is used to create loot modifiers which are applied when a loot table is rolled. This allows us to work directly with the items generated and modify them. + +## `getGlobalModifiers` + +Returns a list of all registered global loot modifiers from mods. + +- Syntax: + - `.getGlobalModifiers()` + +## `removeGlobalModifiers` + +Remove all global loot modifiers from mods by given filter. + +- Syntax: + - `.removeGlobalModifiers(filter: string | regex)` + +## `addTableModifier` + +Add a new loot modifier for all loot tables which match the given filter. + +- Syntax: + - `.addTableModifier(filter: string | string[] | regex)`, returns a [LootModifier] + +```js +LootJS.modifiers((event) => { + event + .addTableModifier("minecraft:chests/simple_dungeon") + .randomChance(0.5) + .addLoot("minecraft:gunpowder") +}) +``` + +```js +LootJS.modifiers((event) => { + // Or we can also use a regex + event + .addTableModifier(/minecraft:chests:.*/) + .randomChance(0.5) + .addLoot("minecraft:gunpowder") +}) +``` + +## `addTypeModifier` + +Add a new loot modifier for given loot types. +Valid loot types are `chest`, `block`, `entity`, `fishing`, `archaeology`, `gift`, `vault`, `shearing`, `piglin_barter` + +- Syntax: + - `.addTypeModifier(type: LootType)`, returns a [LootModifier] + +```js +LootJS.modifiers((event) => { + event + .addTypeModifier("chest") + .randomChance(0.5) + .addLoot("minecraft:gunpowder") +}) +``` + +```js +LootJS.modifiers((event) => { + // We can also use multiple ones + event + .addTypeModifier("block", "entity") + .randomChance(0.5) + .addLoot("minecraft:gunpowder") +}) +``` + +## `addEntityModifier` + +Add a new loot modifier for all entities which match the given filter. + +- Syntax: + - `.addEntityModifier(filter: string | string[] | tag)`, returns a [LootModifier] + +```js +LootJS.modifiers((event) => { + event + .addEntityModifier("minecraft:creeper") + .randomChance(0.5) + .addLoot("minecraft:gunpowder") +}) +``` + +```js +LootJS.modifiers((event) => { + event + .addEntityModifier(["minecraft:cow", "minecraft:pig"]) + .randomChance(0.5) + .addLoot("minecraft:gold_nugget") +}) +``` + +```js +LootJS.modifiers((event) => { + event + .addEntityModifier("#minecraft:skeletons") + .randomChance(0.5) + .addLoot("minecraft:stick") +}) +``` + +## `addBlockModifier` + +Add a new loot modifier for all blocks which match the given filter. + +- Syntax: + - `.addBlockModifier(filter: string | string[] | regex | tag)`, returns a [LootModifier] + +```js +LootJS.modifiers((event) => { + event + .addEntityModifier("minecraft:iron_ore") + .randomChance(0.5) + .addLoot("minecraft:iron_nugget") +}) +``` + +```js +LootJS.modifiers((event) => { + event + .addEntityModifier(["minecraft:gravel", "minecraft:dirt"]) + .randomChance(0.5) + .addLoot("minecraft:gold_nugget") +}) +``` + +```js +LootJS.modifiers((event) => { + event + .addEntityModifier("#c:ores") + .randomChance(0.5) + .addLoot("minecraft:flint") +}) +``` + +[LootModifier]: /api/loot-modifier diff --git a/wikis/lootjs/docs/loot-tables/create-loot-table.md b/wikis/lootjs/docs/loot-tables/create-loot-table.md new file mode 100644 index 0000000..68a004d --- /dev/null +++ b/wikis/lootjs/docs/loot-tables/create-loot-table.md @@ -0,0 +1,136 @@ +# Create a loot table + +With LootJS you can simply create your own loot tables. Please note, that depending on what type of loot table you create it will not be automatically be triggered. + +In this section we will create our own little loot table which may roll some rare items. We will also split the items between pools. The first pool will contain a few rare items and the second pool will have a chance to roll an epic item. + +After this we will append this loot table to an existing loot table with a low chance to be rolled. + +## Create the table + +Create a loot table with one pool is pretty simple: + +```js +LootJS.lootTables((event) => { + event.create("lootjs:rare_equipment").createPool((pool) => { + // ... + }) +}) +``` + +## First pool + +We want to add a some gear to the first pool but first let's take a look how such a loot entry would look like in a datapack. + +### First item + +This is one entry example from `minecraft:chests/end_city_treasure`. You can see the full loot table [here](https://misode.github.io/loot-table/?version=1.21&preset=chests/end_city_treasure). + +```json +{ + "type": "minecraft:item", + "name": "minecraft:diamond_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": { + "type": "minecraft:uniform", + "min": 20, + "max": 39 + }, + "options": "#minecraft:on_random_loot" + } + ] +} +``` + +Now let's add it: + +```js +LootJS.lootTables((event) => { + event.create("lootjs:rare_equipment").createPool((pool) => { + // Per default it will always be `#minecraft:on_random_loot` for `enchantWithLevels` + pool.addEntry( + LootEntry.of("minecraft:diamond_leggings") + .withWeight(3) + .enchantWithLevels([20, 39]), + ) + }) +}) +``` + +### More items + +Let's add some more items to the first pool. + +```js +LootJS.lootTables((event) => { + event.create("lootjs:rare_equipment").createPool((pool) => { + pool.addEntry( + LootEntry.of("minecraft:diamond_leggings") + .withWeight(3) + .enchantWithLevels([20, 39]), + ) + + pool.addEntry( + LootEntry.of("minecraft:iron_pickaxe") + .withWeight(10) + .enchantWithLevels([10, 19]), + ) + + pool.addEntry( + LootEntry.of("minecraft:diamond_sword") + .withWeight(5) + .enchantWithLevels([30, 50]) + .damage([0.3, 0.5]), + ) + + pool.addEntry("minecraft:diamond_horse_armor") + + pool.addEntry(LootEntry.of("minecraft:diamond").setCount([2, 5])) + }) +}) +``` + +## Second pool + +Now let's add a special sword to the second pool. But we want to make it rare. + +```js +LootJS.lootTables((event) => { + event + .create("lootjs:rare_equipment") + .createPool((pool) => { + // first pool + }) + .createPool((pool) => { + pool.addEntry( + LootEntry.of("minecraft:netherite_sword").enchant((builder) => { + builder.withEnchantment("minecraft:sharpness", [4, 5]) + builder.withEnchantment("minecraft:unbreaking", 3) + builder.withEnchantment("minecraft:knockback", 2) + builder.withEnchantment("minecraft:mending", 1) + }), + ) + + // Vanilla often uses an empty entry with a weight instead of `randomChance` + // For this tutorial we will do the same. + pool.addEntry(LootEntry.empty().withWeight(20)) + }) +}) +``` + +## Append our loot table + +Now we want to add our loot table to the `minecraft:gameplay/fishing` loot table. We also will use `randomChance` for our reference to make it even more rare. + +```js +LootJS.lootTables((event) => { + event.getLootTable("minecraft:gameplay/fishing").firstPool((pool) => { + pool.addEntry( + LootEntry.reference("lootjs:rare_equipment").randomChance(0.1), + ) + }) +}) +``` diff --git a/wikis/lootjs/docs/loot-tables/event.md b/wikis/lootjs/docs/loot-tables/event.md new file mode 100644 index 0000000..e19c1fe --- /dev/null +++ b/wikis/lootjs/docs/loot-tables/event.md @@ -0,0 +1,220 @@ +# Loot Table Event + +LootJS let's you modify or create loot tables through the `LootJS.lootTables` event. With this event you directly modify the loot tables, which are loaded through data packs. + +The event also loads after other mods may inject their custom loot tables into vanilla ones, so you will be able to remove or update these changes. + +## `getLootTableIds` + +Returns an array of all loot table ids. Can also be filtered. + +- Syntax: + - `.getLootTableIds()` + - `.getLootTableIds(filter)` + +```js +LootJS.lootTables((event) => { + let ids = event.getLootTableIds() +}) +``` + +It's also possible to filter them through regex: + +```js +LootJS.lootTables((event) => { + let ids = event.getLootTableIds(/.*chests\/.*/) +}) +``` + +## `hasLootTable` + +Will return `true` if the loot table with the given id exists. + +- Syntax: + - `.hasLootTable(id)` + +```js +LootJS.lootTables((event) => { + let exists = event.hasLootTable("minecraft:chests/simple_dungeon") +}) +``` + +## `getLootTable` + +Returns a loot table by the given id which can be modified. Will return `null` if no loot table found. + +- Syntax: + - `.getLootTable(id)` + +```js +LootJS.lootTables((event) => { + let table = event.getLootTable("minecraft:chests/simple_dungeon") +}) +``` + +## `modifyLootTables` + +Modify all matching loot tables by given filter. + +- Syntax: + - `.modifyLootTables(filter)` + +```js +LootJS.lootTables((event) => { + event.modifyLootTables(/.*chests\/.*/).createPool((pool) => { + // editing the pool + }) +}) +``` + +## `getBlockTable` + +Returns a loot table for the given block which can be modified. Will return `null` if no loot table found. + +- Syntax: + - `.getBlockTable(block)` + +```js +LootJS.lootTables((event) => { + let table = event.getBlockTable("minecraft:diamond_ore") +}) +``` + +## `modifyBlockTables` + +Modify all matching block loot by given filter. + +- Syntax: + - `.modifyBlockTables(filter: Block | Block[])` + +```js +LootJS.lootTables((event) => { + event.modifyBlockTables("minecraft:diamond_ore").createPool((pool) => { + // editing the pool + }) +}) +``` + +```js +LootJS.lootTables((event) => { + event + .modifyBlockTables(["minecraft:diamond_ore", "minecraft:emerald_ore"]) + .createPool((pool) => { + // editing the pool + }) +}) +``` + +::: info +Because of the load order inside minecraft, since **1.21** loot tables are loaded before tags even exist. So it's not possible to use `modifyBlockTables` with a tag. + +If you really need to modify by tags, consider to use the loot modifier event. +::: + +## `getEntityTable` + +Returns a loot table for the given entity which can be modified. Will return `null` if no loot table found. + +- Syntax: + - `.getEntityTable(entity: EntityType)` + +```js +LootJS.lootTables((event) => { + let table = event.getEntityTable("minecraft:sheep") +}) +``` + +## `modifyEntityTables` + +Modify all matching entity loot by given filter. + +- Syntax: + - `.modifyEntityTables(filter: EntityType | EntityType[])` +- Example: + +```js +LootJS.lootTables((event) => { + event.modifyEntityTables("minecraft:sheep").createPool((pool) => { + // editing the pool + }) +}) +``` + +## `modifyLootTypeTables` + +Modify all matching loot tables by given type. Loot tables mostly have a type e.g the loot table `minecraft:blocks/bricks` uses `block` as type in line 2. + +```json{2} +{ + "type": "minecraft:block", + "pools": [ + { + // ... + } + ], + "random_sequence": "minecraft:blocks/bricks" +} +``` + +Valid loot types are `chest`, `block`, `entity`, `fishing`, `archaeology`, `gift`, `vault`, `shearing`, `piglin_barter` + +- Syntax: + - `.modifyLootTypeTables(type: LootType | LootType[])` + +```js +LootJS.lootTables((event) => { + event.modifyLootTypeTables(LootType.CHEST).createPool((pool) => { + // editing the pool + }) + + // As kubejs automatically type wraps Enums, we can just use the name of the enum + event.modifyLootTypeTables("chest").createPool((pool) => { + // editing the pool + }) + + // If we want to match multiple types, we can use an array + event + .modifyLootTypeTables(LootType.CHEST, LootType.ENTITY) + .createPool((pool) => { + // editing the pool + }) +}) +``` + +## `clearLootTables` + +Clear all loot tables matching the given filter. + +- Syntax: + - `.clearLootTables(filter: string | regex)` + - + +```js +LootJS.lootTables((event) => { + event.clearLootTables(/.*chests/.*); +}); +``` + +::: info +Alternative to `clearLootTable` we can call `.clear()` directly on our `LootTable`. +::: + +## `create` + +Create a new loot table. + +- Syntax: + - `.create(id: string, type?: LootType)`_, default to `LootType.CHEST` if not provided_ + +```js +LootJS.lootTables((event) => { + event.create("lootjs:table1", LootType.CHEST).createPool((pool) => { + // editing the pool + }) + + // We can skip the type argument if we want to use the default + event.create("lootjs:table2").createPool((pool) => { + // editing the pool + }) +}) +``` diff --git a/wikis/lootjs/docs/loot-tables/modify-loot-table.md b/wikis/lootjs/docs/loot-tables/modify-loot-table.md new file mode 100644 index 0000000..9a8bc11 --- /dev/null +++ b/wikis/lootjs/docs/loot-tables/modify-loot-table.md @@ -0,0 +1,74 @@ +# Modify your first loot table + +Let's get started with modifying your first loot table. LootJS offers different functions you can use for that. You will be able to add, remove or even just change the weight of an item in the loot table. Before starting make sure to have a basic knowledge on how loot tables work, check out the [minecraft wiki](https://minecraft.wiki/w/Loot_table) for that. + +First create a javascript file in `server_scripts` and you can call the file however you want but make sure the file extension will be `.js`, e.g `more_loot.js`. + +We will use the `minecraft:chests/desert_pyramide` loot table as an example. You can see [here](https://misode.github.io/loot-table/?preset=chests/desert_pyramid) how the loot table is structured to get a better understanding of what we will. + +## Add Item + +Let's add a simple `apple` to our chest loot. + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/desert_pyramid") + .firstPool() + .addEntry("minecraft:apple") +}) +``` + +Note that we use `firstPool()` here. We will use this a lot to always get the first loot pool. Most vanilla tables do have one pool which will roll multiple times, see `rolls`. + +### With weight + +But what if we want to add the apple with a specific weight? For this we can simply use [`LootEntry`](/api/loot-entry), which has the functionality to set the weight. + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/desert_pyramid") + .firstPool() + .addEntry(LootEntry.of("minecraft:apple").withWeight(20)) +}) +``` + +### Set quantity + +Let's also change the quantity of the apple, so it will drop 2 - 5 apples each time an apple is rolled. We can use the [`setCount`](/api/loot-entry#setcount) function. + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/desert_pyramid") + .firstPool() + .addEntry( + LootEntry.of("minecraft:apple").withWeight(20).setCount([2, 5]), + ) +}) +``` + +## Modify Item + +Now we want to modify an existing entry inside our loot table. You can see that diamonds have a weight of 5, let's change it to 1 to make it less likely to be rolled. + +```js +LootJS.lootTables((event) => { + event + .getLootTable("minecraft:chests/desert_pyramid") + .firstPool() + .modifyItem((itemEntry) => { + if (itemEntry.item.id === "minecraft:diamond") { + itemEntry.setWeight(1) + } + + return itemEntry + }) +}) +``` + +You can see that we return `itemEntry` again. This is required because `modify` operations always require a result. In our example we just modify the given `itemEntry` and return it, this will ensure that all conditions and loot modifiers will still be applied for the entry. Alternative you can just return a new [`LootEntry`](/api/loot-entry) with the desired modifications. + +## Remove Item + diff --git a/wikis/lootjs/docs/modify-loot-tables.md b/wikis/lootjs/docs/modify-loot-tables.md new file mode 100644 index 0000000..014784a --- /dev/null +++ b/wikis/lootjs/docs/modify-loot-tables.md @@ -0,0 +1 @@ +# Modify loot table diff --git a/wikis/morejs/.vitepress/config.mts b/wikis/morejs/.vitepress/config.mts new file mode 100644 index 0000000..fdf0951 --- /dev/null +++ b/wikis/morejs/.vitepress/config.mts @@ -0,0 +1,16 @@ +import { defineConfig } from "../../../main/defineAlmostWiki"; + +export default defineConfig({ + srcDir: "./docs", + base: "/morejs/", + themeConfig: { + sidebar: [ + { + text: "Intro", + items: [ + { text: "Getting Started", link: "/" }, + ], + }, + ], + }, +}) diff --git a/wikis/morejs/.vitepress/theme/index.ts b/wikis/morejs/.vitepress/theme/index.ts new file mode 100644 index 0000000..c70c4b6 --- /dev/null +++ b/wikis/morejs/.vitepress/theme/index.ts @@ -0,0 +1,3 @@ +// https://vitepress.dev/guide/custom-theme +import Theme from "../../../../main/theme" +export default Theme diff --git a/wikis/morejs/docs/index.md b/wikis/morejs/docs/index.md new file mode 100644 index 0000000..c1c4ec7 --- /dev/null +++ b/wikis/morejs/docs/index.md @@ -0,0 +1,3 @@ +# Index MoreJS + +Test page