diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index abcb366..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -**/node_modules/* \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index f4843be..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "env": { - "es6": true - }, - "parserOptions": { - "sourceType": "module", - "ecmaVersion": 2017 - }, - "extends": "plugin:@typescript-eslint/eslint-recommended", - "parser": "@typescript-eslint/parser", - "rules": { - "no-var": "error", - "semi": ["error", "always", { "omitLastInOneLineBlock": true }], - "block-spacing": "error", - "indent": ["error", 4, { "SwitchCase": 1 }], - "no-mixed-spaces-and-tabs": "error", - "no-multiple-empty-lines": ["error" , { "max": 1 }], - "no-trailing-spaces": "error", - "space-infix-ops": "error", - "dot-notation": "error", - "eqeqeq": "error", - "quotes": ["error", "double"], - "no-else-return": "error", - "no-loop-func": "error", - "arrow-parens": "error", - "arrow-spacing": "error", - "no-undef": "off", - "comma-dangle": "warn", - "no-unused-vars": ["error", { "vars": "local", "args": "all" }], - "no-use-before-define": "error", - "no-const-assign": "error", - "space-before-blocks": "error", - "no-unexpected-multiline": "error", - "object-curly-spacing": ["error", "always"], - "quote-props": ["error", "always"], - "max-len": ["error", { - "code": 200, - "ignoreStrings": true, - "ignoreComments": true, - "ignoreTemplateLiterals": true - }], - "no-debugger": "error", - "no-dupe-keys": "error", - "no-duplicate-case": "error", - "no-empty": "error", - "no-extra-parens": "error", - "no-func-assign": "error", - "no-irregular-whitespace": "error", - "no-sparse-arrays": "error", - "no-unreachable": "error", - "no-unsafe-negation": "error", - "use-isnan": "error", - "block-scoped-var": "error", - "no-caller": "error", - "curly": "error", - "no-case-declarations": "error", - "no-floating-decimal": "error", - "no-eq-null": "error", - "no-empty-function": "error", - "no-empty-pattern": "error", - "no-extend-native": "error", - "dot-location": ["error", "property"], - "no-global-assign": "error", - "no-implicit-globals": "error", - "no-invalid-this": "error", - "no-lone-blocks": "error", - "no-iterator": "error", - "no-new": "error", - "no-proto": "error", - "no-return-assign": "error", - "no-self-assign": "error", - "no-self-compare": "error", - "no-useless-concat": "error", - "no-useless-call": "error", - "no-useless-return": "error", - "no-unused-expressions": "error", - "no-class-assign": "error", - "no-sequences": "error", - "no-dupe-args": "error", - "no-extra-boolean-cast": "error", - "no-obj-calls": "error", - "no-console": "warn", - "no-extra-semi": "warn" - } -} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 30ddbbb..c78eeba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -*.js text eol=lf \ No newline at end of file +*.js text eol=lf +*.ts text eol=lf \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6285f6b..1d22c12 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,6 +27,7 @@ jobs: permissions: actions: read contents: read + pull-requests: write security-events: write strategy: @@ -40,7 +41,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 64811b5..3865578 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -11,11 +11,31 @@ on: - develop jobs: - build: - runs-on: ubuntu-latest + macos-browser-test: + runs-on: macos-latest + permissions: + contents: read + pull-requests: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 + - uses: actions/checkout@v4 + with: + repository: Next2D/player + ref: develop + - run: npm install + - run: npm run test + + windows-browser-test: + runs-on: windows-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/setup-node@v4 + - uses: actions/checkout@v4 + with: + repository: Next2D/player + ref: develop - run: npm install - run: npm run test diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index af26ed5..f41fcb3 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,16 +13,22 @@ on: jobs: macos-browser-test: runs-on: macos-latest + permissions: + contents: read + pull-requests: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 - run: npm install - run: npx eslint ./src/**/*.ts windows-browser-test: runs-on: windows-latest + permissions: + contents: read + pull-requests: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 - run: npm install - run: npx eslint ./src/**/*.ts \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c00691b..9b033fd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,18 +3,21 @@ name: Publish Package on: push: branches: - - publish + - main jobs: build: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: registry-url: "https://registry.npmjs.org" - run: npm install - run: npm run publish - - run: npm publish --access public + - run: cd ~/work/framework/framework/dist && npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} \ No newline at end of file diff --git a/.npmignore b/.npmignore deleted file mode 100644 index a7e8a47..0000000 --- a/.npmignore +++ /dev/null @@ -1,12 +0,0 @@ -.eslintignore -.eslintrc.json -.gitattributes -.gitignore -.github -__tests__ -scripts -src -Framework_Flowchart.svg -tsconfig.eslint.json -tsconfig.json -vite.config.ts \ No newline at end of file diff --git a/@types/window.d.ts b/@types/window.d.ts index 68a29b7..6f5005e 100644 --- a/@types/window.d.ts +++ b/@types/window.d.ts @@ -1,11 +1,9 @@ -import { Next2D } from "@next2d/core"; +import type { Next2D } from "@next2d/core"; declare global { - // eslint-disable-next-line no-unused-vars const next2d: Next2D; - // eslint-disable-next-line no-unused-vars interface Window { next2d: Next2D; } diff --git a/DEVELOP.md b/DEVELOP.md new file mode 100644 index 0000000..6299cc0 --- /dev/null +++ b/DEVELOP.md @@ -0,0 +1,30 @@ +# Development Environments + +## Version +Middleware required for development and supported versions +``` +node >= v22.x +``` + +## Initial Settings +``` +mkdir next2d +cd next2d +git clone git@github.com:Next2D/player.git +git clone git@github.com:Next2D/framework.git +cd framework +npm install +``` + +## Unit Test +``` +npm test +``` + +## ESLint +``` +npm run lint +``` + +## License +This project is licensed under the [MIT License](https://opensource.org/licenses/MIT) - see the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/Framework_Flowchart.svg b/Framework_Flowchart.svg index efa22b0..b713d50 100644 --- a/Framework_Flowchart.svg +++ b/Framework_Flowchart.svg @@ -1,4 +1,4 @@ -RequestRequestUserUser[Source] src/App.js[Function] gotoView({Path})[Source] src/App.js...YESYESNONOuse loading(Default value is true)use loading...[Source] config.loading.{ClassName}[Function] start[Source] config.loading.{ClassName}...JSONGet external JSON dataJSON...CONTENTGet JSON data exported by NoCodeToolCONTENT...CUSTOMRequests to external APIsCUSTOM...YESYESNONOuse cache(Default value is false)use cache...cachecacheGlobalGlobalNONOCachedCached[Source] src/view/{Path}View.js[Function] initialize[Source] src/view/{Path}View.js...[Source] src/view/{Path}ViewModel.js[Function] bind[Source] src/view/{Path}ViewModel.js...[Source] src/view/{PrevPath}ViewModel.js[Function] unbind[Source] src/view/{PrevPath}ViewModel.js...YESYESNONOuse callback(Default value is empty)use callback...[Source] config.loading.{ClassName}[Function] start[Source] config.loading.{ClassName}...YESYESNONOuse loading(Default value is true)use loading...[Source] config.loading.{ClassName}[Function] end[Source] config.loading.{ClassName}...ResponseResponseStart drawingStart drawingYESYESRemove Response Data{ responce } from "@next2d/framework"Remove Response Data...Response Data Registration{ responce } from "@next2d/framework"Response Data Registration...Text is not SVG - cannot display \ No newline at end of file +RequestUser[Source] src/App.js[Function] gotoView({Path})YESNOuse loading(Default value is true)[Source] config.loading.{ClassName}[Function] startJSONGet external JSON dataCONTENTGet JSON data exported by Animation ToolCUSTOMRequests to external APIsYESNOuse cache(Default value is false)cacheGlobalNOCached[Source] src/view/{Path}View.js[Function] initialize[Source] src/view/{Path}ViewModel.js[Function] bind[Source] src/view/{PrevPath}ViewModel.js[Function] unbindYESNOuse callback(Default value is empty)[Source] config.loading.{ClassName}[Function] startYESNOuse loading(Default value is true)[Source] config.loading.{ClassName}[Function] endResponseStart drawingYESRemove Response Data{ app } from "@next2d/framework"responce = app.getResponce()Response Data Registration{ app } from "@next2d/framework"responce = app.getResponce() \ No newline at end of file diff --git a/__tests__/application/ApplicationTest.ts b/__tests__/application/ApplicationTest.ts deleted file mode 100644 index be44f72..0000000 --- a/__tests__/application/ApplicationTest.ts +++ /dev/null @@ -1,193 +0,0 @@ -import "@next2d/player"; -import { - Application, - cache, - response -} from "../../src"; -import { RequestType } from "../../src/infrastructure/constant/RequestType"; -import { ResponseDTO } from "../../src/infrastructure/dto/ResponseDTO"; -import { $createContext } from "../../src/application/variable/Context"; - -describe("ApplicationTest", () => -{ - test("run test", () => { - - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "test": { - "requests": [{ - "type": RequestType.JSON, - "path": "." - }] - } - } - }; - const packages = [["app", "app"]]; - - const app = new Application(config, packages); - - app - .run() - .then(() => - { - expect(app instanceof Application).toBe(true); - }); - }); - - test("loading test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "test": { - "requests": [{ - "type": RequestType.JSON, - "path": "." - }] - } - } - }; - - $createContext(config); - - const packages = [["app", "app"]]; - - const app = new Application(config, packages); - app.gotoView(); - }); - - test("spa test", () => - { - cache.clear(); - cache.set("app_test", new ResponseDTO("app_test", "app success")); - - response.clear(); - expect(response.size).toBe(0); - - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "top": { - "requests": [ - { - "type": RequestType.JSON, - "name": "app_test", - "path": "", - "cache": true - } - ] - } - }, - "gotoView": { - "callback": "" - }, - "loading": { - "callback": "" - } - }; - const packages = [["app", "app"]]; - - const app = new Application(config, packages); - - app - .gotoView() - .then((result) => - { - expect(result).toBe(undefined); - }); - - // @ts-ignore - if (!$windowEventMap.has("popstate")) { - throw new Error("stop test"); - } - - // @ts-ignore - $windowEventMap.get("popstate")(); - }); - - test("spa response zero test", () => - { - // mock - cache.clear(); - cache.set("app_test", new ResponseDTO()); - cache.set("abc", new ResponseDTO()); - - response.clear(); - - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "top": { - "requests": [ - { - "type": RequestType.JSON, - "name": "app_test", - "path": "", - "cache": true - }, - { - "type": RequestType.CONTENT, - "name": "abc", - "path": "", - "cache": true - } - ] - } - }, - "gotoView": { - "callback": "" - }, - "loading": { - "callback": "" - } - }; - const packages = [["app", "app"]]; - - const app = new Application(config, packages); - - app - .gotoView() - .then((result) => - { - expect(result).toBe(undefined); - }); - - // @ts-ignore - if (!$windowEventMap.has("popstate")) { - throw new Error("stop test"); - } - - // @ts-ignore - $windowEventMap.get("popstate")(); - }); -}); \ No newline at end of file diff --git a/__tests__/application/ContextTest.ts b/__tests__/application/ContextTest.ts deleted file mode 100644 index 58dbee1..0000000 --- a/__tests__/application/ContextTest.ts +++ /dev/null @@ -1,99 +0,0 @@ -import "@next2d/player"; -import { Sprite } from "@next2d/display"; -import { packages, View } from "../../src"; -import { Context } from "../../src/application/Context"; - -describe("ContextTest", () => -{ - test("initialize test", () => - { - // mock - packages.clear(); - - const context = new Context(new Sprite()); - context - .addChild("test") - .then((result) => - { - expect(result).toBe(undefined); - expect(context.viewName).toBe("Test"); - expect(typeof context.root).toBe("object"); - expect(context.view).toBe(null); - expect(context.viewModel).toBe(null); - }); - }); - - test("initialize not view test", () => - { - // mock - packages.clear(); - - const context = new Context(new Sprite()); - context - .addChild("abc") - .then((result) => - { - expect(result).toBe(undefined); - expect(context.view).toBe(null); - expect(context.viewModel).toBe(null); - }); - }); - - test("initialize test case1", () => - { - const view_initialize: string = "view_initialize"; - - // @ts-ignore - packages.clear(); - packages.set("XyzView", class XyzView extends View - { - // eslint-disable-next-line no-unreachable - private event: Map; - - constructor () - { - super(); - this.event = new Map(); - } - - initialize () - { - expect(view_initialize).toBe("view_initialize"); - } - - addEventListener (type: string, callback: any): void - { - this.event.set(type, callback); - callback({ - "target": "view_model_unbind" - }); - } - }); - - const view_model_bind: string = "view_model_bind"; - packages.set("XyzViewModel", class XyzViewModel - { - bind (): Promise - { - expect(view_model_bind).toBe("view_model_bind"); - return Promise.resolve(); - } - - unbind (view: any) - { - expect(view).toBe("view_model_unbind"); - } - }); - - // @ts-ignore - next2d.fw.packages = packages; - - const context = new Context(new Sprite()); - context - .addChild("xyz") - .then((result) => - { - expect(result instanceof View).toBe(true); - }); - }); -}); \ No newline at end of file diff --git a/__tests__/domain/callback/CallbackTest.ts b/__tests__/domain/callback/CallbackTest.ts deleted file mode 100644 index ddcb1fa..0000000 --- a/__tests__/domain/callback/CallbackTest.ts +++ /dev/null @@ -1,87 +0,0 @@ -import "@next2d/player"; -import { Callback } from "../../../src/domain/callback/Callback"; -import { packages } from "../../../src"; - -describe("CallbackTest", () => -{ - test("execute test case1", () => - { - const callback = new Callback(); - callback - .execute() - .then((result) => - { - expect(result).toBe(undefined); - }); - }); - - test("execute single test", () => - { - // mock - const SingleTest = class SingleTest - { - execute (value: any): any - { - return value; - } - }; - - packages.clear(); - packages.set("SingleTest", SingleTest); - - const callback = new Callback(); - callback - .execute("SingleTest", "single test") - .then((results: string[] | void) => - { - if (!results) { - throw new Error("stop test"); - } - - expect(results.length).toBe(1); - const result: string = results[0]; - expect(result).toBe("single test"); - }); - }); - - test("execute multiple test", () => - { - // mock - const MultipleTestCase1 = class MultipleTest - { - execute (value: any): any - { - return `${value}_1`; - } - }; - - const MultipleTestCase2 = class MultipleTest - { - execute (value: any): any - { - return `${value}_2`; - } - }; - - packages.clear(); - packages.set("multiple.test.case1", MultipleTestCase1); - packages.set("multiple.test.case2", MultipleTestCase2); - - const callback = new Callback(); - callback - .execute(["multiple.test.case1", "multiple.test.case2"], "multiple test") - .then((results: string[] | void) => - { - if (!results) { - throw new Error("stop test"); - } - - expect(results.length).toBe(2); - const result1: string = results[0]; - expect(result1).toBe("multiple test_1"); - - const result2: string = results[1]; - expect(result2).toBe("multiple test_2"); - }); - }); -}); \ No newline at end of file diff --git a/__tests__/domain/convert/ToCamelCaseTest.ts b/__tests__/domain/convert/ToCamelCaseTest.ts deleted file mode 100644 index 6124b4b..0000000 --- a/__tests__/domain/convert/ToCamelCaseTest.ts +++ /dev/null @@ -1,23 +0,0 @@ -import "@next2d/player"; -import { ToCamelCase } from "../../../src/domain/convert/ToCamelCase"; - -describe("ToCamelCaseTest", () => -{ - test("execute test case1", () => - { - const toCamelCase = new ToCamelCase(); - expect(toCamelCase.execute("home")).toBe("Home"); - }); - - test("execute test case2", () => - { - const toCamelCase = new ToCamelCase(); - expect(toCamelCase.execute("quest/list")).toBe("QuestList"); - }); - - test("execute test case3", () => - { - const toCamelCase = new ToCamelCase(); - expect(toCamelCase.execute("game/list/page")).toBe("GameListPage"); - }); -}); diff --git a/__tests__/domain/loading/LoadingTest.ts b/__tests__/domain/loading/LoadingTest.ts deleted file mode 100644 index d2e84f5..0000000 --- a/__tests__/domain/loading/LoadingTest.ts +++ /dev/null @@ -1,154 +0,0 @@ -import "@next2d/player"; -import { Loading } from "../../../src/domain/loading/Loading"; -import { $setConfig } from "../../../src/application/variable/Config"; -import { packages } from "../../../src"; - -describe("LoadingTest", () => -{ - test("loading do not start and end test case not config", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {} - }; - - $setConfig(config); - - const loading = new Loading(); - expect(loading.start()).toBe(undefined); - expect(loading.end()).toBe(undefined); - }); - - test("loading do not start and end test case not callback", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {}, - "loading": { - "callback": "" - } - }; - - $setConfig(config); - - const loading = new Loading(); - expect(loading.start()).toBe(undefined); - expect(loading.end()).toBe(undefined); - }); - - test("default loading start and end test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {}, - "loading": { - "callback": "test" - } - }; - - $setConfig(config); - - const TestLoading = class TestLoading - { - private readonly startValue: string; - private readonly endValue: string; - - constructor() - { - this.startValue = "start"; - this.endValue = "end"; - } - - start () - { - expect(this.startValue).toBe("start"); - } - - end () - { - expect(this.endValue).toBe("end"); - } - }; - - packages.set("test", TestLoading); - packages.clear(); - - const loading = new Loading(); - loading.start(); - loading.end(); - }); - - test("callback loading start and end test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {}, - "loading": { - "callback": "origin.loader" - } - }; - - $setConfig(config); - - const OriginLoader = class OriginLoader - { - private readonly startValue: string; - private readonly endValue: string; - - constructor() - { - this.startValue = "origin start"; - this.endValue = "origin end"; - } - - start () - { - expect(this.startValue).toBe("origin start"); - } - - end () - { - expect(this.endValue).toBe("origin end"); - } - }; - - packages.clear(); - packages.set("origin.loader", OriginLoader); - - const loading = new Loading(); - loading.start(); - loading.end(); - }); -}); diff --git a/__tests__/domain/parser/ConfigParserTest.ts b/__tests__/domain/parser/ConfigParserTest.ts deleted file mode 100644 index e1ac7b5..0000000 --- a/__tests__/domain/parser/ConfigParserTest.ts +++ /dev/null @@ -1,104 +0,0 @@ -import "@next2d/player"; -import { parser } from "../../../src/application/variable/Parser"; -import { $setConfig } from "../../../src/application/variable/Config"; - -describe("ConfigParserTest", () => -{ - test("parse config test case1", () => - { - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {}, - "endPoint": "localhost", - "v1": "version/1" - }; - - $setConfig(config); - - expect(parser.execute("{{normal")).toBe("{{normal"); - }); - - test("parse config test case2", () => - { - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {}, - "endPoint": "localhost", - "v1": "version/1" - }; - - $setConfig(config); - - expect(parser.execute("{{ endPoint }}/{{ v1 }}/test")) - .toBe("localhost/version/1/test"); - }); - - test("parse config test case3", () => - { - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {}, - "api": { - "platform": { - "endPoint": "localhost" - } - }, - "v1": "version/1" - }; - - $setConfig(config); - - expect(parser.execute("{{ api.platform.endPoint }}/{{ v1 }}/test")) - .toBe("localhost/version/1/test"); - }); - - test("parse config test case4", () => - { - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "api": { - "platform": { - "endPoint": "localhost" - } - } - }; - - $setConfig(config); - - expect(parser.execute("{{ api.platform.endPoint }}/{{ v1 }}/test")) - .toBe("localhost/{{ v1 }}/test"); - }); - - test("parse config test case5", () => - { - expect(parser.execute()).toBe(""); - }); -}); \ No newline at end of file diff --git a/__tests__/domain/parser/QueryParserTest.ts b/__tests__/domain/parser/QueryParserTest.ts deleted file mode 100644 index c0675d2..0000000 --- a/__tests__/domain/parser/QueryParserTest.ts +++ /dev/null @@ -1,258 +0,0 @@ -import "@next2d/player"; -import { QueryParser } from "../../../src/domain/parser/QueryParser"; -import { query } from "../../../src"; -import { $setConfig } from "../../../src/application/variable/Config"; - -interface Object { - name: string; - queryString: string; -} - -describe("QueryParserTest", () => -{ - test("parse query test case1", () => - { - query.clear(); - query.set("test", 123); - expect(query.size).toBe(1); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute(); - - expect(query.size).toBe(0); - expect(object.name).toBe("top"); - expect(object.queryString).toBe(""); - }); - - test("parse query test case2", () => - { - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute("@test"); - - expect(query.size).toBe(0); - expect(object.name).toBe("test"); - expect(object.queryString).toBe(""); - }); - - test("parse location.search test case1", () => - { - // @ts-ignore - globalThis.location.search = "?q=abc&sample=1"; - - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute(""); - - expect(query.size).toBe(2); - expect(query.get("q")).toBe("abc"); - expect(query.get("sample")).toBe("1"); - expect(object.name).toBe("top"); - expect(object.queryString).toBe("?q=abc&sample=1"); - }); - - test("parse location.pathname un match test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "top": {} - } - }; - - $setConfig(config); - - // @ts-ignore - globalThis.location.pathname = "/quest/list"; - - // @ts-ignore - globalThis.location.search = "?q=xyz&sample=0"; - - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute(""); - - expect(query.size).toBe(2); - expect(query.get("q")).toBe("xyz"); - expect(query.get("sample")).toBe("0"); - expect(object.name).toBe("top"); - expect(object.queryString).toBe("?q=xyz&sample=0"); - }); - - test("parse location.pathname public test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "quest/list": { - "private": false - } - } - }; - - $setConfig(config); - - // @ts-ignore - globalThis.location.pathname = "/quest/list"; - - // @ts-ignore - globalThis.location.search = "?q=xyz&sample=0"; - - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute(""); - - expect(query.size).toBe(2); - expect(query.get("q")).toBe("xyz"); - expect(query.get("sample")).toBe("0"); - expect(object.name).toBe("quest/list"); - expect(object.queryString).toBe("?q=xyz&sample=0"); - }); - - test("parse location.pathname private test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "quest/list": { - "private": true - } - } - }; - - $setConfig(config); - - // @ts-ignore - globalThis.location.pathname = "/quest/list"; - - // @ts-ignore - globalThis.location.search = "?q=xyz&sample=0"; - - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute(""); - - expect(query.size).toBe(2); - expect(query.get("q")).toBe("xyz"); - expect(query.get("sample")).toBe("0"); - expect(object.name).toBe("top"); - expect(object.queryString).toBe("?q=xyz&sample=0"); - }); - - test("parse location.pathname redirect test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "quest/list": { - "private": true, - "redirect": "quest/detail" - } - } - }; - - $setConfig(config); - - // @ts-ignore - globalThis.location.pathname = "/quest/list"; - - // @ts-ignore - globalThis.location.search = "?q=xyz&sample=0"; - - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute(""); - - expect(query.size).toBe(2); - expect(query.get("q")).toBe("xyz"); - expect(query.get("sample")).toBe("0"); - expect(object.name).toBe("quest/detail"); - expect(object.queryString).toBe("?q=xyz&sample=0"); - }); - - test("parse name query test", () => - { - // mock - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute("page/test?abc=123&xyz=999"); - - expect(query.size).toBe(2); - expect(query.get("abc")).toBe("123"); - expect(query.get("xyz")).toBe("999"); - expect(object.name).toBe("page/test"); - expect(object.queryString).toBe("?abc=123&xyz=999"); - }); - - test("parse name path test case1", () => - { - // mock - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute("./test"); - - expect(query.size).toBe(0); - expect(object.name).toBe("test"); - }); - - test("parse name path test case2", () => - { - // mock - query.clear(); - expect(query.size).toBe(0); - - const queryParser = new QueryParser(); - const object: Object = queryParser.execute("./"); - - expect(query.size).toBe(0); - expect(object.name).toBe("top"); - }); -}); \ No newline at end of file diff --git a/__tests__/domain/parser/RequestParserTest.ts b/__tests__/domain/parser/RequestParserTest.ts deleted file mode 100644 index f2a33b8..0000000 --- a/__tests__/domain/parser/RequestParserTest.ts +++ /dev/null @@ -1,156 +0,0 @@ -import "@next2d/player"; -import { RequestParser } from "../../../src/domain/parser/RequestParser"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { $setConfig } from "../../../src/application/variable/Config"; -import { RequestTypeImpl } from "../../../src/interface/RequestTypeImpl"; - -interface Object { - type: RequestTypeImpl; - name: string; - path: string; - cache?: boolean; - class: string; - access: string; - method: string; - callback?: string | string[]; -} - -describe("RequestParserTest", () => -{ - test("request parse no match test case1", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": {} - }; - - $setConfig(config); - - const requestParser: RequestParser = new RequestParser(); - const requests: Object[] = requestParser.execute("top"); - expect(requests.length).toBe(0); - }); - - test("request parse no match test case2", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "top": {} - } - }; - - $setConfig(config); - - const requestParser: RequestParser = new RequestParser(); - const requests: Object[] = requestParser.execute("top"); - expect(requests.length).toBe(0); - }); - - test("request parse match test case1", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "top": { - "requests": [ - { - "type": RequestType.JSON, - "name": "TopTest", - "path": "local" - } - ] - } - } - }; - - $setConfig(config); - - const requestParser: RequestParser = new RequestParser(); - const requests: Object[] = requestParser.execute("top"); - expect(requests.length).toBe(1); - - const object: Object = requests[0]; - expect(object.type).toBe(RequestType.JSON); - expect(object.name).toBe("TopTest"); - expect(object.path).toBe("local"); - }); - - test("request parse cluster test case1", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "@sample": { - "requests": [ - { - "type": RequestType.CONTENT, - "path": "{{ content.endPoint }}content/sample.json", - "name": "MainContent", - "cache": true - } - ] - }, - "top": { - "requests": [ - { - "type": RequestType.CLUSTER, - "path": "@sample" - }, - { - "type": RequestType.JSON, - "path": "{{ api.endPoint }}api/top.json", - "name": "TopText" - } - ] - } - } - }; - - $setConfig(config); - - const requestParser: RequestParser = new RequestParser(); - const requests: Object[] = requestParser.execute("top"); - expect(requests.length).toBe(2); - - const object1: Object = requests[0]; - expect(object1.type).toBe(RequestType.CONTENT); - expect(object1.name).toBe("MainContent"); - - const object2: Object = requests[1]; - expect(object2.type).toBe(RequestType.JSON); - expect(object2.name).toBe("TopText"); - }); -}); \ No newline at end of file diff --git a/__tests__/domain/screen/CaptureTest.ts b/__tests__/domain/screen/CaptureTest.ts deleted file mode 100644 index eb1a7cb..0000000 --- a/__tests__/domain/screen/CaptureTest.ts +++ /dev/null @@ -1,44 +0,0 @@ -import "@next2d/player"; -import { Capture } from "../../../src/domain/screen/Capture"; -import { context, $createContext } from "../../../src/application/variable/Context"; -import { $setConfig } from "../../../src/application/variable/Config"; - -describe("CaptureTest", () => -{ - test("execute test", () => - { - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - } - }; - - $setConfig(config); - const capture = new Capture(); - if (context) { - capture - .execute() - .then((result: void) => - { - expect(result).toBe(undefined); - }); - } else { - $createContext(config) - .then(() => - { - capture - .execute() - .then((result: void) => - { - expect(result).toBe(undefined); - }); - }); - } - }); -}); \ No newline at end of file diff --git a/__tests__/domain/screen/DefaultLoadingTest.ts b/__tests__/domain/screen/DefaultLoadingTest.ts deleted file mode 100644 index d507824..0000000 --- a/__tests__/domain/screen/DefaultLoadingTest.ts +++ /dev/null @@ -1,162 +0,0 @@ -import "@next2d/player"; -import { DefaultLoading } from "../../../src"; -import { $setConfig } from "../../../src/application/variable/Config"; -import { $createContext, context } from "../../../src/application/variable/Context"; - -describe("DefaultLoadingTest", () => -{ - test("start function no element test", () => - { - // @ts-ignore - $elements.clear(); - - // @ts-ignore - $elements.set( - "__next2d__framework_loading", - // @ts-ignore - document.createElement() - ); - - const defaultLoading = new DefaultLoading(); - defaultLoading.start(); - - const element = document - .getElementById("__next2d__framework_loading"); - - if (element) { - expect(element.getAttribute("style")).toBe(""); - } - }); - - test("start function no parent test", () => - { - // @ts-ignore - $elements.clear(); - - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - } - }; - - $setConfig(config); - if (context) { - const defaultLoading = new DefaultLoading(); - defaultLoading.start(); - - // @ts-ignore - expect($elements.size).toBe(0); - } else { - $createContext(config) - .then(() => - { - const defaultLoading = new DefaultLoading(); - defaultLoading.start(); - - // @ts-ignore - expect($elements.size).toBe(0); - }); - } - - }); - - test("start function test", () => - { - // @ts-ignore - $elements.clear(); - - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - } - }; - - $setConfig(config); - if (context) { - // @ts-ignore - $elements.clear(); - - // @ts-ignore - $elements.set("__next2d__", document.createElement()); - - const defaultLoading = new DefaultLoading(); - defaultLoading.start(); - - const element = document - .getElementById("__next2d__framework_loading"); - - if (element) { - expect(element.id).toBe("__next2d__framework_loading"); - } - } else { - $createContext(config) - .then(() => - { - // @ts-ignore - $elements.clear(); - - // @ts-ignore - $elements.set("__next2d__", document.createElement()); - - const defaultLoading = new DefaultLoading(); - defaultLoading.start(); - - const element = document - .getElementById("__next2d__framework_loading"); - - if (element) { - expect(element.id).toBe("__next2d__framework_loading"); - } - }); - } - }); - - test("end function no element test", () => - { - // @ts-ignore - $elements.clear(); - - const defaultLoading = new DefaultLoading(); - defaultLoading.end(); - - const element = document - .getElementById("__next2d__framework_loading"); - - expect(element).toBe(null); - }); - - test("end function element test", () => - { - // @ts-ignore - $elements.clear(); - - // @ts-ignore - $elements.set( - "__next2d__framework_loading", - // @ts-ignore - document.createElement() - ); - - const defaultLoading = new DefaultLoading(); - defaultLoading.end(); - - const element = document - .getElementById("__next2d__framework_loading"); - - if (element) { - expect(element.getAttribute("style")).toBe("display:none;"); - } - }); -}); \ No newline at end of file diff --git a/__tests__/infrastructure/constant/RequestTypeTest.ts b/__tests__/infrastructure/constant/RequestTypeTest.ts deleted file mode 100644 index 567db59..0000000 --- a/__tests__/infrastructure/constant/RequestTypeTest.ts +++ /dev/null @@ -1,13 +0,0 @@ -import "@next2d/player"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; - -describe("RequestType Test", () => -{ - test("const check", () => - { - expect(RequestType.CLUSTER).toBe("cluster"); - expect(RequestType.CONTENT).toBe("content"); - expect(RequestType.CUSTOM).toBe("custom"); - expect(RequestType.JSON).toBe("json"); - }); -}); diff --git a/__tests__/infrastructure/dto/ResponseDTOTest.ts b/__tests__/infrastructure/dto/ResponseDTOTest.ts deleted file mode 100644 index 0cac7c0..0000000 --- a/__tests__/infrastructure/dto/ResponseDTOTest.ts +++ /dev/null @@ -1,19 +0,0 @@ -import "@next2d/player"; -import { ResponseDTO } from "../../../src/infrastructure/dto/ResponseDTO"; - -describe("ResponseDTO Test", () => -{ - test("property check case1", () => - { - const responseDTO: ResponseDTO = new ResponseDTO("string", "any"); - expect(responseDTO.name).toBe("string"); - expect(responseDTO.response).toBe("any"); - }); - - test("property check case2", () => - { - const responseDTO: ResponseDTO = new ResponseDTO(); - expect(responseDTO.name).toBe(""); - expect(responseDTO.response).toBe(null); - }); -}); diff --git a/__tests__/infrastructure/repository/ContentRepositoryTest.ts b/__tests__/infrastructure/repository/ContentRepositoryTest.ts deleted file mode 100644 index f40d259..0000000 --- a/__tests__/infrastructure/repository/ContentRepositoryTest.ts +++ /dev/null @@ -1,54 +0,0 @@ -import "@next2d/player"; -import { ContentRepository } from "../../../src/infrastructure/repository/ContentRepository"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { cache } from "../../../src"; -import { loaderInfoMap } from "../../../src"; - -interface Object { - type: string; - name: string; - path: string; - cache?: boolean; - callback?: string|string[]; - method?: string; - body?: object; - headers?: HeadersInit; -} - -describe("ContentRepository Test", () => -{ - test("execute json content test", () => - { - // reset - cache.clear(); - loaderInfoMap.clear(); - - const object: Object = { - "type": RequestType.CONTENT, - "name": "ContentRepository", - "path": "", - "method": "GET", - "body": { - "sample": 12345 - }, - "headers": { - "Content-Type": "application/json" - } - }; - - expect(cache.size).toBe(0); - expect(loaderInfoMap.size).toBe(0); - - const contentRepository = new ContentRepository(); - contentRepository - .execute(object) - .then((response: any) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.text).toBe("NoCode Tool content"); - }); - }); -}); \ No newline at end of file diff --git a/__tests__/infrastructure/repository/CustomRepositoryTest.ts b/__tests__/infrastructure/repository/CustomRepositoryTest.ts deleted file mode 100644 index 0cc73d4..0000000 --- a/__tests__/infrastructure/repository/CustomRepositoryTest.ts +++ /dev/null @@ -1,108 +0,0 @@ -import "@next2d/player"; -import { CustomRepository } from "../../../src/infrastructure/repository/CustomRepository"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { packages } from "../../../src"; - -interface Object { - type: string; - name: string; - path: string; - cache?: boolean; - class: string; - access: string; - method: string; - callback?: string|string[]; - body?: object; - headers?: HeadersInit; -} - -describe("CustomRepository Test", () => -{ - test("execute public test", () => - { - // mock - const object: Object = { - "type": RequestType.CUSTOM, - "name": "CustomRepository", - "path": "next2d", - "method": "publicGet", - "access": "public", - "class": "CustomClass" - }; - - const CustomClass = class CustomClass - { - publicGet () - { - return "publicGet"; - } - }; - - packages.clear(); - packages.set("CustomClass", CustomClass); - - const customRepository = new CustomRepository(); - customRepository - .execute(object) - .then((response) => - { - expect(response).toBe("publicGet"); - }); - }); - - test("execute static test", () => - { - // mock - - const object: Object = { - "type": RequestType.CUSTOM, - "name": "CustomRepository", - "path": "next2d", - "method": "staticGet", - "access": "static", - "class": "CustomClass" - }; - - const CustomClass = class CustomClass - { - static staticGet () - { - return "staticGet"; - } - }; - - packages.clear(); - packages.set("CustomClass", CustomClass); - - const customRepository = new CustomRepository(); - customRepository - .execute(object) - .then((response) => - { - expect(response).toBe("staticGet"); - }); - }); - - test("execute not found test", () => - { - // mock - const object: Object = { - "type": RequestType.CUSTOM, - "name": "CustomRepository", - "path": "next2d", - "method": "staticGet", - "access": "static", - "class": "CustomClass" - }; - - packages.clear(); - - const customRepository = new CustomRepository(); - customRepository - .execute(object) - .then((response) => - { - expect(response).toBe(null); - }); - }); -}); diff --git a/__tests__/infrastructure/service/ContentServiceTest.ts b/__tests__/infrastructure/service/ContentServiceTest.ts deleted file mode 100644 index d94de51..0000000 --- a/__tests__/infrastructure/service/ContentServiceTest.ts +++ /dev/null @@ -1,165 +0,0 @@ -import "@next2d/player"; -import { ContentService } from "../../../src/infrastructure/service/ContentService"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { ResponseDTO } from "../../../src/infrastructure/dto/ResponseDTO"; -import { - cache, - packages, - loaderInfoMap -} from "../../../src"; - -interface Object { - type: string; - name: string; - path: string; - cache?: boolean; - callback?: string|string[]; - method?: string; - body?: object; - headers?: HeadersInit; -} - -describe("ContentService Test", () => -{ - test("execute fetch test use cache", () => - { - // mock - cache.clear(); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value.text).toBe("NoCode Tool content"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback_Case1", TestCallback); - - loaderInfoMap.clear(); - - const contentService = new ContentService(); - - const object: Object = { - "type": RequestType.CONTENT, - "name": "ContentRepository", - "path": "", - "cache": true, - "callback": "TestCallback_Case1" - }; - - expect(cache.size).toBe(0); - expect(loaderInfoMap.size).toBe(0); - - contentService - .execute(object) - .then((response: ResponseDTO | void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("ContentRepository"); - expect(response.response.text).toBe("NoCode Tool content"); - - expect(cache.size).toBe(1); - expect(cache.get("ContentRepository").text).toBe("NoCode Tool content"); - - expect(loaderInfoMap.size).toBe(1); - // @ts-ignore - expect(loaderInfoMap.get("app")._$data.symbols.get("app")).toBe("app"); - }); - }); - - test("execute fetch test no use cache", () => - { - // mock - cache.clear(); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value.text).toBe("NoCode Tool content"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback_Case1", TestCallback); - - loaderInfoMap.clear(); - - const contentService = new ContentService(); - - const object: Object = { - "type": RequestType.CONTENT, - "name": "ContentRepository", - "path": "", - "callback": "TestCallback_Case1" - }; - - expect(cache.size).toBe(0); - expect(loaderInfoMap.size).toBe(0); - - contentService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("ContentRepository"); - expect(response.response.text).toBe("NoCode Tool content"); - - expect(cache.size).toBe(0); - - expect(loaderInfoMap.size).toBe(1); - // @ts-ignore - expect(loaderInfoMap.get("app")._$data.symbols.get("app")).toBe("app"); - }); - }); - - test("execute cache test", () => - { - // mock - cache.set("ContentRepository", "success cache content"); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value).toBe("success cache content"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback_Case2", TestCallback); - - const contentService = new ContentService(); - - const object: Object = { - "type": RequestType.CONTENT, - "name": "ContentRepository", - "cache": true, - "callback": "TestCallback_Case2", - "path": "" - }; - - contentService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("ContentRepository"); - expect(response.response).toBe("success cache content"); - }); - }); -}); \ No newline at end of file diff --git a/__tests__/infrastructure/service/CustomServiceTest.ts b/__tests__/infrastructure/service/CustomServiceTest.ts deleted file mode 100644 index 298c17a..0000000 --- a/__tests__/infrastructure/service/CustomServiceTest.ts +++ /dev/null @@ -1,183 +0,0 @@ -import "@next2d/player"; -import { CustomService } from "../../../src/infrastructure/service/CustomService"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { ResponseDTO } from "../../../src/infrastructure/dto/ResponseDTO"; -import { - cache, - packages -} from "../../../src"; - -interface Object { - type: string; - name: string; - path: string; - cache?: boolean; - class: string; - access: string; - method: string; - callback?: string|string[]; - body?: object; - headers?: HeadersInit; -} - -describe("CustomService Test", () => -{ - test("execute load test use cache", () => - { - // mock - cache.clear(); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value).toBe("success custom"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback", TestCallback); - - const TestRepository = { - "get": () => { - return "success custom"; - } - }; - - packages.set("TestRepository", TestRepository); - - const customService = new CustomService(); - - const object: Object = { - "type": RequestType.CUSTOM, - "class": "TestRepository", - "access": "static", - "method": "get", - "name": "CustomRepository", - "callback": "TestCallback", - "path": "", - "cache": true - }; - - expect(cache.size).toBe(0); - - customService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("CustomRepository"); - expect(response.response).toBe("success custom"); - expect(cache.size).toBe(1); - expect(cache.get("CustomRepository")).toBe("success custom"); - }); - }); - - test("execute load test no use cache", () => - { - // mock - cache.clear(); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value).toBe("success custom"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback", TestCallback); - - const TestRepository = { - "get": () => { - return "success custom"; - } - }; - - packages.set("TestRepository", TestRepository); - - const customService = new CustomService(); - - const object: Object = { - "type": RequestType.CUSTOM, - "class": "TestRepository", - "access": "static", - "method": "get", - "name": "CustomRepository", - "callback": "TestCallback", - "path": "" - }; - - expect(cache.size).toBe(0); - - customService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("CustomRepository"); - expect(response.response).toBe("success custom"); - expect(cache.size).toBe(0); - }); - }); - - test("execute cache test", () => - { - // mock - cache.set("CustomRepository", "success cache custom"); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value).toBe("success cache custom"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback", TestCallback); - - const TestRepository = { - "get": () => { - return "success custom"; - } - }; - - packages.set("TestRepository", TestRepository); - - const customService = new CustomService(); - - const object: Object = { - "type": RequestType.CUSTOM, - "class": "TestRepository", - "access": "static", - "method": "get", - "name": "CustomRepository", - "callback": "TestCallback", - "cache": true, - "path": "" - }; - - customService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("CustomRepository"); - expect(response.response).toBe("success cache custom"); - }); - }); -}); \ No newline at end of file diff --git a/__tests__/infrastructure/service/JsonServiceTest.ts b/__tests__/infrastructure/service/JsonServiceTest.ts deleted file mode 100644 index 02ef767..0000000 --- a/__tests__/infrastructure/service/JsonServiceTest.ts +++ /dev/null @@ -1,174 +0,0 @@ -import "@next2d/player"; -import { JsonService } from "../../../src/infrastructure/service/JsonService"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { ResponseDTO } from "../../../src/infrastructure/dto/ResponseDTO"; -import { - cache, - packages -} from "../../../src"; - -interface Object { - type: string; - name: string; - path: string; - cache?: boolean; - callback?: string | string[]; - method?: string; - body?: object; - headers?: HeadersInit; -} - -describe("JsonService Test", () => -{ - test("execute fetch test use cache", () => - { - // mock - cache.clear(); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value).toBe("success fetch json"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback_Case1", TestCallback); - - const jsonService = new JsonService(); - - const object: Object = { - "type": RequestType.JSON, - "name": "JSONRepository", - "cache": true, - "path": "", - "callback": "TestCallback_Case1" - }; - - const responseMock = () => Promise.resolve({ - "status": 200, - "json": () => { - return Promise.resolve("success fetch json"); - } - }); - global.fetch = jest.fn().mockImplementation(responseMock); - - expect(cache.size).toBe(0); - - jsonService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("JSONRepository"); - expect(response.response).toBe("success fetch json"); - expect(cache.size).toBe(1); - expect(cache.get("JSONRepository")).toBe("success fetch json"); - }); - }); - - test("execute fetch test no use cache", () => - { - // mock - cache.clear(); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value).toBe("success fetch json"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback_Case1", TestCallback); - - const jsonService = new JsonService(); - - const object: Object = { - "type": RequestType.JSON, - "name": "JSONRepository", - "path": "", - "callback": "TestCallback_Case1" - }; - - const responseMock = () => Promise.resolve({ - "status": 200, - "json": () => { - return Promise.resolve("success fetch json"); - } - }); - global.fetch = jest.fn().mockImplementation(responseMock); - - expect(cache.size).toBe(0); - - jsonService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("JSONRepository"); - expect(response.response).toBe("success fetch json"); - expect(cache.size).toBe(0); - }); - }); - - test("execute cache test", () => - { - // mock - cache.set("JSONRepository", "success cache json"); - - const TestCallback = function () - { - return { - "execute": (value: any) => { - expect(value).toBe("success cache json"); - } - }; - }; - - packages.clear(); - packages.set("TestCallback_Case2", TestCallback); - - const jsonService = new JsonService(); - - const object: Object = { - "type": RequestType.JSON, - "name": "JSONRepository", - "cache": true, - "callback": "TestCallback_Case2", - "path": "" - }; - - const responseMock = () => Promise.resolve({ - "status": 200, - "json": () => { - return { - "result": "success json" - }; - } - }); - global.fetch = jest.fn().mockImplementation(responseMock); - - jsonService - .execute(object) - .then((response: ResponseDTO|void) => - { - if (!response) { - throw new Error("stop test"); - } - - expect(response.name).toBe("JSONRepository"); - expect(response.response).toBe("success cache json"); - }); - }); -}); \ No newline at end of file diff --git a/__tests__/infrastructure/usecase/RequestUseCaseTest.ts b/__tests__/infrastructure/usecase/RequestUseCaseTest.ts deleted file mode 100644 index 14fd3e6..0000000 --- a/__tests__/infrastructure/usecase/RequestUseCaseTest.ts +++ /dev/null @@ -1,99 +0,0 @@ -import "@next2d/player"; -import { RequestUseCase } from "../../../src/infrastructure/usecase/RequestUseCase"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { ResponseDTO } from "../../../src/infrastructure/dto/ResponseDTO"; -import { $setPackages } from "../../../src/application/variable/Packages"; -import { $setConfig } from "../../../src/application/variable/Config"; -import { - cache, - packages -} from "../../../src"; - -describe("RequestUseCase Test", () => -{ - test("request test", () => - { - const TestRepository = { - "get": () => { - return "success custom"; - } - }; - - packages.clear(); - packages.set("TestRepository", TestRepository); - - $setPackages(Array.from(packages)); - - cache.clear(); - cache.set("JSONRepository", "success json"); - cache.set("ContentRepository", "success content"); - - // mock - const config = { - "platform": "web", - "spa": true, - "stage": { - "width": 240, - "height": 240, - "fps": 12, - "options": {} - }, - "routing": { - "test": { - "requests": [ - { - "type": RequestType.CUSTOM, - "class": "TestRepository", - "access": "static", - "method": "get", - "name": "TestRepository" - }, - { - "type": RequestType.JSON, - "cache": true, - "name": "JSONRepository" - }, - { - "type": RequestType.CONTENT, - "cache": true, - "name": "ContentRepository" - } - ] - } - } - }; - - $setConfig(config); - - const requestUseCase: RequestUseCase = new RequestUseCase(); - const promises = requestUseCase.execute("test"); - - Promise - .all(promises) - .then((responses) => - { - expect(responses.length).toBe(3); - - const customResponse: ResponseDTO|void = responses[0]; - if (!customResponse) { - throw new Error("stop test"); - } - expect(customResponse.name).toBe("TestRepository"); - expect(customResponse.response).toBe("success custom"); - - const jsonResponse: ResponseDTO|void = responses[1]; - if (!jsonResponse) { - throw new Error("stop test"); - } - expect(jsonResponse.name).toBe("JSONRepository"); - expect(jsonResponse.response).toBe("success json"); - - const contentResponse: ResponseDTO|void = responses[2]; - if (!contentResponse) { - throw new Error("stop test"); - } - expect(contentResponse.name).toBe("ContentRepository"); - expect(contentResponse.response).toBe("success content"); - }); - }); -}); diff --git a/__tests__/view/ViewModelTest.ts b/__tests__/view/ViewModelTest.ts deleted file mode 100644 index 464c729..0000000 --- a/__tests__/view/ViewModelTest.ts +++ /dev/null @@ -1,41 +0,0 @@ -import "@next2d/player"; -import { - View, - ViewModel -} from "../../src"; - -describe("ViewModelTest", () => -{ - test("bind call test", () => - { - const view: View = new View(); - const viewModel: ViewModel = new ViewModel(); - - viewModel - .bind(view) - .then((result) => - { - expect(result instanceof View).toBe(true); - }); - - }); - - test("unbind call test", () => - { - const viewModel: ViewModel = new ViewModel(); - expect(viewModel.unbind(new View())).toBe(undefined); - }); - - test("factory call test", () => - { - const view: View = new View(); - const viewModel: ViewModel = new ViewModel(); - - viewModel - .factory(view) - .then((result) => - { - expect(result instanceof View).toBe(true); - }); - }); -}); \ No newline at end of file diff --git a/__tests__/view/ViewTest.ts b/__tests__/view/ViewTest.ts deleted file mode 100644 index 21c7fd6..0000000 --- a/__tests__/view/ViewTest.ts +++ /dev/null @@ -1,10 +0,0 @@ -import "@next2d/player"; -import { View } from "../../src"; - -describe("ViewTest", () => -{ - test("initialize call test", () => { - const view: View = new View(); - expect(typeof view.initialize).toBe("function"); - }); -}); \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..b3afcd3 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,142 @@ +import unusedImports from "eslint-plugin-unused-imports"; +import globals from "globals"; +import tsParser from "@typescript-eslint/parser"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + "baseDirectory": __dirname, + "recommendedConfig": js.configs.recommended, + "allConfig": js.configs.all +}); + +export default [ + { + "ignores": [ + "**/node_modules/*", + "**/dist", + "**/build", + "**/json", + "**/@types", + "**/.github", + "**/*.test.ts" + ] + }, + ...compat.extends("plugin:@typescript-eslint/eslint-recommended"), + { + "plugins": { + "unused-imports": unusedImports + }, + "languageOptions": { + "globals": { + ...globals.browser + }, + + "parser": tsParser, + "ecmaVersion": "latest", + "sourceType": "module" + }, + + "rules": { + "no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + + "unused-imports/no-unused-vars": ["warn", { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_" + }], + + "no-var": "error", + + "semi": ["error", "always", { + "omitLastInOneLineBlock": true + }], + + "block-spacing": "error", + + "indent": ["error", 4, { + "SwitchCase": 1 + }], + + "no-mixed-spaces-and-tabs": "error", + + "no-multiple-empty-lines": ["error", { + "max": 1 + }], + + "no-trailing-spaces": "error", + "space-infix-ops": "error", + "dot-notation": "error", + "eqeqeq": "error", + "quotes": ["error", "double"], + "no-else-return": "error", + "no-loop-func": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "no-undef": "off", + "comma-dangle": "warn", + "no-use-before-define": "off", + "no-const-assign": "error", + "space-before-blocks": "error", + "no-unexpected-multiline": "error", + "object-curly-spacing": ["error", "always"], + "quote-props": ["error", "always"], + + "max-len": ["error", { + "code": 200, + "ignoreStrings": true, + "ignoreComments": true, + "ignoreTemplateLiterals": true + }], + + "no-debugger": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty": "error", + "no-extra-parens": "error", + "no-func-assign": "error", + "no-irregular-whitespace": "error", + "no-sparse-arrays": "error", + "no-unreachable": "error", + "no-unsafe-negation": "error", + "use-isnan": "error", + "block-scoped-var": "error", + "no-caller": "error", + "curly": "error", + "no-case-declarations": "error", + "no-floating-decimal": "error", + "no-eq-null": "error", + "no-empty-function": "error", + "no-empty-pattern": "error", + "no-extend-native": "error", + "dot-location": ["error", "property"], + "no-global-assign": "error", + "no-implicit-globals": "error", + "no-invalid-this": "error", + "no-lone-blocks": "error", + "no-iterator": "error", + "no-new": "error", + "no-proto": "error", + "no-return-assign": "error", + "no-self-assign": "error", + "no-self-compare": "error", + "no-useless-concat": "error", + "no-useless-call": "error", + "no-useless-return": "error", + "no-unused-expressions": "error", + "no-class-assign": "error", + "no-sequences": "error", + "no-dupe-args": "error", + "no-extra-boolean-cast": "error", + "no-obj-calls": "error", + "no-console": "off", + "no-extra-semi": "warn" + } + } +]; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e5fa66f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4045 @@ +{ + "name": "@next2d/framework", + "version": "3.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@next2d/framework", + "version": "3.0.0", + "license": "MIT", + "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.23.0", + "@types/node": "^22.13.11", + "@typescript-eslint/eslint-plugin": "^8.27.0", + "@typescript-eslint/parser": "^8.27.0", + "@vitest/web-worker": "^3.0.9", + "eslint": "^9.23.0", + "eslint-plugin-unused-imports": "^4.1.4", + "globals": "^16.0.0", + "jsdom": "^26.0.0", + "typescript": "^5.8.2", + "vite": "^6.2.2", + "vitest": "^3.0.9", + "vitest-webgl-canvas-mock": "^1.1.0" + }, + "peerDependencies": { + "@next2d/cache": "file:../player/packages/cache", + "@next2d/core": "file:../player/packages/core", + "@next2d/display": "file:../player/packages/display", + "@next2d/events": "file:../player/packages/events", + "@next2d/filters": "file:../player/packages/filters", + "@next2d/geom": "file:../player/packages/geom", + "@next2d/media": "file:../player/packages/media", + "@next2d/net": "file:../player/packages/net", + "@next2d/player": "file:../player", + "@next2d/render-queue": "file:../player/packages/render-queue", + "@next2d/renderer": "file:../player/packages/renderer", + "@next2d/text": "file:../player/packages/text", + "@next2d/texture-packer": "file:../player/packages/texture-packer", + "@next2d/ui": "file:../player/packages/ui", + "@next2d/webgl": "file:../player/packages/webgl" + } + }, + "../player": { + "name": "@next2d/player", + "version": "2.0.0", + "license": "MIT", + "peer": true, + "workspaces": [ + "packages/*" + ], + "dependencies": { + "fflate": "^0.8.2", + "htmlparser2": "^10.0.0" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.23.0", + "@types/node": "^22.13.11", + "@typescript-eslint/eslint-plugin": "^8.27.0", + "@typescript-eslint/parser": "^8.27.0", + "@vitest/web-worker": "^3.0.9", + "eslint": "^9.23.0", + "eslint-plugin-unused-imports": "^4.1.4", + "globals": "^16.0.0", + "jsdom": "^26.0.0", + "typescript": "^5.8.2", + "vite": "^6.2.2", + "vitest": "^3.0.9", + "vitest-webgl-canvas-mock": "^1.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Next2D" + }, + "peerDependencies": { + "@next2d/cache": "file:packages/cache", + "@next2d/core": "file:packages/core", + "@next2d/display": "file:packages/display", + "@next2d/events": "file:packages/events", + "@next2d/filters": "file:packages/filters", + "@next2d/geom": "file:packages/geom", + "@next2d/media": "file:packages/media", + "@next2d/net": "file:packages/net", + "@next2d/render-queue": "file:packages/render-queue", + "@next2d/renderer": "file:packages/renderer", + "@next2d/text": "file:packages/text", + "@next2d/texture-packer": "file:packages/texture-packer", + "@next2d/ui": "file:packages/ui", + "@next2d/webgl": "file:packages/webgl" + } + }, + "../player/packages/cache": { + "name": "@next2d/cache", + "version": "*", + "license": "MIT", + "peer": true + }, + "../player/packages/core": { + "name": "@next2d/core", + "version": "*", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@next2d/core": "file:../core", + "@next2d/display": "file:../display", + "@next2d/events": "file:../events", + "@next2d/filters": "file:../filters", + "@next2d/geom": "file:../geom", + "@next2d/media": "file:../media", + "@next2d/net": "file:../net", + "@next2d/render-queue": "file:../render-queue", + "@next2d/renderer": "file:../renderer", + "@next2d/text": "file:../text", + "@next2d/ui": "file:../ui" + } + }, + "../player/packages/display": { + "name": "@next2d/display", + "version": "*", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@next2d/events": "file:../events", + "@next2d/filters": "file:../filters", + "@next2d/geom": "file:../geom", + "@next2d/media": "file:../media", + "@next2d/net": "file:../net", + "@next2d/render-queue": "file:../render-queue", + "@next2d/text": "file:../text", + "@next2d/ui": "file:../ui" + } + }, + "../player/packages/events": { + "name": "@next2d/events", + "version": "*", + "license": "MIT", + "peer": true + }, + "../player/packages/filters": { + "name": "@next2d/filters", + "version": "*", + "license": "MIT", + "peer": true + }, + "../player/packages/geom": { + "name": "@next2d/geom", + "version": "*", + "license": "MIT", + "peer": true + }, + "../player/packages/media": { + "name": "@next2d/media", + "version": "*", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@next2d/display": "file:../display", + "@next2d/events": "file:../events", + "@next2d/geom": "file:../geom", + "@next2d/net": "file:../net" + } + }, + "../player/packages/net": { + "name": "@next2d/net", + "version": "*", + "license": "MIT", + "peer": true + }, + "../player/packages/render-queue": { + "name": "@next2d/render-queue", + "version": "*", + "license": "MIT", + "peer": true + }, + "../player/packages/renderer": { + "name": "@next2d/renderer", + "version": "*", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@next2d/cache": "file:../cache", + "@next2d/texture-packer": "file:../texture-packer", + "@next2d/webgl": "file:../webgl" + } + }, + "../player/packages/text": { + "name": "@next2d/text", + "version": "*", + "license": "MIT", + "peer": true, + "dependencies": { + "htmlparser2": "^10.0.0" + }, + "peerDependencies": { + "@next2d/cache": "file:../cache", + "@next2d/display": "file:../display", + "@next2d/events": "file:../events", + "@next2d/geom": "file:../geom", + "@next2d/ui": "file:../ui" + } + }, + "../player/packages/texture-packer": { + "name": "@next2d/texture-packer", + "version": "*", + "license": "MIT", + "peer": true + }, + "../player/packages/ui": { + "name": "@next2d/ui", + "version": "*", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@next2d/events": "file:../events" + } + }, + "../player/packages/webgl": { + "name": "@next2d/webgl", + "version": "*", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@next2d/render-queue": "file:../render-queue", + "@next2d/texture-packer": "file:../texture-packer" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.1.1.tgz", + "integrity": "sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.2", + "@csstools/css-color-parser": "^3.0.8", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.2.tgz", + "integrity": "sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.8.tgz", + "integrity": "sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", + "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.0.tgz", + "integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.12.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@next2d/cache": { + "resolved": "../player/packages/cache", + "link": true + }, + "node_modules/@next2d/core": { + "resolved": "../player/packages/core", + "link": true + }, + "node_modules/@next2d/display": { + "resolved": "../player/packages/display", + "link": true + }, + "node_modules/@next2d/events": { + "resolved": "../player/packages/events", + "link": true + }, + "node_modules/@next2d/filters": { + "resolved": "../player/packages/filters", + "link": true + }, + "node_modules/@next2d/geom": { + "resolved": "../player/packages/geom", + "link": true + }, + "node_modules/@next2d/media": { + "resolved": "../player/packages/media", + "link": true + }, + "node_modules/@next2d/net": { + "resolved": "../player/packages/net", + "link": true + }, + "node_modules/@next2d/player": { + "resolved": "../player", + "link": true + }, + "node_modules/@next2d/render-queue": { + "resolved": "../player/packages/render-queue", + "link": true + }, + "node_modules/@next2d/renderer": { + "resolved": "../player/packages/renderer", + "link": true + }, + "node_modules/@next2d/text": { + "resolved": "../player/packages/text", + "link": true + }, + "node_modules/@next2d/texture-packer": { + "resolved": "../player/packages/texture-packer", + "link": true + }, + "node_modules/@next2d/ui": { + "resolved": "../player/packages/ui", + "link": true + }, + "node_modules/@next2d/webgl": { + "resolved": "../player/packages/webgl", + "link": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz", + "integrity": "sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.36.0.tgz", + "integrity": "sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.36.0.tgz", + "integrity": "sha512-JQ1Jk5G4bGrD4pWJQzWsD8I1n1mgPXq33+/vP4sk8j/z/C2siRuxZtaUA7yMTf71TCZTZl/4e1bfzwUmFb3+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.36.0.tgz", + "integrity": "sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.36.0.tgz", + "integrity": "sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.36.0.tgz", + "integrity": "sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.36.0.tgz", + "integrity": "sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.36.0.tgz", + "integrity": "sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.36.0.tgz", + "integrity": "sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.36.0.tgz", + "integrity": "sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.36.0.tgz", + "integrity": "sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.36.0.tgz", + "integrity": "sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.36.0.tgz", + "integrity": "sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.36.0.tgz", + "integrity": "sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.36.0.tgz", + "integrity": "sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.36.0.tgz", + "integrity": "sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.36.0.tgz", + "integrity": "sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.36.0.tgz", + "integrity": "sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.36.0.tgz", + "integrity": "sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.13.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz", + "integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.27.0.tgz", + "integrity": "sha512-4henw4zkePi5p252c8ncBLzLce52SEUz2Ebj8faDnuUXz2UuHEONYcJ+G0oaCF+bYCWVZtrGzq3FD7YXetmnSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.27.0", + "@typescript-eslint/type-utils": "8.27.0", + "@typescript-eslint/utils": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.27.0.tgz", + "integrity": "sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.27.0", + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/typescript-estree": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.27.0.tgz", + "integrity": "sha512-8oI9GwPMQmBryaaxG1tOZdxXVeMDte6NyJA4i7/TWa4fBwgnAXYlIQP+uYOeqAaLJ2JRxlG9CAyL+C+YE9Xknw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.27.0.tgz", + "integrity": "sha512-wVArTVcz1oJOIEJxui/nRhV0TXzD/zMSOYi/ggCfNq78EIszddXcJb7r4RCp/oBrjt8n9A0BSxRMKxHftpDxDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.27.0", + "@typescript-eslint/utils": "8.27.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.27.0.tgz", + "integrity": "sha512-/6cp9yL72yUHAYq9g6DsAU+vVfvQmd1a8KyA81uvfDE21O2DwQ/qxlM4AR8TSdAu+kJLBDrEHKC5/W2/nxsY0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.27.0.tgz", + "integrity": "sha512-BnKq8cqPVoMw71O38a1tEb6iebEgGA80icSxW7g+kndx0o6ot6696HjG7NdgfuAVmVEtwXUr3L8R9ZuVjoQL6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.27.0.tgz", + "integrity": "sha512-njkodcwH1yvmo31YWgRHNb/x1Xhhq4/m81PhtvmRngD8iHPehxffz1SNCO+kwaePhATC+kOa/ggmvPoPza5i0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.27.0", + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/typescript-estree": "8.27.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.27.0.tgz", + "integrity": "sha512-WsXQwMkILJvffP6z4U3FYJPlbf/j07HIxmDjZpbNvBJkMfvwXj5ACRkkHwBDvLBbDbtX5TdU64/rcvKJ/vuInQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.27.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz", + "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz", + "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.0.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz", + "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz", + "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.0.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz", + "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.0.9", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz", + "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz", + "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.0.9", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/web-worker": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/web-worker/-/web-worker-3.0.9.tgz", + "integrity": "sha512-6ofXRWDelTlFIOaGLVtHPiIEzoTQK/DkH6DMrG7ZurrTF9szaiH86/u3qncA1cXsgp+vN19Kj+YYl4mbL+EDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "3.0.9" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssfontparser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssfontparser/-/cssfontparser-1.2.1.tgz", + "integrity": "sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.3.0.tgz", + "integrity": "sha512-6r0NiY0xizYqfBvWp1G7WXJ06/bZyrk7Dc6PHql82C/pKGUTKu4yAX4Y8JPamb1ob9nBKuxWzCGTRuGwU3yxJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.1.1", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.2.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.23.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", + "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", + "eslint": "^9.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz", + "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 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, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", + "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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==", + "dev": true, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nwsapi": { + "version": "2.2.19", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.19.tgz", + "integrity": "sha512-94bcyI3RsqiZufXjkr3ltkI86iEl+I7uiHVDtcq9wJUTwYQJ5odHDeSzkkrRzi80jJ8MaeZgqKjH1bAWAFw9bA==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-color": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz", + "integrity": "sha512-fuDHYgFHJGbpGMgw9skY/bj3HL/Jrn4l/5rSspy00DoT4RyLnDcRvPxdZ+r6OFwIsgAuhDh4I09tAId4mI12bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "~0.5.0" + } + }, + "node_modules/parse-color/node_modules/color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==", + "dev": true + }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.36.0.tgz", + "integrity": "sha512-zwATAXNQxUcd40zgtQG0ZafcRK4g004WtEl7kbuhTWPvf07PsfohXl39jVUvPF7jvNAIkKPQ2XrsDlWuxBd++Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.36.0", + "@rollup/rollup-android-arm64": "4.36.0", + "@rollup/rollup-darwin-arm64": "4.36.0", + "@rollup/rollup-darwin-x64": "4.36.0", + "@rollup/rollup-freebsd-arm64": "4.36.0", + "@rollup/rollup-freebsd-x64": "4.36.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.36.0", + "@rollup/rollup-linux-arm-musleabihf": "4.36.0", + "@rollup/rollup-linux-arm64-gnu": "4.36.0", + "@rollup/rollup-linux-arm64-musl": "4.36.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.36.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.36.0", + "@rollup/rollup-linux-riscv64-gnu": "4.36.0", + "@rollup/rollup-linux-s390x-gnu": "4.36.0", + "@rollup/rollup-linux-x64-gnu": "4.36.0", + "@rollup/rollup-linux-x64-musl": "4.36.0", + "@rollup/rollup-win32-arm64-msvc": "4.36.0", + "@rollup/rollup-win32-ia32-msvc": "4.36.0", + "@rollup/rollup-win32-x64-msvc": "4.36.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz", + "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.85", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.85.tgz", + "integrity": "sha512-gBdZ1RjCSevRPFix/hpaUWeak2/RNUZB4/8frF1r5uYMHjFptkiT0JXIebWvgI/0ZHXvxaUDDJshiA0j6GdL3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.85" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.85", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.85.tgz", + "integrity": "sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz", + "integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz", + "integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.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 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz", + "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.0", + "es-module-lexer": "^1.6.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz", + "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "3.0.9", + "@vitest/mocker": "3.0.9", + "@vitest/pretty-format": "^3.0.9", + "@vitest/runner": "3.0.9", + "@vitest/snapshot": "3.0.9", + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", + "chai": "^5.2.0", + "debug": "^4.4.0", + "expect-type": "^1.1.0", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinypool": "^1.0.2", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0", + "vite-node": "3.0.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.0.9", + "@vitest/ui": "3.0.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest-webgl-canvas-mock": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vitest-webgl-canvas-mock/-/vitest-webgl-canvas-mock-1.1.0.tgz", + "integrity": "sha512-F/5+XvBs7cSZPe41IGQTbSjNimB4NntPnRqv4eWb42voFKQINH8y2xZkibNUxYJCGIuDFsYp1lDQgTvWLahSzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssfontparser": "^1.2.1", + "parse-color": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index 3da6ec1..16f7a78 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,64 @@ { "name": "@next2d/framework", "description": "Next2D Framework is designed according to the principles of clean architecture, domain-driven development, test-driven development, and MVVM, with an emphasis on flexibility, scalability, and maintainability, and a design methodology that keeps each layer loosely coupled.", - "version": "2.0.2", + "version": "3.0.0", "homepage": "https://next2d.app", "bugs": "https://github.com/Next2D/Framework/issues/new", "author": "Toshiyuki Ienaga (https://github.com/ienaga/)", "license": "MIT", - "main": "dist/index.js", - "types": "dist/index.d.ts", + "main": "src/index.js", + "types": "src/index.d.ts", "type": "module", + "exports": { + ".": { + "import": "./src/index.js", + "require": "./src/index.js" + } + }, "keywords": [ "Next2D", "Next2D Framework" ], "scripts": { "lint": "eslint src/**/*.ts", - "publish": "node ./scripts/version.js && tsc", - "test": "npx vitest" + "publish": "node ./scripts/clean.js && node ./scripts/version.js && tsc && node ./scripts/publish.js", + "test": "vitest" }, - "files": [ - "dist" - ], "repository": { "type": "git", "url": "git+https://github.com/Next2D/Framework.git" }, "devDependencies": { - "@next2d/player": "*", - "@typescript-eslint/eslint-plugin": "^6.10.0", - "@typescript-eslint/parser": "^6.10.0", - "eslint": "^8.53.0", - "jsdom": "^22.1.0", - "typescript": "^5.2.2", - "vite": "^4.5.0", - "vitest": "^0.34.6" + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "^9.23.0", + "@types/node": "^22.13.11", + "@typescript-eslint/eslint-plugin": "^8.27.0", + "@typescript-eslint/parser": "^8.27.0", + "@vitest/web-worker": "^3.0.9", + "eslint": "^9.23.0", + "eslint-plugin-unused-imports": "^4.1.4", + "globals": "^16.0.0", + "jsdom": "^26.0.0", + "typescript": "^5.8.2", + "vite": "^6.2.2", + "vitest": "^3.0.9", + "vitest-webgl-canvas-mock": "^1.1.0" + }, + "peerDependencies": { + "@next2d/cache": "file:../player/packages/cache", + "@next2d/core": "file:../player/packages/core", + "@next2d/display": "file:../player/packages/display", + "@next2d/events": "file:../player/packages/events", + "@next2d/filters": "file:../player/packages/filters", + "@next2d/geom": "file:../player/packages/geom", + "@next2d/media": "file:../player/packages/media", + "@next2d/net": "file:../player/packages/net", + "@next2d/player": "file:../player", + "@next2d/render-queue": "file:../player/packages/render-queue", + "@next2d/renderer": "file:../player/packages/renderer", + "@next2d/text": "file:../player/packages/text", + "@next2d/texture-packer": "file:../player/packages/texture-packer", + "@next2d/ui": "file:../player/packages/ui", + "@next2d/webgl": "file:../player/packages/webgl" } } diff --git a/scripts/clean.js b/scripts/clean.js new file mode 100644 index 0000000..b47d6d7 --- /dev/null +++ b/scripts/clean.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +"use strict"; + +import { existsSync } from "fs"; +import { spawnSync } from "child_process"; + +const execute = () => +{ + const distPath = `${process.cwd()}/dist`; + if (existsSync(distPath)) { + spawnSync(`rm -rf ${distPath}`, { "shell": true }); + } +}; + +execute(); \ No newline at end of file diff --git a/scripts/publish.js b/scripts/publish.js new file mode 100644 index 0000000..63031fe --- /dev/null +++ b/scripts/publish.js @@ -0,0 +1,42 @@ +#!/usr/bin/env node + +"use strict"; + +import { readFileSync, writeFileSync } from "fs"; +import { spawnSync } from "child_process"; +import { join } from "path"; + +/** + * @return {void} + * @method + * @private + */ +const execute = () => +{ + const packageJson = JSON.parse( + readFileSync(`${process.cwd()}/package.json`, { "encoding": "utf8" }) + ); + + delete packageJson.peerDependencies; + packageJson.dependencies = { "@next2d/player": "*" }; + + // write package.json + writeFileSync( + join(process.cwd(), "dist/package.json"), + JSON.stringify(packageJson, null, 2) + ); + + // LICENSE + spawnSync( + `cp -r ${process.cwd()}/LICENSE ${process.cwd()}/dist/LICENSE`, + { "shell": true } + ); + + // README + spawnSync( + `cp -r ${process.cwd()}/README.md ${process.cwd()}/dist/README.md`, + { "shell": true } + ); +}; + +execute(); \ No newline at end of file diff --git a/scripts/version.js b/scripts/version.js index 828391e..260574d 100644 --- a/scripts/version.js +++ b/scripts/version.js @@ -5,7 +5,6 @@ import * as fs from "fs"; /** - * @param {string} dir * @return {void} * @method * @private diff --git a/src/application/Application.ts b/src/application/Application.ts index b9f3d66..7ea6226 100644 --- a/src/application/Application.ts +++ b/src/application/Application.ts @@ -1,41 +1,41 @@ -import type { ResponseDTO } from "../infrastructure/dto/ResponseDTO"; -import type { View } from "../view/View"; -import type { ConfigImpl } from "../interface/ConfigImpl"; -import type { QueryObjectImpl } from "../interface/QueryObjectImpl"; -import { execute as queryParser } from "../domain/parser/QueryParser"; -import { execute as requestUseCase } from "../infrastructure/usecase/RequestUseCase"; -import { execute as callback } from "../domain/callback/Callback"; -import { - execute as captureExecute, - dispose as captureDispose -} from "../domain/screen/Capture"; -import { execute as removeResponse } from "./service/RemoveResponse"; -import { $setPackages } from "./variable/Packages"; -import { response } from "./variable/Response"; -import { - config, - $setConfig -} from "./variable/Config"; -import { - context, - $createContext -} from "./variable/Context"; -import { - start as loadingStart, - end as loadingEnd -} from "../domain/loading/Loading"; +import type { IConfig } from "../interface/IConfig"; +import type { IPackages } from "../interface/IPackages"; +import type { Context } from "./Context"; +import { execute as applicationInitializeService } from "./Application/service/ApplicationInitializeService"; +import { execute as applicationGotoViewUseCase } from "./Application/usecase/ApplicationGotoViewUseCase"; +import { execute as contextRunService } from "./Context/service/ContextRunService"; +import { $getConfig } from "./variable/Config"; +import { $getContext } from "./variable/Context"; +import { response } from "../infrastructure/Response/variable/Response"; +import { cache } from "./variable/Cache"; /** - * シーン遷移のコントロールを行うクラス。 - * Class for controlling scene transitions. + * @description シーン遷移のコントロールを行うクラス。 + * Class for controlling scene transitions. * * @class - * @memberof application */ export class Application { - private _$popstate: boolean; - private _$currentName: string; + /** + * @description SPAの遷移かどうかを判定します + * Determines whether it is a transition of SPA + * + * @type {boolean} + * @default false + * @public + */ + public popstate: boolean; + + /** + * @description 現在の画面名 + * Current screen name + * + * @type {string} + * @default "" + * @public + */ + public currentName: string; /** * @constructor @@ -43,19 +43,8 @@ export class Application */ constructor () { - /** - * @type {boolean} - * @default false - * @private - */ - this._$popstate = false; - - /** - * @type {string} - * @default "top" - * @private - */ - this._$currentName = "top"; + this.popstate = false; + this.currentName = ""; } /** @@ -66,37 +55,22 @@ export class Application * @method * @public */ - initialize (config: ConfigImpl, packages: any[]): Application + initialize (config: IConfig, packages: IPackages): Application { - $setConfig(config); - $setPackages(packages); - - /** - * SPAが有効の場合は、遷移の履歴を残す - * Keep history of transitions if SPA setting is enabled - */ - if (config.spa) { - window.addEventListener("popstate", (): void => - { - this._$popstate = true; - this.gotoView(); - }); - } - - return this; + return applicationInitializeService(this, config, packages); } /** * @description Next2Dのアプリを起動します * Launch the Next2D application * - * @return {Promise} + * @return {Promise} * @method * @public */ - run (): Promise + async run (): Promise { - return $createContext(config); + await contextRunService($getConfig()); } /** @@ -111,105 +85,45 @@ export class Application */ async gotoView (name: string = ""): Promise { - if (config.loading) { - - const promises: Promise[] = []; - - /** - * 現時点の描画をBitmapにして処理の負担を減らす - * Reduce the processing burden by making the current drawing a Bitmap. - */ - promises.push(captureExecute()); - - /** - * ローディング表示を起動 - * Launch loading display - */ - promises.push(loadingStart()); - - await Promise.all(promises); - } - - /** - * 前の画面で取得したレスポンスデータを初期化 - * Initialize the response data obtained on the previous screen - */ - removeResponse(this._$currentName); - - /** - * 指定されたパス、もしくはURLからアクセス先を算出 - * Calculate the access point from the specified path or URL - */ - const queryObject: QueryObjectImpl = queryParser(name); - - /** - * 現在の画面名を更新 - * Update current screen name - */ - this._$currentName = queryObject.name; - - /** - * 遷移履歴をセット - * Set transition history - */ - if (config.spa && !this._$popstate) { - history.pushState("", "", - `${location.origin}/${this._$currentName}${queryObject.queryString}` - ); - } - - // update - this._$popstate = false; - - /** - * routing.jsonで設定したリクエスト処理を実行 - * Execute request processing set by routing.json - */ - const responses: ResponseDTO[] = await Promise.all(requestUseCase(this._$currentName)); - - /** - * レスポンス情報をマップに登録 - * Response information is registered on the map - */ - for (let idx: number = 0; idx < responses.length; ++idx) { - - const object: ResponseDTO = responses[idx]; - if (!object.name) { - continue; - } - - response.set(object.name, object.response); - } - - /** - * ViewとViewModelを起動 - * Start View and ViewModel - */ - const view: View = await context.boot(this._$currentName); - - /** - * コールバック設定があれば実行 - * Execute callback settings if any. - */ - if (view && config.gotoView) { - const promises: Promise[] = []; - promises.push(callback( - config.gotoView.callback, view - )); + await applicationGotoViewUseCase(this, name); + } - await Promise.all(promises); - } + /** + * @description コンテキストを取得します + * Get the context + * + * @return {Context} + * @method + * @public + */ + getContext (): Context + { + return $getContext(); + } - /** - * ローディング表示を終了 - * End loading display - */ - await loadingEnd(); + /** + * @description configで設定したリクエストのレスポンスマップを返却します + * Returns the response map of the request set in config + * + * @return {Map} + * @method + * @public + */ + getResponse (): Map + { + return response; + } - /** - * 前の画面のキャプチャーを終了 - * End previous screen capture - */ - captureDispose(); + /** + * @description キャッシュのMapオブジェクトを返却します + * Returns the Map object of the cache + * + * @return {Map} + * @method + * @public + */ + getCache (): Map + { + return cache; } -} +} \ No newline at end of file diff --git a/src/application/Application/service/ApplicationInitializeService.test.ts b/src/application/Application/service/ApplicationInitializeService.test.ts new file mode 100644 index 0000000..b7d3c8c --- /dev/null +++ b/src/application/Application/service/ApplicationInitializeService.test.ts @@ -0,0 +1,74 @@ +import type { IConfig } from "../../../interface/IConfig"; +import type { IPackages } from "../../../interface/IPackages"; +import { execute } from "./ApplicationInitializeService"; +import { Application } from "../../Application"; +import { View } from "../../../view/View"; +import { $getConfig } from "../../variable/Config"; +import { packages } from "../../variable/Packages"; +import { describe, expect, it, vi } from "vitest"; + +describe("ApplicationInitializeService", () => +{ + it("test case", () => + { + let state = ""; + window.addEventListener = vi.fn((name) => + { + state = name; + }); + + const app = new Application(); + const config: IConfig = { + "platform": "web", + "stage": { + "width": 640, + "height": 480, + "fps": 60 + }, + "spa": true + }; + + const buildPackages: IPackages = [[ + "view", View + ]]; + + expect(state).toBe(""); + expect(packages.size).toBe(0); + expect($getConfig()).toBe(undefined); + + execute(app, config, buildPackages); + + expect($getConfig()).toBe(config); + expect(packages.size).toBe(1); + expect(packages.get("view")).toBe(View); + expect(state).toBe("popstate"); + }); + + it("test case", () => + { + let state = ""; + window.addEventListener = vi.fn((name) => + { + state = name; + }); + + const app = new Application(); + const config: IConfig = { + "platform": "web", + "stage": { + "width": 640, + "height": 480, + "fps": 60 + }, + "spa": false + }; + + const buildPackages: IPackages = [[ + "view", View + ]]; + + expect(state).toBe(""); + execute(app, config, buildPackages); + expect(state).toBe(""); + }); +}); \ No newline at end of file diff --git a/src/application/Application/service/ApplicationInitializeService.ts b/src/application/Application/service/ApplicationInitializeService.ts new file mode 100644 index 0000000..7d34b81 --- /dev/null +++ b/src/application/Application/service/ApplicationInitializeService.ts @@ -0,0 +1,46 @@ +import type { IConfig } from "../../../interface/IConfig"; +import type { IPackages } from "../../../interface/IPackages"; +import type { Application } from "../../Application"; +import { $setConfig } from "../../variable/Config"; +import { $setPackages } from "../../variable/Packages"; + +/** + * @type {Promise} + * @private + */ +let $popstateQueue: Promise = Promise.resolve(); + +/** + * @description アプリケーションの初期化処理を実行します + * Execute the application initialization process + * + * @param {Application} application + * @param {IConfig} config + * @param {IPackages} packages + * @return {Application} + * @method + * @protected + */ +export const execute = ( + application: Application, + config: IConfig, + packages: IPackages +): Application => { + + $setConfig(config); + $setPackages(packages); + + /** + * SPAが有効の場合は、遷移の履歴を残す + * Keep history of transitions if SPA setting is enabled + */ + if (config.spa) { + window.addEventListener("popstate", async (): Promise => + { + application.popstate = true; + $popstateQueue = $popstateQueue.then(() => application.gotoView()); + }); + } + + return application; +}; \ No newline at end of file diff --git a/src/domain/parser/QueryParser.test.ts b/src/application/Application/service/ApplicationQueryStringParserService.test.ts similarity index 79% rename from src/domain/parser/QueryParser.test.ts rename to src/application/Application/service/ApplicationQueryStringParserService.test.ts index 855b5b0..57412b7 100644 --- a/src/domain/parser/QueryParser.test.ts +++ b/src/application/Application/service/ApplicationQueryStringParserService.test.ts @@ -1,8 +1,8 @@ -import { execute } from "./QueryParser"; -import { query } from "../../application/variable/Query"; -import { $setConfig } from "../../application/variable/Config"; -import { QueryObjectImpl } from "../../interface/QueryObjectImpl"; -import { vi } from "vitest"; +import type { IQueryObject } from "../../../interface/IQueryObject"; +import { execute } from "./ApplicationQueryStringParserService"; +import { query } from "../../variable/Query"; +import { $setConfig } from "../../variable/Config"; +import { describe, expect, it, vi } from "vitest"; Object.defineProperty(window, "location", { "get": vi.fn().mockReturnValue({ @@ -11,34 +11,34 @@ Object.defineProperty(window, "location", { }) }); -describe("QueryParserTest", () => +describe("ApplicationQueryStringParserService", () => { - test("parse query test case1", () => + it("parse query test case1", () => { query.clear(); query.set("test", 123); expect(query.size).toBe(1); - const object: QueryObjectImpl = execute(); + const object: IQueryObject = execute(); expect(query.size).toBe(0); expect(object.name).toBe("top"); expect(object.queryString).toBe(""); }); - test("parse query test case2", () => + it("parse query test case2", () => { query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute("@test"); + const object: IQueryObject = execute("@test"); expect(query.size).toBe(0); expect(object.name).toBe("test"); expect(object.queryString).toBe(""); }); - test("parse location.search test case1", () => + it("parse location.search test case1", () => { // @ts-ignore globalThis.location.search = "?q=abc&sample=1"; @@ -46,7 +46,7 @@ describe("QueryParserTest", () => query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute(""); + const object: IQueryObject = execute(""); expect(query.size).toBe(2); expect(query.get("q")).toBe("abc"); @@ -55,7 +55,7 @@ describe("QueryParserTest", () => expect(object.queryString).toBe("?q=abc&sample=1"); }); - test("parse location.pathname un match test", () => + it("parse location.pathname un match test", () => { // mock const config = { @@ -83,7 +83,7 @@ describe("QueryParserTest", () => query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute(""); + const object: IQueryObject = execute(""); expect(query.size).toBe(2); expect(query.get("q")).toBe("xyz"); @@ -92,7 +92,7 @@ describe("QueryParserTest", () => expect(object.queryString).toBe("?q=xyz&sample=0"); }); - test("parse location.pathname public test", () => + it("parse location.pathname public test", () => { // mock const config = { @@ -122,7 +122,7 @@ describe("QueryParserTest", () => query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute(""); + const object: IQueryObject = execute(""); expect(query.size).toBe(2); expect(query.get("q")).toBe("xyz"); @@ -131,7 +131,7 @@ describe("QueryParserTest", () => expect(object.queryString).toBe("?q=xyz&sample=0"); }); - test("parse location.pathname private test", () => + it("parse location.pathname private test", () => { // mock const config = { @@ -161,7 +161,7 @@ describe("QueryParserTest", () => query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute(""); + const object: IQueryObject = execute(""); expect(query.size).toBe(2); expect(query.get("q")).toBe("xyz"); @@ -170,7 +170,7 @@ describe("QueryParserTest", () => expect(object.queryString).toBe("?q=xyz&sample=0"); }); - test("parse location.pathname redirect test", () => + it("parse location.pathname redirect test", () => { // mock const config = { @@ -201,7 +201,7 @@ describe("QueryParserTest", () => query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute(""); + const object: IQueryObject = execute(""); expect(query.size).toBe(2); expect(query.get("q")).toBe("xyz"); @@ -210,13 +210,13 @@ describe("QueryParserTest", () => expect(object.queryString).toBe("?q=xyz&sample=0"); }); - test("parse name query test", () => + it("parse name query test", () => { // mock query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute("page/test?abc=123&xyz=999"); + const object: IQueryObject = execute("page/test?abc=123&xyz=999"); expect(query.size).toBe(2); expect(query.get("abc")).toBe("123"); @@ -225,25 +225,25 @@ describe("QueryParserTest", () => expect(object.queryString).toBe("?abc=123&xyz=999"); }); - test("parse name path test case1", () => + it("parse name path test case1", () => { // mock query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute("./test"); + const object: IQueryObject = execute("./test"); expect(query.size).toBe(0); expect(object.name).toBe("test"); }); - test("parse name path test case2", () => + it("parse name path test case2", () => { // mock query.clear(); expect(query.size).toBe(0); - const object: QueryObjectImpl = execute("./"); + const object: IQueryObject = execute("./"); expect(query.size).toBe(0); expect(object.name).toBe("top"); diff --git a/src/domain/parser/QueryParser.ts b/src/application/Application/service/ApplicationQueryStringParserService.ts similarity index 63% rename from src/domain/parser/QueryParser.ts rename to src/application/Application/service/ApplicationQueryStringParserService.ts index 46a1021..75923ba 100644 --- a/src/domain/parser/QueryParser.ts +++ b/src/application/Application/service/ApplicationQueryStringParserService.ts @@ -1,18 +1,17 @@ -import type { QueryObjectImpl } from "src/interface/QueryObjectImpl"; -import type { RoutingImpl } from "src/interface/RoutingImpl"; -import { config } from "../../application/variable/Config"; -import { query } from "../../application/variable/Query"; +import type { IQueryObject } from "src/interface/IQueryObject"; +import { $getConfig } from "../../variable/Config"; +import { query } from "../../variable/Query"; /** * @description 指定されたQueryStringか、URLのQueryStringをquery mapに登録 * Register the specified QueryString or URL QueryString in the query map * * @param {string} [name=""] - * @return {object} + * @return {IQueryObject} * @method - * @public + * @protected */ -export const execute = (name: string = ""): QueryObjectImpl => +export const execute = (name: string = ""): IQueryObject => { /** * 前のシーンのクエリデータを初期化 @@ -26,23 +25,24 @@ export const execute = (name: string = ""): QueryObjectImpl => * QueryStringがあれば分解 * Disassemble QueryString if available */ - let queryString: string = ""; + let queryString = ""; if (!name && location.search) { queryString = location.search; const parameters = queryString.slice(1).split("&"); - for (let idx: number = 0; idx < parameters.length; ++idx) { - const pair: string[] = parameters[idx].split("="); + for (let idx = 0; idx < parameters.length; ++idx) { + const pair = parameters[idx].split("="); query.set(pair[0], pair[1]); } } - const defaultTop: string = config?.defaultTop || "top"; + const config = $getConfig(); + const defaultTop = config?.defaultTop || "top"; if (!name) { - const names: string[] = location.pathname.split("/"); + const names = location.pathname.split("/"); names.shift(); name = `${names.join("/")}`; if (name && config && config.routing) { - const routing: RoutingImpl = config.routing[name]; + const routing = config.routing[name]; if (!routing) { name = defaultTop; } @@ -63,14 +63,14 @@ export const execute = (name: string = ""): QueryObjectImpl => */ if (name.indexOf("?") > -1) { - const names: string[] = name.split("?"); + const names = name.split("?"); name = names[0]; queryString = `?${names[1]}`; - const parameters: string[] = names[1].split("&"); - for (let idx: number = 0; idx < parameters.length; ++idx) { - const pair: string[] = parameters[idx].split("="); + const parameters = names[1].split("&"); + for (let idx = 0; idx < parameters.length; ++idx) { + const pair = parameters[idx].split("="); query.set(pair[0], pair[1]); } } diff --git a/src/application/Application/usecase/ApplicationGotoViewUseCase.ts b/src/application/Application/usecase/ApplicationGotoViewUseCase.ts new file mode 100644 index 0000000..79bc606 --- /dev/null +++ b/src/application/Application/usecase/ApplicationGotoViewUseCase.ts @@ -0,0 +1,124 @@ +import type { Application } from "../../Application"; +import { $getConfig } from "../../variable/Config"; +import { $getContext } from "../../variable/Context"; +import { response } from "../../../infrastructure/Response/variable/Response"; +import { execute as addScreenCaptureService } from "../../../domain/screen/Capture/service/AddScreenCaptureService"; +import { execute as disposeCaptureService } from "../../../domain/screen/Capture/service/DisposeCaptureService"; +import { execute as loadingStartService } from "../../../domain/loading/Loading/service/LoadingStartService"; +import { execute as loadingEndService } from "../../../domain/loading/Loading/service/LoadingEndService"; +import { execute as responseRemoveVariableUseCase } from "../../../infrastructure/Response/usecase/ResponseRemoveVariableUseCase"; +import { execute as applicationQueryStringParserService } from "../service/ApplicationQueryStringParserService"; +import { execute as requestUseCase } from "../../../infrastructure/Request/usecase/RequestUseCase"; +import { execute as callbackService } from "../../../domain/callback/service/CallbackService"; + +/** + * @description 指定されたパス、もしくはURLのクラスを起動 + * Start the class of the specified path or URL + * + * @param {Application} application + * @param {string} [name=""] + * @return {Promise} + * @method + * @protected + */ +export const execute = async (application: Application, name: string = ""): Promise => +{ + const config = $getConfig(); + if (config.loading) { + /** + * 現時点の描画をキャプチャーして表示 + * Capture and display the current drawing + */ + await addScreenCaptureService(); + + /** + * ローディング表示を起動 + * Launch loading display + */ + await loadingStartService(); + } + + /** + * 現在の画面のViewとViewModelをunbind + * Unbind the View and ViewModel of the current screen + */ + const context = $getContext(); + await context.unbind(); + + /** + * 前の画面で取得したレスポンスデータを初期化 + * Initialize the response data obtained on the previous screen + */ + responseRemoveVariableUseCase(application.currentName); + + /** + * 指定されたパス、もしくはURLからアクセス先を算出 + * Calculate the access point from the specified path or URL + */ + const queryObject = applicationQueryStringParserService(name); + + /** + * 現在の画面名を更新 + * Update current screen name + */ + application.currentName = queryObject.name; + + /** + * 遷移履歴をセット + * Set transition history + */ + if (config.spa && !application.popstate) { + history.pushState("", "", + `${location.origin}/${application.currentName}${queryObject.queryString}` + ); + } + + // update + application.popstate = false; + + /** + * routing.jsonで設定したリクエスト処理を実行 + * Execute request processing set by routing.json + */ + const responses = await requestUseCase(application.currentName); + + /** + * レスポンス情報をマップに登録 + * Response information is registered on the map + */ + for (let idx = 0; idx < responses.length; ++idx) { + + const object = responses[idx]; + if (!object.name) { + continue; + } + + response.set(object.name, object.response); + } + + /** + * ローディング表示を終了 + * End loading display + */ + await loadingEndService(); + + /** + * 前の画面のキャプチャーを終了 + * End previous screen capture + */ + disposeCaptureService(); + + /** + * ViewとViewModelを起動 + * Start View and ViewModel + */ + const view = await context.bind(application.currentName); + + /** + * コールバック設定があれば実行 + * Execute callback settings if any. + */ + if (view && config.gotoView) { + await callbackService(config.gotoView.callback, view); + } +}; \ No newline at end of file diff --git a/src/domain/parser/RequestParser.test.ts b/src/application/Config/service/ConfigParserRequestsPropertyService.test.ts similarity index 78% rename from src/domain/parser/RequestParser.test.ts rename to src/application/Config/service/ConfigParserRequestsPropertyService.test.ts index 8b477db..55d172f 100644 --- a/src/domain/parser/RequestParser.test.ts +++ b/src/application/Config/service/ConfigParserRequestsPropertyService.test.ts @@ -1,12 +1,14 @@ -import { execute } from "./RequestParser"; -import { $setConfig } from "../../../src/application/variable/Config"; +import { execute } from "./ConfigParserRequestsPropertyService"; +import { $setConfig } from "../../variable/Config"; +import type { IConfig } from "../../../interface/IConfig"; +import { describe, expect, it } from "vitest"; -describe("RequestParserTest", () => +describe("ConfigParserRequestsPropertyService Test", () => { - test("request parse no match test case1", () => + it("request parse no match test case1", () => { // mock - const config = { + const config: IConfig = { "platform": "web", "spa": true, "stage": { @@ -24,10 +26,10 @@ describe("RequestParserTest", () => expect(requests.length).toBe(0); }); - test("request parse no match test case2", () => + it("request parse no match test case2", () => { // mock - const config = { + const config: IConfig = { "platform": "web", "spa": true, "stage": { @@ -47,10 +49,10 @@ describe("RequestParserTest", () => expect(requests.length).toBe(0); }); - test("request parse match test case1", () => + it("request parse match test case1", () => { // mock - const config = { + const config: IConfig = { "platform": "web", "spa": true, "stage": { @@ -74,19 +76,19 @@ describe("RequestParserTest", () => $setConfig(config); - const requests: Object[] = execute("top"); + const requests = execute("top"); expect(requests.length).toBe(1); - const object: Object = requests[0]; + const object = requests[0]; expect(object.type).toBe("json"); expect(object.name).toBe("TopTest"); expect(object.path).toBe("local"); }); - test("request parse cluster test case1", () => + it("request parse cluster test case1", () => { // mock - const config = { + const config: IConfig = { "platform": "web", "spa": true, "stage": { @@ -124,14 +126,14 @@ describe("RequestParserTest", () => $setConfig(config); - const requests: Object[] = execute("top"); + const requests = execute("top"); expect(requests.length).toBe(2); - const object1: Object = requests[0]; + const object1 = requests[0]; expect(object1.type).toBe("content"); expect(object1.name).toBe("MainContent"); - const object2: Object = requests[1]; + const object2 = requests[1]; expect(object2.type).toBe("json"); expect(object2.name).toBe("TopText"); }); diff --git a/src/domain/parser/RequestParser.ts b/src/application/Config/service/ConfigParserRequestsPropertyService.ts similarity index 67% rename from src/domain/parser/RequestParser.ts rename to src/application/Config/service/ConfigParserRequestsPropertyService.ts index f48a64c..aa42ffc 100644 --- a/src/domain/parser/RequestParser.ts +++ b/src/application/Config/service/ConfigParserRequestsPropertyService.ts @@ -1,6 +1,6 @@ -import { RequestImpl } from "src/interface/RequestImpl"; -import { config } from "../../application/variable/Config"; -import type { RoutingImpl } from "src/interface/RoutingImpl"; +import type { IRequest } from "../../../interface/IRequest"; +import type { IRouting } from "../../../interface/IRouting"; +import { $getConfig } from "../../../application/variable/Config"; /** * @description routing.jsonに設定されたrequestsを返却します。 @@ -13,22 +13,23 @@ import type { RoutingImpl } from "src/interface/RoutingImpl"; * @method * @public */ -export const execute = (name: string): RequestImpl[] => +export const execute = (name: string): IRequest[] => { - const requests: RequestImpl[] = []; + const requests: IRequest[] = []; + const config = $getConfig(); if (!config || !config.routing) { return requests; } - const routing: RoutingImpl = config.routing[name]; + const routing: IRouting = config.routing[name]; if (!routing || !routing.requests) { return requests; } for (let idx: number = 0; idx < routing.requests.length; idx++) { - const request: RequestImpl = routing.requests[idx]; + const request: IRequest = routing.requests[idx]; if (request.type !== "cluster") { requests.push(request); @@ -43,7 +44,7 @@ export const execute = (name: string): RequestImpl[] => * クラスターの場合は分解して配列に追加 * For clusters, disassemble and add to array */ - const results: RequestImpl[] = execute(request.path); + const results: IRequest[] = execute(request.path); requests.push(...results); } diff --git a/src/application/Context.ts b/src/application/Context.ts index 1178e41..761b481 100644 --- a/src/application/Context.ts +++ b/src/application/Context.ts @@ -1,21 +1,41 @@ -import { execute as toCamelCase } from "../domain/convert/ToCamelCase"; -import { packages } from "./variable/Packages"; import type { View } from "../view/View"; import type { ViewModel } from "../view/ViewModel"; import type { Sprite } from "@next2d/display"; +import { execute as contextUnbindService } from "./Context/service/ContextUnbindService"; +import { execute as contextBindUseCase } from "./Context/usecase/ContextBindUseCase"; /** * @description メインコンテキスト、ViewとViewModelのunbind、bindをコントロールします。 * Controls unbind and bind of the main context, View and ViewModel. * * @class - * @memberof context */ export class Context { - private _$view: View | null; - private _$viewModel: ViewModel | null; - private _$viewName: string; + /** + * @description 現在のシーンで利用中のViewクラスを返却します。 + * Returns the View class that is being used in the current scene. + * + * @return {View} + * @default null + * @public + */ + public view: View | null; + + /** + * @description 現在のシーンで利用中のViewModelクラスを返却します。 + * Returns the ViewModel class that is being used in the current scene. + * + * @return {ViewModel} + * @default null + * @public + */ + public viewModel: ViewModel | null; + + /** + * @type {Sprite} + * @private + */ private readonly _$root: Sprite; /** @@ -26,32 +46,11 @@ export class Context */ constructor (root: Sprite) { - /** - * @type {View} - * @default null - * @private - */ - this._$view = null; - - /** - * @type {ViewModel} - * @default null - * @private - */ - this._$viewModel = null; - - /** - * @type {string} - * @default "Top" - * @private - */ - this._$viewName = "Top"; - - /** - * @type {Sprite} - * @private - */ this._$root = root; + + // 初期化 + this.view = null; + this.viewModel = null; } /** @@ -68,107 +67,29 @@ export class Context } /** - * @description 現在のシーンで利用中のViewクラスを返却します。 - * Returns the View class that is being used in the current scene. - * - * @return {View} - * @default null - * @readonly - * @public - */ - get view (): View | null - { - return this._$view; - } - - /** - * @description 現在のシーンで利用中のViewModelクラスを返却します。 - * Returns the ViewModel class that is being used in the current scene. - * - * @return {ViewModel} - * @default null - * @readonly - * @public - */ - get viewModel (): ViewModel | null - { - return this._$viewModel; - } - - /** - * @description 現在のシーンで利用中のViewクラス名を返却します。 - * Returns the name of the View class currently being used in the current scene. + * @description ViewクラスをrootのSpriteにアタッチします。 + * Attach the View class to the root Sprite. * - * @return {string} - * @default "Top" - * @readonly + * @param {string} name + * @return {Promise} + * @method * @public */ - get viewName (): string + async bind (name: string): Promise { - return this._$viewName; + return await contextBindUseCase(this, name); } /** - * @description ViewクラスをrootのSpriteにアタッチします。 - * Attach the View class to the root Sprite. + * @description ViewとViewModelのバインドを解除します。 + * Unbinds View and ViewModel. * - * @param {string} name - * @return {Promise} + * @return {Promise} * @method * @public */ - async boot (name: string): Promise + async unbind (): Promise { - this._$viewName = toCamelCase(name); - - const viewName: string = `${this._$viewName}View`; - const viewModelName: string = `${viewName}Model`; - - if (!packages.size - || !packages.has(viewName) - || !packages.has(viewModelName) - ) { - throw new Error("not found view or viewMode."); - } - - /** - * 現在のページをstageから削除して、unbind関数を実行 - * Delete current page from stage and execute unbind function - */ - if (this._$view) { - if (this._$viewModel) { - this._$viewModel.unbind(this._$view); - } - - // remove - if (this._$view.parent === this._$root) { - this._$root.removeChild(this._$view); - } - } - - /** - * 遷移先のViewとViewModelを準備 - * Prepare the destination View and ViewModel - */ - const ViewModelClass: typeof ViewModel = packages.get(viewModelName); - this._$viewModel = new ViewModelClass(); - - const ViewClass: typeof View = packages.get(viewName); - this._$view = new ViewClass(); - - /** - * ViewModelにViewをbindしてページを生成 - * Bind a View to a ViewModel to generate a page - */ - await Promise.all([this._$viewModel.bind(this._$view)]); - - /** - * stageの一番背面にviewをセット - * Set the view at the very back of the stage - */ - this._$root.addChildAt(this._$view, 0); - - return this._$view; + await contextUnbindService(this); } } \ No newline at end of file diff --git a/src/application/Context/service/ContextRunService.test.ts b/src/application/Context/service/ContextRunService.test.ts new file mode 100644 index 0000000..3b3169d --- /dev/null +++ b/src/application/Context/service/ContextRunService.test.ts @@ -0,0 +1,35 @@ +import { execute } from "./ContextRunService"; +import { $getContext } from "../../../application/variable/Context"; +import { describe, expect, it, vi } from "vitest"; +import { MovieClip } from "@next2d/display"; + +const root = new MovieClip(); + +Object.defineProperty(window, "next2d", { + "get": vi.fn().mockReturnValue({ + "createRootMovieClip": async () => { + return root; + } + }) +}); + +describe("ContextRunService Test", () => +{ + it("execute test case", async () => + { + const config = { + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + } + }; + + await execute(config); + const context = $getContext(); + expect(context).not.toBeNull(); + expect(context.root.instanceId).toBe(root.instanceId) + }); +}); \ No newline at end of file diff --git a/src/application/Context/service/ContextRunService.ts b/src/application/Context/service/ContextRunService.ts new file mode 100644 index 0000000..9bccfa1 --- /dev/null +++ b/src/application/Context/service/ContextRunService.ts @@ -0,0 +1,24 @@ +import type { IConfig } from "../../../interface/IConfig"; +import { Context } from "../../Context"; +import { $setContext } from "../../variable/Context"; + +/** + * @description コンテキストを起動します。 + * Start the context. + * + * @param {IConfig} config + * @return {Promise} + * @method + * @protected + */ +export const execute = async (config: IConfig): Promise => +{ + const root = await next2d.createRootMovieClip( + config.stage.width, + config.stage.height, + config.stage.fps, + config.stage.options + ); + + $setContext(new Context(root)); +}; \ No newline at end of file diff --git a/src/application/Context/service/ContextToCamelCaseService.test.ts b/src/application/Context/service/ContextToCamelCaseService.test.ts new file mode 100644 index 0000000..dd030d5 --- /dev/null +++ b/src/application/Context/service/ContextToCamelCaseService.test.ts @@ -0,0 +1,20 @@ +import { execute } from "./ContextToCamelCaseService"; +import { describe, expect, it } from "vitest"; + +describe("ContextToCamelCaseService Test", () => +{ + it("execute test case1", () => + { + expect(execute("home")).toBe("Home"); + }); + + it("execute test case2", () => + { + expect(execute("quest/list")).toBe("QuestList"); + }); + + it("execute test case3", () => + { + expect(execute("game/list/page")).toBe("GameListPage"); + }); +}); \ No newline at end of file diff --git a/src/domain/convert/ToCamelCase.ts b/src/application/Context/service/ContextToCamelCaseService.ts similarity index 100% rename from src/domain/convert/ToCamelCase.ts rename to src/application/Context/service/ContextToCamelCaseService.ts diff --git a/src/application/Context/service/ContextUnbindService.test.ts b/src/application/Context/service/ContextUnbindService.test.ts new file mode 100644 index 0000000..9d4cda7 --- /dev/null +++ b/src/application/Context/service/ContextUnbindService.test.ts @@ -0,0 +1,47 @@ +import type { ViewModel } from "../../../view/ViewModel"; +import { execute } from "./ContextUnbindService"; +import { MovieClip } from "@next2d/display"; +import { Context } from "../../../application/Context"; +import { $setContext } from "../../../application/variable/Context"; +import { $setConfig } from "../../../application/variable/Config"; +import { View } from "../../../view/View"; +import { describe, expect, it } from "vitest"; + +describe("ContextUnbindService Test", () => +{ + it("execute test case", async () => + { + // mock + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + } + }); + + const root = new MovieClip(); + const context = new Context(root); + $setContext(context); + + let state = "none"; + context.view = new View(); + root.addChild(context.view); + context.viewModel = { + "unbind": (view: View) => + { + state = "unbind"; + } + } as ViewModel; + + expect(state).toBe("none"); + expect(root.numChildren).toBe(1); + + await execute(context); + + expect(state).toBe("unbind"); + expect(root.numChildren).toBe(0); + }); +}); \ No newline at end of file diff --git a/src/application/Context/service/ContextUnbindService.ts b/src/application/Context/service/ContextUnbindService.ts new file mode 100644 index 0000000..9b21385 --- /dev/null +++ b/src/application/Context/service/ContextUnbindService.ts @@ -0,0 +1,26 @@ +import type { Context } from "../../Context"; + +/** + * @description ViewとViewModelのバインドを解除します。 + * Unbinds View and ViewModel. + * + * @param {Context} context + * @return {Promise} + * @method + * @protected + */ +export const execute = async (context: Context): Promise => +{ + if (!context.view || !context.viewModel) { + return ; + } + + await context.viewModel.unbind(context.view); + + const root = context.root; + if (!root) { + return ; + } + + root.removeChild(context.view); +}; \ No newline at end of file diff --git a/src/application/Context/usecase/ContextBindUseCase.test.ts b/src/application/Context/usecase/ContextBindUseCase.test.ts new file mode 100644 index 0000000..162daf3 --- /dev/null +++ b/src/application/Context/usecase/ContextBindUseCase.test.ts @@ -0,0 +1,51 @@ +import { execute } from "./ContextBindUseCase"; +import { MovieClip } from "@next2d/display"; +import { Context } from "../../../application/Context"; +import { $setContext } from "../../../application/variable/Context"; +import { $setConfig } from "../../../application/variable/Config"; +import { packages } from "../../../application/variable/Packages"; +import { View } from "../../../view/View"; +import { ViewModel } from "../../../view/ViewModel"; +import { describe, expect, it } from "vitest"; + +describe("ContextBindUseCase Test", () => +{ + it("execute test case1", async () => + { + // mock + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + } + }); + + let state = "none"; + class TestViewModel extends ViewModel + { + async bind () + { + state = "bind"; + } + } + + packages.clear(); + packages.set("TestView", View); + packages.set("TestViewModel", TestViewModel); + + const root = new MovieClip(); + const context = new Context(root); + $setContext(context); + + expect(state).toBe("none"); + expect(root.numChildren).toBe(0); + + await execute(context, "test"); + + expect(state).toBe("bind"); + expect(root.numChildren).toBe(1); + }); +}); \ No newline at end of file diff --git a/src/application/Context/usecase/ContextBindUseCase.ts b/src/application/Context/usecase/ContextBindUseCase.ts new file mode 100644 index 0000000..942366b --- /dev/null +++ b/src/application/Context/usecase/ContextBindUseCase.ts @@ -0,0 +1,61 @@ +import type { Context } from "../../Context"; +import type { View } from "../../../view/View"; +import type { ViewModel } from "../../../view/ViewModel"; +import { packages } from "../../variable/Packages"; +import { execute as contextToCamelCaseService } from "../service/ContextToCamelCaseService"; + +/** + * @description ViewとViewModelのbindを行います。 + * Binds View and ViewModel. + * + * @param {Context} context + * @param {string} name + * @return {Promise} + * @method + * @protected + */ +export const execute = async (context: Context, name: string): Promise => +{ + const viewName = `${contextToCamelCaseService(name)}View`; + const viewModelName = `${viewName}Model`; + + if (!packages.size + || !packages.has(viewName) + || !packages.has(viewModelName) + ) { + throw new Error("not found view or viewMode."); + } + + /** + * 遷移先のViewとViewModelを準備 + * Prepare the destination View and ViewModel + */ + const ViewModelClass: any = packages.get(viewModelName) as unknown as ViewModel; + context.viewModel = (new ViewModelClass() as ViewModel); + + const ViewClass: any = packages.get(viewName) as unknown as View; + context.view = (new ViewClass() as View); + + /** + * ViewModelにViewをbindしてページを生成 + * Bind a View to a ViewModel to generate a page + */ + await context.viewModel.bind(context.view); + + /** + * rootの子要素を全て削除 + * Remove all child elements of root + */ + const root = context.root; + while (root.numChildren) { + root.removeChildAt(0); + } + + /** + * stageの一番背面にviewをセット + * Set the view at the very back of the stage + */ + root.addChildAt(context.view, 0); + + return context.view; +}; \ No newline at end of file diff --git a/src/application/content/Builder/service/ContentBuilderService.test.ts b/src/application/content/Builder/service/ContentBuilderService.test.ts new file mode 100644 index 0000000..233b607 --- /dev/null +++ b/src/application/content/Builder/service/ContentBuilderService.test.ts @@ -0,0 +1,52 @@ +import { execute } from "./ContentBuilderService"; +import { ShapeContent } from "../../ShapeContent"; +import { loaderInfoMap } from "../../../variable/LoaderInfoMap"; +import { Shape, type LoaderInfo } from "@next2d/display"; +import { describe, expect, it, vi } from "vitest"; + +describe("ContentBuilderService Test", () => +{ + it("test case", () => + { + const displayObject = new ShapeContent(); + + let state = "none"; + displayObject.$sync = vi.fn(() => + { + state = "sync"; + }); + + const map: Map = new Map(); + map.set(Shape.namespace, 1); + loaderInfoMap.clear(); + loaderInfoMap.set(Shape.namespace, { + "data": { + "stage": { + "width": 100, + "height": 100, + "fps": 60, + "bgColor": "#000000" + }, + "characters": [ + { + "extends": Shape.namespace, + "bounds": { "xMin": 0, "yMin": 0, "xMax": 100, "yMax": 100 }, + "bitmapId": 0 + }, + { + "extends": Shape.namespace, + "bounds": { "xMin": 0, "yMin": 0, "xMax": 100, "yMax": 100 }, + "bitmapId": 0 + } + ], + "symbols": map + } + } as LoaderInfo); + + expect(state).toBe("none"); + expect(displayObject.characterId).toBe(-1); + execute(displayObject); + expect(state).toBe("sync"); + expect(displayObject.characterId).toBe(1); + }); +}); \ No newline at end of file diff --git a/src/application/content/Builder/service/ContentBuilderService.ts b/src/application/content/Builder/service/ContentBuilderService.ts new file mode 100644 index 0000000..4b57fd7 --- /dev/null +++ b/src/application/content/Builder/service/ContentBuilderService.ts @@ -0,0 +1,34 @@ +import type { IContent } from "../../../../interface/IContent"; +import { loaderInfoMap } from "../../../variable/LoaderInfoMap"; + +/** + * @description Animation Toolで作成したアニメーションを動的に生成 + * Dynamically generate animations created with Animation Tool + * + * @param {IContent} display_object + * @return {void} + * @method + * @protected + */ +export const execute = (display_object: IContent): void => +{ + // Set the target LoaderInfo class + const name = display_object.namespace; + const loaderInfo = loaderInfoMap.get(name); + if (!loaderInfo || !loaderInfo.data) { + return ; + } + + const characterId: number | void = loaderInfo.data.symbols.get(name); + if (!characterId) { + return ; + } + + const character = loaderInfo.data.characters[characterId]; + if (!character) { + return ; + } + + display_object.characterId = characterId; + display_object.$sync(character, loaderInfo); +}; \ No newline at end of file diff --git a/src/application/content/ContentBuilder.ts b/src/application/content/ContentBuilder.ts deleted file mode 100644 index 660e2d4..0000000 --- a/src/application/content/ContentBuilder.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { loaderInfoMap } from "../variable/LoaderInfoMap"; -import type { LoaderInfo } from "@next2d/display"; -import type { - Character, - DisplayObjectImpl -} from "@next2d/interface"; - -/** - * @description NoCode Toolで作成したアニメーションの動的生成の補完を行うクラス。 - * A class that completes the dynamic generation of animations created by NoCode Tool. - * - * @class - * @memberof application.content - */ -export const execute = (instance: DisplayObjectImpl): void => -{ - const name = instance.namespace; - if (!loaderInfoMap.has(name)) { - return ; - } - - // Set the target LoaderInfo class - const loaderInfo: LoaderInfo | void = loaderInfoMap.get(name); - if (!loaderInfo || !loaderInfo._$data) { - return ; - } - - const characterId: number | void = loaderInfo._$data.symbols.get(name); - if (!characterId) { - return ; - } - - const character: Character = loaderInfo._$data.characters[characterId]; - if (!character) { - return ; - } - - instance._$loaderInfo = loaderInfo; - instance._$characterId = characterId; - instance._$sync(character); -}; \ No newline at end of file diff --git a/src/application/content/MovieClipContent.ts b/src/application/content/MovieClipContent.ts index 540e328..70bee1c 100644 --- a/src/application/content/MovieClipContent.ts +++ b/src/application/content/MovieClipContent.ts @@ -1,12 +1,11 @@ import { MovieClip } from "@next2d/display"; -import { execute as contentBuilder } from "./ContentBuilder"; +import { execute as contentBuilderService } from "./Builder/service/ContentBuilderService"; /** - * @description NoCode Toolで作成したMovieClipの動的生成の補完を行うクラス。 - * A class that complements the dynamic generation of MovieClip created by the NoCode Tool. + * @description Animation Toolで作成したMovieClipの動的生成の補完を行うクラス。 + * A class that complements the dynamic generation of MovieClip created by the Animation Tool. * * @class - * @memberof application.content * @extends {MovieClip} */ export class MovieClipContent extends MovieClip @@ -19,7 +18,7 @@ export class MovieClipContent extends MovieClip { super(); - contentBuilder(this); + contentBuilderService(this); // initial processing this.initialize(); diff --git a/src/application/content/ShapeContent.ts b/src/application/content/ShapeContent.ts index aca96a9..a8753e2 100644 --- a/src/application/content/ShapeContent.ts +++ b/src/application/content/ShapeContent.ts @@ -1,12 +1,11 @@ import { Shape } from "@next2d/display"; -import { execute as contentBuilder } from "./ContentBuilder"; +import { execute as contentBuilderService } from "./Builder/service/ContentBuilderService"; /** - * @description NoCode Toolで作成したShapeの動的生成の補完を行うクラス。 - * A class that complements the dynamic generation of Shape created by the NoCode Tool. + * @description Animation Toolで作成したShapeの動的生成の補完を行うクラス。 + * A class that complements the dynamic generation of Shape created by the Animation Tool. * * @class - * @memberof application.content * @extends {Shape} */ export class ShapeContent extends Shape @@ -19,7 +18,7 @@ export class ShapeContent extends Shape { super(); - contentBuilder(this); + contentBuilderService(this); // initial processing this.initialize(); diff --git a/src/application/content/TextFieldContent.ts b/src/application/content/TextFieldContent.ts index b20e702..c9af0ff 100644 --- a/src/application/content/TextFieldContent.ts +++ b/src/application/content/TextFieldContent.ts @@ -1,12 +1,11 @@ -import { TextField } from "@next2d/display"; -import { execute as contentBuilder } from "./ContentBuilder"; +import { TextField } from "@next2d/text"; +import { execute as contentBuilderService } from "./Builder/service/ContentBuilderService"; /** - * @description NoCode Toolで作成したTextFieldの動的生成の補完を行うクラス。 - * A class that complements the dynamic generation of TextField created by the NoCode Tool. + * @description Animation Toolで作成したTextFieldの動的生成の補完を行うクラス。 + * A class that complements the dynamic generation of TextField created by the Animation Tool. * * @class - * @memberof application.content * @extends {TextField} */ export class TextFieldContent extends TextField @@ -19,7 +18,7 @@ export class TextFieldContent extends TextField { super(); - contentBuilder(this); + contentBuilderService(this); // initial processing this.initialize(); diff --git a/src/application/content/VideoContent.ts b/src/application/content/VideoContent.ts index 52b6d79..3c4ebc1 100644 --- a/src/application/content/VideoContent.ts +++ b/src/application/content/VideoContent.ts @@ -1,12 +1,11 @@ import { Video } from "@next2d/media"; -import { execute as contentBuilder } from "./ContentBuilder"; +import { execute as contentBuilderService } from "./Builder/service/ContentBuilderService"; /** - * @description NoCode Toolで作成したVideoの動的生成の補完を行うクラス。 - * A class that complements the dynamic generation of Video created by the NoCode Tool. + * @description Animation Toolで作成したVideoの動的生成の補完を行うクラス。 + * A class that complements the dynamic generation of Video created by the Animation Tool. * * @class - * @memberof application.content * @extends {Video} */ export class VideoContent extends Video @@ -19,7 +18,7 @@ export class VideoContent extends Video { super(); - contentBuilder(this); + contentBuilderService(this); // initial processing this.initialize(); diff --git a/src/application/service/RemoveResponse.ts b/src/application/service/RemoveResponse.ts deleted file mode 100644 index 132a6b6..0000000 --- a/src/application/service/RemoveResponse.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { execute as requestParser } from "../../domain/parser/RequestParser"; -import { loaderInfoMap } from "../variable/LoaderInfoMap"; -import { response } from "../variable/Response"; -import type { LoaderInfo } from "@next2d/display"; -import type { ParentImpl } from "@next2d/interface"; -import { RequestImpl } from "src/interface/RequestImpl"; - -/** - * @param {string} name - * @return {void} - * @method - * @public - */ -export const execute = (name: string): void => -{ - const requests: RequestImpl[] = requestParser(name); - for (let idx: number = 0; idx < requests.length; ++idx) { - - const object: RequestImpl = requests[idx]; - - if (object.type !== "content") { - continue; - } - - if (object.cache - || !object.name - || !response.has(object.name) - ) { - continue; - } - - /** - * キャッシュしないパッケージはインメモリから削除 - * Remove non-cached packages from in-memory - */ - const content: ParentImpl = response.get(object.name); - const contentLoaderInfo: LoaderInfo | null = content._$loaderInfo; - if (contentLoaderInfo && contentLoaderInfo._$data) { - const symbols: Map = contentLoaderInfo._$data.symbols; - if (symbols.size) { - for (const name of symbols.keys()) { - loaderInfoMap.delete(name); - } - } - } - } - - /** - * レスポンスデータを初期化 - * Initialize response data - */ - if (response.size) { - response.clear(); - } -}; \ No newline at end of file diff --git a/src/application/variable/Cache.ts b/src/application/variable/Cache.ts index 40a3054..d2b89e7 100644 --- a/src/application/variable/Cache.ts +++ b/src/application/variable/Cache.ts @@ -1 +1,5 @@ +/** + * @type {Map} + * @protected + */ export const cache: Map = new Map(); \ No newline at end of file diff --git a/src/application/variable/Config.ts b/src/application/variable/Config.ts index c832d91..4e54ea3 100644 --- a/src/application/variable/Config.ts +++ b/src/application/variable/Config.ts @@ -1,18 +1,34 @@ -import { ConfigImpl } from "../../interface/ConfigImpl"; +import type { IConfig } from "../../interface/IConfig"; /** - * @type {object} - * @public + * @type {IConfig} + * @private */ -export let config: ConfigImpl; +let $config: IConfig; /** - * @param {object} object + * @description 環境設定として書き出ししたobjectをセットします + * Set the object written as environment settings + * + * @param {IConfig} object * @return {void} * @method - * @private + * @protected + */ +export const $setConfig = (object: IConfig): void => +{ + $config = object; +}; + +/** + * @description 環境設定としてセットされたobjectを返却します + * Returns the object set as environment settings + * + * @return {IConfig} + * @method + * @protected */ -export const $setConfig = (object: ConfigImpl): void => +export const $getConfig = (): IConfig => { - config = object; + return $config; }; \ No newline at end of file diff --git a/src/application/variable/Context.ts b/src/application/variable/Context.ts index 6bf6295..5f76ca0 100644 --- a/src/application/variable/Context.ts +++ b/src/application/variable/Context.ts @@ -1,29 +1,33 @@ -import { Context } from "../Context"; -import type { Sprite } from "@next2d/display"; -import type { ConfigImpl } from "../../interface/ConfigImpl"; +import type { Context } from "../Context"; /** * @type {Context} * @public */ -export let context: Context; +let $context: Context; /** - * @param {object} config - * @return {void} + * @description コンテキストを取得します + * Get the context + * + * @return {Context} * @method - * @private + * @protected */ -export const $createContext = async (config: ConfigImpl): Promise => +export const $getContext = (): Context => { - const root: Sprite = await window - .next2d - .createRootMovieClip( - config.stage.width, - config.stage.height, - config.stage.fps, - config.stage.options - ); + return $context as NonNullable; +}; - context = new Context(root); +/** + * @description コンテキストを設定します + * Set the context + * + * @param {Context} context + * @method + * @protected + */ +export const $setContext = (context: Context): void => +{ + $context = context; }; \ No newline at end of file diff --git a/src/application/variable/LoaderInfoMap.ts b/src/application/variable/LoaderInfoMap.ts index 4cf9b45..67ba461 100644 --- a/src/application/variable/LoaderInfoMap.ts +++ b/src/application/variable/LoaderInfoMap.ts @@ -1,3 +1,7 @@ import type { LoaderInfo } from "@next2d/display"; +/** + * @type {Map} + * @protected + */ export const loaderInfoMap: Map = new Map(); \ No newline at end of file diff --git a/src/application/variable/Packages.ts b/src/application/variable/Packages.ts index fd9e778..f6055bb 100644 --- a/src/application/variable/Packages.ts +++ b/src/application/variable/Packages.ts @@ -1,16 +1,16 @@ /** * @type {Map} - * @public + * @protected */ -export let packages: Map = new Map(); +export let packages: Map = new Map(); /** - * @param {array} package_list + * @param {Array>} package_list * @return {void} * @method - * @private + * @protected */ -export const $setPackages = (package_list: any[]): void => +export const $setPackages = (package_list: any): void => { packages = new Map(package_list); }; \ No newline at end of file diff --git a/src/application/variable/Query.ts b/src/application/variable/Query.ts index a357963..3046049 100644 --- a/src/application/variable/Query.ts +++ b/src/application/variable/Query.ts @@ -1 +1,5 @@ +/** + * @type {Map} + * @protected + */ export const query: Map = new Map(); \ No newline at end of file diff --git a/src/domain/callback/Callback.test.ts b/src/domain/callback/Callback.test.ts deleted file mode 100644 index ba6982f..0000000 --- a/src/domain/callback/Callback.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { execute } from "./Callback"; -import { packages } from "../../application/variable/Packages"; - -describe("CallbackTest", () => -{ - test("execute test case1", () => - { - execute() - .then((result) => - { - expect(result).toBe(undefined); - }); - }); - - test("execute single test", () => - { - // mock - const SingleTest = class SingleTest - { - execute (value: any): any - { - return value; - } - }; - - packages.clear(); - packages.set("SingleTest", SingleTest); - - execute("SingleTest", "single test") - .then((results: string[] | void) => - { - if (!results) { - throw new Error("stop test"); - } - - expect(results.length).toBe(1); - const result: string = results[0]; - expect(result).toBe("single test"); - }); - }); - - test("execute multiple test", () => - { - // mock - const MultipleTestCase1 = class MultipleTest - { - execute (value: any): any - { - return `${value}_1`; - } - }; - - const MultipleTestCase2 = class MultipleTest - { - execute (value: any): any - { - return `${value}_2`; - } - }; - - packages.clear(); - packages.set("multiple.test.case1", MultipleTestCase1); - packages.set("multiple.test.case2", MultipleTestCase2); - - execute(["multiple.test.case1", "multiple.test.case2"], "multiple test") - .then((results: string[] | void) => - { - if (!results) { - throw new Error("stop test"); - } - - expect(results.length).toBe(2); - const result1: string = results[0]; - expect(result1).toBe("multiple test_1"); - - const result2: string = results[1]; - expect(result2).toBe("multiple test_2"); - }); - }); -}); \ No newline at end of file diff --git a/src/domain/callback/service/CallbackService.test.ts b/src/domain/callback/service/CallbackService.test.ts new file mode 100644 index 0000000..a845341 --- /dev/null +++ b/src/domain/callback/service/CallbackService.test.ts @@ -0,0 +1,66 @@ +import { execute } from "./CallbackService"; +import { packages } from "../../../application/variable/Packages"; +import { describe, expect, it } from "vitest"; + +describe("CallbackService Test", () => +{ + it("execute test case1", async () => + { + const result = await execute() + expect(result).toBe(undefined); + }); + + it("execute single test", async () => + { + // mock + let state = "none"; + const SingleTest = class SingleTest + { + execute (value: any): any + { + state = value; + } + }; + + packages.clear(); + packages.set("SingleTest", SingleTest); + + expect(state).toBe("none"); + await execute("SingleTest", "single test"); + expect(state).toBe("single test"); + }); + + it("execute multiple test", async () => + { + // mock + let state1 = "none"; + const MultipleTestCase1 = class MultipleTest + { + execute (value: any): any + { + state1 = `${value}_1`; + } + }; + + let state2 = "none"; + const MultipleTestCase2 = class MultipleTest + { + execute (value: any): any + { + state2 = `${value}_2`; + } + }; + + packages.clear(); + packages.set("multiple.test.case1", MultipleTestCase1); + packages.set("multiple.test.case2", MultipleTestCase2); + + expect(state1).toBe("none"); + expect(state2).toBe("none"); + + await execute(["multiple.test.case1", "multiple.test.case2"], "multiple test") + + expect(state1).toBe("multiple test_1"); + expect(state2).toBe("multiple test_2"); + }); +}); \ No newline at end of file diff --git a/src/domain/callback/Callback.ts b/src/domain/callback/service/CallbackService.ts similarity index 59% rename from src/domain/callback/Callback.ts rename to src/domain/callback/service/CallbackService.ts index f529cb6..4cafd77 100644 --- a/src/domain/callback/Callback.ts +++ b/src/domain/callback/service/CallbackService.ts @@ -1,39 +1,36 @@ -import { packages } from "../../application/variable/Packages"; +import { packages } from "../../../application/variable/Packages"; /** * @description configで指定されたクラスのexecute関数を実行 * Execute function of the class specified in config. * - * @param {string|array} [callback=""] + * @param {string | string[]} [callback=""] * @param {*} [value=null] * @return {Promise} * @method * @public */ -export const execute = ( +export const execute = async ( callback: string | string[] = "", value: any = null ): Promise[]|void> => { if (!callback) { - return Promise.resolve(); + return ; } const callbacks: string[] = typeof callback === "string" ? [callback] : callback; - const promises: Promise[] = []; - for (let idx: number = 0; idx < callbacks.length; ++idx) { + for (let idx = 0; idx < callbacks.length; ++idx) { - const name: string = callbacks[idx]; + const name = callbacks[idx]; if (!packages.has(name)) { continue; } const CallbackClass: any = packages.get(name); - promises.push(new CallbackClass().execute(value)); + await new CallbackClass().execute(value); } - - return Promise.all(promises); }; \ No newline at end of file diff --git a/src/domain/convert/ToCamelCase.test.ts b/src/domain/convert/ToCamelCase.test.ts deleted file mode 100644 index 91dddbf..0000000 --- a/src/domain/convert/ToCamelCase.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { execute } from "./ToCamelCase"; - -describe("ToCamelCaseTest", () => -{ - test("execute test case1", () => - { - expect(execute("home")).toBe("Home"); - }); - - test("execute test case2", () => - { - expect(execute("quest/list")).toBe("QuestList"); - }); - - test("execute test case3", () => - { - expect(execute("game/list/page")).toBe("GameListPage"); - }); -}); \ No newline at end of file diff --git a/src/domain/loading/DefaultLoader.ts b/src/domain/loading/DefaultLoader.ts new file mode 100644 index 0000000..a278c22 --- /dev/null +++ b/src/domain/loading/DefaultLoader.ts @@ -0,0 +1,71 @@ +import { Sprite } from "@next2d/display"; +import { execute as defaultLoadingInitializeService } from "./DefaultLoading/service/DefaultLoadingInitializeService"; +import { execute as defaultLoaderStartService } from "./DefaultLoading/service/DefaultLoaderStartService"; +import { execute as defaultLoaderEndService } from "./DefaultLoading/service/DefaultLoaderEndService"; + +/** + * @description デフォルトのローディング演出 + * Default loading direction + * + * @class + */ +export class DefaultLoader +{ + /** + * @description ローディング演出に使用するSprite + * Sprite used for loading direction + * + * @type {Sprite} + * @public + */ + public readonly sprite: Sprite; + + /** + * @constructor + */ + constructor () + { + this.sprite = new Sprite(); + this.initialize(); + } + + /** + * @description ローディング演出の初期化 + * Initialization of loading direction + * + * @return {void} + * @method + * @public + */ + initialize (): void + { + defaultLoadingInitializeService(this); + } + + /** + * @description Canvasが設置されたDOMにローディング演出を登録、既にDOMがあれば演出を表示 + * Register loading direction in the DOM where Canvas is installed, + * and display the direction if the DOM already exists. + * + * @return {void} + * @method + * @public + */ + start (): void + { + defaultLoaderStartService(this); + } + + /** + * @description ローディング演出を非表示にする + * Hide loading direction + * + * @return {void} + * @method + * @public + */ + end (): void + { + defaultLoaderEndService(this); + } +} \ No newline at end of file diff --git a/src/domain/loading/DefaultLoading/service/DefaultLoaderEndService.test.ts b/src/domain/loading/DefaultLoading/service/DefaultLoaderEndService.test.ts new file mode 100644 index 0000000..09e6535 --- /dev/null +++ b/src/domain/loading/DefaultLoading/service/DefaultLoaderEndService.test.ts @@ -0,0 +1,53 @@ +import type { Shape } from "@next2d/display"; +import type { Job } from "@next2d/ui"; +import { MovieClip } from "@next2d/display"; +import { Context } from "../../../../application/Context"; +import { $setContext } from "../../../../application/variable/Context"; +import { $setConfig } from "../../../../application/variable/Config"; +import { DefaultLoader } from "../../DefaultLoader"; +import { execute } from "./DefaultLoaderEndService"; +import { describe, expect, it } from "vitest"; + +describe("DefaultLoaderEndService Test", () => +{ + it("execute test", () => + { + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + } + }); + $setContext(new Context(new MovieClip())); + + // mock + const defaultLoader = new DefaultLoader(); + defaultLoader.start(); + + const sprite = defaultLoader.sprite; + const length = sprite.numChildren; + for (let idx = 0; idx < length; ++idx) { + const shape = sprite.getChildAt(idx) as Shape; + expect(shape.hasLocalVariable("reduceJob")).toBe(true); + expect(shape.hasLocalVariable("expandJob")).toBe(true); + + const expandJob = shape.getLocalVariable("expandJob") as Job; + const reduceJob = shape.getLocalVariable("reduceJob") as Job; + expect(expandJob.stopFlag).toBe(false); + expect(reduceJob.stopFlag).toBe(false); + } + + execute(defaultLoader); + + for (let idx = 0; idx < length; ++idx) { + const shape = sprite.getChildAt(idx) as Shape; + const expandJob = shape.getLocalVariable("expandJob") as Job; + const reduceJob = shape.getLocalVariable("reduceJob") as Job; + expect(expandJob.entries).toBeNull(); + expect(reduceJob.entries).toBeNull(); + } + }); +}); \ No newline at end of file diff --git a/src/domain/loading/DefaultLoading/service/DefaultLoaderEndService.ts b/src/domain/loading/DefaultLoading/service/DefaultLoaderEndService.ts new file mode 100644 index 0000000..12d7360 --- /dev/null +++ b/src/domain/loading/DefaultLoading/service/DefaultLoaderEndService.ts @@ -0,0 +1,42 @@ +import type { DefaultLoader } from "../../DefaultLoader"; +import type { Shape } from "@next2d/display"; +import type { Job } from "@next2d/ui"; +import { $getContext } from "../../../../application/variable/Context"; + +/** + * @description ローダーのアニメーションを終了 + * End loader animation + * + * @param {DefaultLoader} default_loader + * @return {void} + * @method + * @protected + */ +export const execute = (default_loader: DefaultLoader): void => +{ + const root = $getContext().root; + if (!root) { + return ; + } + + const sprite = default_loader.sprite; + for (let idx = 0; idx < 3; ++idx) { + + const shape = sprite.getChildAt(idx); + if (!shape) { + continue ; + } + + if (shape.hasLocalVariable("expandJob")) { + const expandJob = shape.getLocalVariable("expandJob") as Job; + expandJob.stop(); + } + + if (shape.hasLocalVariable("reduceJob")) { + const reduceJob = shape.getLocalVariable("reduceJob") as Job; + reduceJob.stop(); + } + } + + root.removeChild(sprite); +}; \ No newline at end of file diff --git a/src/domain/loading/DefaultLoading/service/DefaultLoaderStartService.test.ts b/src/domain/loading/DefaultLoading/service/DefaultLoaderStartService.test.ts new file mode 100644 index 0000000..1a5c600 --- /dev/null +++ b/src/domain/loading/DefaultLoading/service/DefaultLoaderStartService.test.ts @@ -0,0 +1,44 @@ +import type { Shape } from "@next2d/display"; +import { MovieClip } from "@next2d/display"; +import { Context } from "../../../../application/Context"; +import { $setContext } from "../../../../application/variable/Context"; +import { $setConfig } from "../../../../application/variable/Config"; +import { DefaultLoader } from "../../DefaultLoader"; +import { execute } from "./DefaultLoaderStartService"; +import { describe, expect, it } from "vitest"; + +describe("DefaultLoaderStartService Test", () => +{ + it("execute test", async () => + { + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + } + }); + $setContext(new Context(new MovieClip())); + + // mock + const defaultLoader = new DefaultLoader(); + + const sprite = defaultLoader.sprite; + const length = sprite.numChildren; + for (let idx = 0; idx < length; ++idx) { + const shape = sprite.getChildAt(idx) as Shape; + expect(shape.hasLocalVariable("reduceJob")).toBe(false); + expect(shape.hasLocalVariable("expandJob")).toBe(false); + } + + execute(defaultLoader); + + for (let idx = 0; idx < length; ++idx) { + const shape = sprite.getChildAt(idx) as Shape; + expect(shape.hasLocalVariable("reduceJob")).toBe(true); + expect(shape.hasLocalVariable("expandJob")).toBe(true); + } + }); +}); \ No newline at end of file diff --git a/src/domain/loading/DefaultLoading/service/DefaultLoaderStartService.ts b/src/domain/loading/DefaultLoading/service/DefaultLoaderStartService.ts new file mode 100644 index 0000000..5cfe2c8 --- /dev/null +++ b/src/domain/loading/DefaultLoading/service/DefaultLoaderStartService.ts @@ -0,0 +1,123 @@ +import type { DefaultLoader } from "../../DefaultLoader"; +import type { Shape } from "@next2d/display"; +import type { Job } from "@next2d/ui"; +import { $getConfig } from "../../../../application/variable/Config"; +import { $getContext } from "../../../../application/variable/Context"; +import { + Tween, + Easing +} from "@next2d/ui"; + +/** + * @description ローダーのアニメーションを実行 + * Execute loader animation + * + * @param {DefaultLoader} default_loader + * @return {void} + * @method + * @protected + */ +export const execute = (default_loader: DefaultLoader): void => +{ + const root = $getContext().root; + if (!root) { + return ; + } + + const config = $getConfig(); + const sprite = default_loader.sprite; + + const minSize = Math.ceil(Math.min(config.stage.width, config.stage.height) / 100); + const halfSize = minSize / 2; + for (let idx = 0; idx < 3; ++idx) { + + const shape = sprite.getChildAt(idx); + if (!shape) { + continue ; + } + + /** + * 初期値を設定 + * Set initial values + */ + shape.scaleX = 0.1; + shape.scaleY = 0.1; + shape.alpha = 0; + + let reduceJob: Job; + if (shape.hasLocalVariable("reduceJob")) { + reduceJob = shape.getLocalVariable("reduceJob") as Job; + reduceJob.stop(); + } else { + reduceJob = Tween.add( + shape, + { + "scaleX": 0.1, + "scaleY": 0.1, + "alpha": 0 + }, + { + "scaleX": 1, + "scaleY": 1, + "alpha": 1 + }, + 0.12, + 0.5, + Easing.inOutCubic + ); + shape.setLocalVariable("reduceJob", reduceJob); + } + + let expandJob: Job; + if (shape.hasLocalVariable("expandJob")) { + expandJob = shape.getLocalVariable("expandJob") as Job; + expandJob.stop(); + } else { + expandJob = Tween.add( + shape, + { + "scaleX": 0.1, + "scaleY": 0.1, + "alpha": 0 + }, + { + "scaleX": 1, + "scaleY": 1, + "alpha": 1 + }, + 0.12, + 0.5, + Easing.inOutCubic + ); + shape.setLocalVariable("expandJob", expandJob); + } + + reduceJob.nextJob = expandJob; + expandJob.nextJob = reduceJob; + + if (idx) { + setTimeout((): void => + { + expandJob.start(); + }, 120 * idx); + } else { + expandJob.start(); + } + + if (shape.width === minSize) { + continue; + } + + shape + .graphics + .clear() + .beginFill("#ffffff") + .drawCircle(0, 0, halfSize); + + shape.x = minSize * 2 * idx; + } + + sprite.x = (config.stage.width - sprite.width) / 2; + sprite.y = (config.stage.height - sprite.height) / 2; + root.addChild(sprite); +}; \ No newline at end of file diff --git a/src/domain/loading/DefaultLoading/service/DefaultLoadingInitializeService.test.ts b/src/domain/loading/DefaultLoading/service/DefaultLoadingInitializeService.test.ts new file mode 100644 index 0000000..2e2b330 --- /dev/null +++ b/src/domain/loading/DefaultLoading/service/DefaultLoadingInitializeService.test.ts @@ -0,0 +1,19 @@ +import type { DefaultLoader } from "../../DefaultLoader"; +import { execute } from "./DefaultLoadingInitializeService"; +import { Sprite } from "@next2d/display"; +import { describe, expect, it } from "vitest"; + +describe("DefaultLoadingInitializeService Test", () => +{ + it("execute test", async () => + { + // mock + const defaultLoader = { + "sprite": new Sprite(), + } as DefaultLoader; + + expect(defaultLoader.sprite.numChildren).toBe(0); + execute(defaultLoader); + expect(defaultLoader.sprite.numChildren).toBe(3); + }); +}); \ No newline at end of file diff --git a/src/domain/loading/DefaultLoading/service/DefaultLoadingInitializeService.ts b/src/domain/loading/DefaultLoading/service/DefaultLoadingInitializeService.ts new file mode 100644 index 0000000..b3f7efd --- /dev/null +++ b/src/domain/loading/DefaultLoading/service/DefaultLoadingInitializeService.ts @@ -0,0 +1,18 @@ +import type { DefaultLoader } from "../../DefaultLoader"; +import { Shape } from "@next2d/display"; + +/** + * @description ローディング演出の初期登録 + * Initial registration of loading direction + * + * @param {DefaultLoader} default_loader + * @return {void} + * @method + * @protected + */ +export const execute = (default_loader: DefaultLoader): void => +{ + for (let idx = 0; idx < 3; ++idx) { + default_loader.sprite.addChild(new Shape()); + } +}; \ No newline at end of file diff --git a/src/domain/loading/Loading.ts b/src/domain/loading/Loading.ts index 1016488..aa7a071 100644 --- a/src/domain/loading/Loading.ts +++ b/src/domain/loading/Loading.ts @@ -1,86 +1,35 @@ -import type { LoadingImpl } from "src/interface/LoadingImpl"; -import { config } from "../../application/variable/Config"; -import { packages } from "../../application/variable/Packages"; -import { DefaultLoading } from "../screen/DefaultLoading"; +import type { ILoading } from "src/interface/ILoading"; /** * @type {object} * @default null * @private */ -let $instance: LoadingImpl | null = null; +let $instance: ILoading | null = null; /** - * @description ページ遷移時のローディング演出を開始 - * Starts loading performance at page transitions + * @description ローダーのインスタンスを取得 + * Get loader instance * - * @return {Promise} + * @return {ILoading} * @method * @public */ -export const start = (): Promise => +export const $getInstance = (): ILoading => { - return new Promise((resolve): void => - { - if (!config || !config.loading) { - return resolve(); - } - - const name: string | void = config.loading.callback; - if (!name) { - return resolve(); - } - - if (!$instance) { - const CallbackClass: any = packages.has(name) - ? packages.get(name) - : DefaultLoading; - - $instance = new CallbackClass(); - } - - if (!$instance) { - return resolve(); - } - - resolve($instance.start()); - }); + return $instance as ILoading; }; /** - * @description ページ遷移時のローディング演出を終了 - * Terminate loading direction at page transition + * @description ローダーのインスタンスを設定 + * Set loader instance * - * @return {Promise} + * @param {ILoading} instance + * @return {void} * @method * @public */ -export const end = (): Promise => +export const $setInstance = (instance: ILoading): void => { - return new Promise((resolve): void => - { - if (!config || !config.loading) { - return resolve(); - } - - const name: string | undefined = config.loading.callback; - if (!name) { - return resolve(); - } - - if (!$instance) { - - const CallbackClass: any = packages.has(name) - ? packages.get(name) - : DefaultLoading; - - $instance = new CallbackClass(); - } - - if (!$instance) { - return resolve(); - } - - resolve($instance.end()); - }); + $instance = instance; }; \ No newline at end of file diff --git a/src/domain/loading/Loading/service/LoadingEndService.test.ts b/src/domain/loading/Loading/service/LoadingEndService.test.ts new file mode 100644 index 0000000..645897b --- /dev/null +++ b/src/domain/loading/Loading/service/LoadingEndService.test.ts @@ -0,0 +1,40 @@ +import { execute } from "./LoadingEndService"; +import { $setConfig } from "../../../../application/variable/Config"; +import { packages } from "../../../../application/variable/Packages"; +import { $setInstance } from "../../Loading"; +import { describe, expect, it } from "vitest"; + +describe("LoadingEndService Test", () => +{ + it("execute test", async () => + { + // mock + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + }, + "loading": { + "callback": "LoaderTest" + } + }); + + let state = "none"; + class LoaderTest { + end (): void { + state = "start"; + } + } + + packages.clear(); + packages.set("LoaderTest", LoaderTest); + + $setInstance(null); + expect(state).toBe("none"); + await execute(); + expect(state).toBe("start"); + }); +}); \ No newline at end of file diff --git a/src/domain/loading/Loading/service/LoadingEndService.ts b/src/domain/loading/Loading/service/LoadingEndService.ts new file mode 100644 index 0000000..921e02a --- /dev/null +++ b/src/domain/loading/Loading/service/LoadingEndService.ts @@ -0,0 +1,41 @@ +import { DefaultLoader } from "../../DefaultLoader"; +import { $getConfig } from "../../../../application/variable/Config"; +import { packages } from "../../../../application/variable/Packages"; +import { + $getInstance, + $setInstance +} from "../../Loading"; + +/** + * @description ローダーのアニメーションを終了 + * End loader animation + * + * @return {Promise} + * @method + * @protected + */ +export const execute = async (): Promise => +{ + const config = $getConfig(); + if (!config || !config.loading) { + return ; + } + + const name: string | undefined = config.loading.callback; + if (!name) { + return ; + } + + let instance = $getInstance(); + if (!instance) { + + const LoaderClass: any = packages.has(name) + ? packages.get(name) + : DefaultLoader; + + instance = new LoaderClass(); + $setInstance(instance); + } + + await instance.end(); +}; \ No newline at end of file diff --git a/src/domain/loading/Loading/service/LoadingStartService.test.ts b/src/domain/loading/Loading/service/LoadingStartService.test.ts new file mode 100644 index 0000000..a3132d8 --- /dev/null +++ b/src/domain/loading/Loading/service/LoadingStartService.test.ts @@ -0,0 +1,71 @@ +import { execute } from "./LoadingStartService"; +import { MovieClip } from "@next2d/display"; +import { Context } from "../../../../application/Context"; +import { $setContext } from "../../../../application/variable/Context"; +import { $setConfig } from "../../../../application/variable/Config"; +import { packages } from "../../../../application/variable/Packages"; +import { + $getInstance, + $setInstance +} from "../../Loading"; +import { describe, expect, it } from "vitest"; + +describe("LoadingStartService Test", () => +{ + it("execute test case1", async () => + { + // mock + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + }, + "loading": { + "callback": "Loader" + } + }); + + const root = new MovieClip(); + $setContext(new Context(root)); + + $setInstance(null); + expect($getInstance()).toBeNull(); + await execute(); + expect($getInstance()).not.toBeNull(); + }); + + it("execute test case2", async () => + { + // mock + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + }, + "loading": { + "callback": "LoaderTest" + } + }); + + let state = "none"; + class LoaderTest { + start (): void { + state = "start"; + } + } + + packages.clear(); + packages.set("LoaderTest", LoaderTest); + + $setInstance(null); + expect(state).toBe("none"); + await execute(); + expect(state).toBe("start"); + }); +}); \ No newline at end of file diff --git a/src/domain/loading/Loading/service/LoadingStartService.ts b/src/domain/loading/Loading/service/LoadingStartService.ts new file mode 100644 index 0000000..fab5f17 --- /dev/null +++ b/src/domain/loading/Loading/service/LoadingStartService.ts @@ -0,0 +1,41 @@ +import { DefaultLoader } from "../../DefaultLoader"; +import { $getConfig } from "../../../../application/variable/Config"; +import { packages } from "../../../../application/variable/Packages"; +import { + $getInstance, + $setInstance +} from "../../Loading"; + +/** + * @description ローダーのアニメーションを実行 + * Execute loader animation + * + * @return {Promise} + * @method + * @protected + */ +export const execute = async (): Promise => +{ + const config = $getConfig(); + if (!config || !config.loading) { + return ; + } + + const name: string | void = config.loading.callback; + if (!name) { + return ; + } + + let instance = $getInstance(); + if (!instance) { + + const LoaderClass: any = packages.has(name) + ? packages.get(name) + : DefaultLoader; + + instance = new LoaderClass(); + $setInstance(instance); + } + + await instance.start(); +}; \ No newline at end of file diff --git a/src/domain/screen/Capture.ts b/src/domain/screen/Capture.ts index e77e043..550013e 100644 --- a/src/domain/screen/Capture.ts +++ b/src/domain/screen/Capture.ts @@ -1,106 +1,13 @@ -import { config } from "../../application/variable/Config"; -import { context } from "../../application/variable/Context"; -import { $currentPlayer } from "@next2d/util"; import { Shape } from "@next2d/display"; -import type { Sprite } from "@next2d/display"; -import type { Player } from "@next2d/core"; /** * @type {Shape} * @private */ -const shape: Shape = new Shape(); +export const shape: Shape = new Shape(); /** - * @type {number} - * @default 0 - * @private - */ -let cacheX: number = 0; - -/** - * @type {number} - * @default 0 + * @type {Shape} * @private */ -let cacheY: number = 0; - -/** - * @description 現時点の描画キャプチャーを生成 - * Generate current drawing capture - * - * @return {Promise} - * @method - * @public - */ -export const execute = (): Promise => -{ - return new Promise((resolve) => - { - const width: number = config.stage.width; - const height: number = config.stage.height; - if (shape.width !== width || shape.width !== height) { - shape - .graphics - .clear() - .beginFill(0, 0.8) - .drawRect(0, 0, width, height) - .endFill(); - } - - const player: Player = $currentPlayer(); - - const tx: number = player.x; - if (tx && cacheX !== tx) { - cacheX = tx; - const scaleX: number = player.scaleX; - shape.scaleX = (width + tx * 2 / scaleX) / width; - shape.x = -tx / scaleX; - } - - const ty: number = player.y; - if (ty && cacheY !== ty) { - cacheY = ty; - const scaleY: number = player.scaleY; - shape.scaleY = (height + ty * 2 / scaleY) / height; - shape.y = -ty / scaleY; - } - - const root: Sprite = context.root; - if (root) { - /** - * マウス操作を強制停止 - * Mouse operation is forced to stop - */ - root.mouseChildren = false; - root.addChild(shape); - } - - resolve(); - }); -}; - -/** - * @description 画面キャプチャーのShapeをStageから削除 - * Delete Screen Capture Shape from Stage - * - * @return {void} - * @method - * @public - */ -export const dispose = (): void => -{ - const root: Sprite = context.root; - if (root) { - - if (shape.parent === root) { - root.removeChild(shape); - } - - /** - * マウス操作を有効化 - * Enable Mouse Operation - */ - root.mouseChildren = true; - } -}; \ No newline at end of file +export const bitmap: Shape = new Shape(); \ No newline at end of file diff --git a/src/domain/screen/Capture/service/AddScreenCaptureService.test.ts b/src/domain/screen/Capture/service/AddScreenCaptureService.test.ts new file mode 100644 index 0000000..668c070 --- /dev/null +++ b/src/domain/screen/Capture/service/AddScreenCaptureService.test.ts @@ -0,0 +1,40 @@ +import { execute } from "./AddScreenCaptureService"; +import { MovieClip } from "@next2d/display"; +import { Context } from "../../../../application/Context"; +import { $setContext } from "../../../../application/variable/Context"; +import { $setConfig } from "../../../../application/variable/Config"; +import { describe, expect, it, vi } from "vitest"; + +Object.defineProperty(window, "next2d", { + "get": vi.fn().mockReturnValue({ + "captureToCanvas": async () => { + return document.createElement("canvas"); + } + }) +}); + +describe("AddScreenCaptureService Test", () => +{ + it("execute test", async () => + { + // mock + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + } + }); + + const root = new MovieClip(); + $setContext(new Context(root)); + + expect(root.numChildren).toBe(0); + expect(root.mouseChildren).toBe(true); + await execute(); + expect(root.numChildren).toBe(2); + expect(root.mouseChildren).toBe(false); + }); +}); \ No newline at end of file diff --git a/src/domain/screen/Capture/service/AddScreenCaptureService.ts b/src/domain/screen/Capture/service/AddScreenCaptureService.ts new file mode 100644 index 0000000..da4097b --- /dev/null +++ b/src/domain/screen/Capture/service/AddScreenCaptureService.ts @@ -0,0 +1,97 @@ +import { $getConfig } from "../../../../application/variable/Config"; +import { $getContext } from "../../../../application/variable/Context"; +import { Matrix } from "@next2d/geom"; +import { shape } from "../../Capture"; +import { + stage, + BitmapData, + Shape +} from "@next2d/display"; + +/** + * @type {number} + * @private + */ +let $cacheX: number = 0; + +/** + * @type {number} + * @private + */ +let $cacheY: number = 0; + +/** + * @description 画面キャプチャーのShapeをStageに追加 + * Add Screen Capture Shape to Stage + * + * @return {void} + * @method + * @protected + */ +export const execute = async (): Promise => +{ + const root = $getContext().root; + if (!root) { + return ; + } + + /** + * マウス操作を強制停止 + * Mouse operation is forced to stop + */ + root.mouseChildren = false; + + const canvas = await next2d.captureToCanvas(root, { + "matrix": new Matrix(stage.rendererScale, 0, 0, stage.rendererScale, 0, 0) + }); + + const rectangle = root.getBounds(); + const bitmapData = new BitmapData(canvas.width, canvas.height); + + bitmapData.canvas = canvas; + + const bitmap = new Shape(); + bitmap.x = rectangle.x; + bitmap.y = rectangle.y; + if (stage.rendererScale !== 1) { + bitmap.scaleX = 1 / stage.rendererScale; + bitmap.scaleY = 1 / stage.rendererScale; + } + + bitmap.setBitmapBuffer( + canvas.width, canvas.height, + bitmapData.buffer as Uint8Array + ); + + root.addChild(bitmap); + + const config = $getConfig(); + const width = config.stage.width; + const height = config.stage.height; + if (shape.width !== width || shape.width !== height) { + shape + .graphics + .clear() + .beginFill(0, 0.8) + .drawRect(0, 0, width, height) + .endFill(); + } + + const scale = stage.rendererScale; + + const tx = (stage.rendererWidth - stage.stageWidth * scale) / 2; + if (tx && $cacheX !== tx) { + $cacheX = tx; + shape.scaleX = (width + tx * 2 / scale) / width; + shape.x = -tx / scale; + } + + const ty = (stage.rendererHeight - stage.stageHeight * scale) / 2; + if (ty && $cacheY !== ty) { + $cacheY = ty; + shape.scaleY = (height + ty * 2 / scale) / height; + shape.y = -ty / scale; + } + + root.addChild(shape); +}; \ No newline at end of file diff --git a/src/domain/screen/Capture/service/DisposeCaptureService.test.ts b/src/domain/screen/Capture/service/DisposeCaptureService.test.ts new file mode 100644 index 0000000..3b7f5e9 --- /dev/null +++ b/src/domain/screen/Capture/service/DisposeCaptureService.test.ts @@ -0,0 +1,40 @@ +import { execute } from "./DisposeCaptureService"; +import { MovieClip } from "@next2d/display"; +import { Context } from "../../../../application/Context"; +import { $setContext } from "../../../../application/variable/Context"; +import { $setConfig } from "../../../../application/variable/Config"; +import { + shape, + bitmap +} from "../../Capture"; +import { describe, expect, it } from "vitest"; + +describe("DisposeCaptureService Test", () => +{ + it("execute test", async () => + { + // mock + $setConfig({ + "platform": "web", + "spa": false, + "stage": { + "width": 800, + "height": 600, + "fps": 60 + } + }); + + const root = new MovieClip(); + $setContext(new Context(root)); + + root.mouseChildren = false; + root.addChild(shape); + root.addChild(bitmap); + + expect(root.numChildren).toBe(2); + expect(root.mouseChildren).toBe(false); + execute(); + expect(root.numChildren).toBe(0); + expect(root.mouseChildren).toBe(true); + }); +}); \ No newline at end of file diff --git a/src/domain/screen/Capture/service/DisposeCaptureService.ts b/src/domain/screen/Capture/service/DisposeCaptureService.ts new file mode 100644 index 0000000..e6cdb87 --- /dev/null +++ b/src/domain/screen/Capture/service/DisposeCaptureService.ts @@ -0,0 +1,31 @@ +import { $getContext } from "../../../../application/variable/Context"; + +/** + * @description 画面キャプチャーのShapeをStageから削除 + * Delete Screen Capture Shape from Stage + * + * @return {void} + * @method + * @protected + */ +export const execute = (): void => +{ + const root = $getContext().root; + if (!root) { + return ; + } + + /** + * rootの子要素を全て削除 + * Remove all child elements of root + */ + while (root.numChildren > 0) { + root.removeChildAt(0); + } + + /** + * マウス操作を有効化 + * Enable Mouse Operation + */ + root.mouseChildren = true; +}; \ No newline at end of file diff --git a/src/domain/screen/DefaultLoading.ts b/src/domain/screen/DefaultLoading.ts deleted file mode 100644 index dc99766..0000000 --- a/src/domain/screen/DefaultLoading.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { context } from "../../application/variable/Context"; -import { config } from "../../application/variable/Config"; -import { Sprite, Shape } from "@next2d/display"; -import { Tween, Job, Easing } from "@next2d/ui"; -import { Event } from "@next2d/events"; - -/** - * @type {Sprite} - * @private - */ -const $sprite: Sprite = new Sprite(); - -/** - * @return {object} - * @method - * @private - */ -const getStartObject = (): object => { - return { - "scaleX": 0.1, - "scaleY": 0.1, - "alpha": 0 - }; -}; - -/** - * @return {object} - * @method - * @private - */ -const getEndObject = (): object => { - return { - "scaleX": 1, - "scaleY": 1, - "alpha": 1 - }; -}; - -/** - * @description ローディングのアニメーションに必要なDisplayObjectを追加 - * Add DisplayObject needed for loading animation - * - * @return {void} - * @method - * @private - */ -const initialize = (): void => -{ - for (let idx: number = 0; idx < 3; ++idx) { - - const sprite: Sprite = new Sprite(); - sprite.addChild(new Shape()); - - const reduceJob: Job = Tween.add( - sprite, - getEndObject(), - getStartObject(), - 0.12, - 0.5, - Easing.inOutCubic - ); - sprite.setLocalVariable("reduceJob", reduceJob); - - const expandJob: Job = Tween.add( - sprite, - getStartObject(), - getEndObject(), - 0.12, - 0.5, - Easing.inOutCubic - ); - sprite.setLocalVariable("expandJob", expandJob); - - // loop event - reduceJob.addEventListener(Event.COMPLETE, () => - { - const expandJob: Job = sprite.getLocalVariable("expandJob"); - expandJob.from = getStartObject(); - expandJob.to = getEndObject(); - expandJob.start(); - }); - - // loop event - expandJob.addEventListener(Event.COMPLETE, () => - { - const reduceJob: Job = sprite.getLocalVariable("reduceJob"); - reduceJob.from = getEndObject(); - reduceJob.to = getStartObject(); - reduceJob.start(); - }); - - $sprite.addChild(sprite); - } -}; -initialize(); - -/** - * @class - * @memberof domain.screen - */ -export class DefaultLoading -{ - /** - * @description Canvasが設置されたDOMにローディング演出を登録、既にDOMがあれば演出を表示 - * Register loading direction in the DOM where Canvas is installed, - * and display the direction if the DOM already exists. - * - * @return {void} - * @method - * @public - */ - start (): void - { - const minSize: number = Math.ceil(Math.min(config.stage.width, config.stage.height) / 100); - const halfSize: number = minSize / 2; - for (let idx: number = 0; idx < 3; ++idx) { - - const sprite: Sprite = $sprite.getChildAt(idx); - - /** - * 初期値を設定 - * Set initial values - */ - sprite.scaleX = 0.1; - sprite.scaleY = 0.1; - sprite.alpha = 0; - - const reduceJob: Job = sprite.getLocalVariable("reduceJob"); - // reset - reduceJob.from = getEndObject(); - reduceJob.to = getStartObject(); - - const expandJob: Job = sprite.getLocalVariable("expandJob"); - // reset - expandJob.from = getStartObject(); - expandJob.to = getEndObject(); - - if (idx) { - setTimeout((): void => - { - expandJob.start(); - }, 120 * idx); - } else { - expandJob.start(); - } - - const shape: Shape = sprite.getChildAt(0); - if (shape.width === minSize) { - continue; - } - - shape - .graphics - .clear() - .beginFill("#ffffff") - .drawCircle(0, 0, halfSize); - - sprite.x = minSize * 2 * idx; - } - - $sprite.x = (config.stage.width - $sprite.width) / 2; - $sprite.y = (config.stage.height - $sprite.height) / 2; - context.root.addChild($sprite); - } - - /** - * @description ローディング演出を非表示にする - * Hide loading direction - * - * @return {void} - * @method - * @public - */ - end (): void - { - // stop job - for (let idx: number = 0; idx < 3; ++idx) { - const sprite: Sprite = $sprite.getChildAt(idx); - - const expandJob: Job = sprite.getLocalVariable("expandJob"); - expandJob.stop(); - - const reduceJob: Job = sprite.getLocalVariable("reduceJob"); - reduceJob.stop(); - } - - if ($sprite.parent === context.root) { - context.root.removeChild($sprite); - } - } -} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 4a1e71b..5a83e14 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,21 +6,19 @@ import { MovieClipContent } from "./application/content/MovieClipContent"; import { ShapeContent } from "./application/content/ShapeContent"; import { TextFieldContent } from "./application/content/TextFieldContent"; import { VideoContent } from "./application/content/VideoContent"; -import { packages } from "./application/variable/Packages"; -import { context } from "./application/variable/Context"; -import { cache } from "./application/variable/Cache"; -import { query } from "./application/variable/Query"; -import { response } from "./application/variable/Response"; -import { loaderInfoMap } from "./application/variable/LoaderInfoMap"; -import type { ConfigImpl } from "./interface/ConfigImpl"; // output build version -console.log("%c Next2D Framework %c 2.0.0 %c https://next2d.app", +console.log("%c Next2D Framework %c 3.0.0 %c https://next2d.app", "color: #fff; background: #5f5f5f", "color: #fff; background: #4bc729", ""); +/** + * @type {Application} + * @public + */ const app: Application = new Application(); + export { app, View, @@ -28,12 +26,5 @@ export { MovieClipContent, ShapeContent, TextFieldContent, - VideoContent, - packages, - context, - cache, - query, - response, - loaderInfoMap, - ConfigImpl -}; + VideoContent +}; \ No newline at end of file diff --git a/src/infrastructure/Request/repository/RequestContentRepository.ts b/src/infrastructure/Request/repository/RequestContentRepository.ts new file mode 100644 index 0000000..3c98793 --- /dev/null +++ b/src/infrastructure/Request/repository/RequestContentRepository.ts @@ -0,0 +1,107 @@ +import type { IRequest } from "src/interface/IRequest"; +import { Loader } from "@next2d/display"; +import { URLRequest } from "@next2d/net"; +import { cache } from "../../../application/variable/Cache"; +import { loaderInfoMap } from "../../../application/variable/LoaderInfoMap"; +import { ResponseDTO } from "../../Response/dto/ResponseDTO"; +import { execute as callbackService } from "../../../domain/callback/service/CallbackService"; + +/** + * @description 指定先のJSONを非同期で取得 + * Asynchronously obtain JSON of the specified destination + * + * @param {IRequest} request_object + * @return {Promise} + * @method + * @public + */ +export const execute = async (request_object: IRequest): Promise => +{ + if (!request_object.path || !request_object.name) { + throw new Error("`path` and `name` must be set for content requests."); + } + + const name = request_object.name; + + /** + * キャッシュを利用する場合はキャッシュデータをチェック + * Check cache data if cache is used + */ + if (request_object.cache) { + + if (cache.size && cache.has(name)) { + + const value: any = cache.get(name); + + if (request_object.callback) { + await callbackService(request_object.callback, value); + } + + return new ResponseDTO(name, value); + } + } + + const urlRequest = new URLRequest(request_object.path); + + const method: string = request_object.method + ? request_object.method.toUpperCase() + : "GET"; + + switch (method) { + + case "DELETE": + case "GET": + case "HEAD": + case "OPTIONS": + case "POST": + case "PUT": + urlRequest.method = method; + break; + + default: + urlRequest.method = "GET"; + break; + + } + + if (request_object.headers) { + for (const [name, value] of Object.entries(request_object.headers)) { + urlRequest + .requestHeaders + .push({ name, value }); + } + } + + if (request_object.body) { + urlRequest.data = JSON.stringify(request_object.body); + } + + const loader = new Loader(); + await loader.load(urlRequest); + + const content = loader.content; + + /** + * Animation Toolで設定したシンボルをマップに登録 + * Register the symbols set by Animation Tool to the map + */ + const loaderInfo = loader.loaderInfo; + if (loaderInfo.data) { + const symbols: Map = loaderInfo.data.symbols; + if (symbols.size) { + for (const name of symbols.keys()) { + loaderInfoMap.set(name, loaderInfo); + } + } + } + + if (request_object.cache) { + cache.set(request_object.name, content); + } + + if (request_object.callback) { + await callbackService(request_object.callback, content); + } + + return new ResponseDTO(request_object.name, content); +}; \ No newline at end of file diff --git a/src/infrastructure/Request/repository/RequestCustomRepository.test.ts b/src/infrastructure/Request/repository/RequestCustomRepository.test.ts new file mode 100644 index 0000000..e09537a --- /dev/null +++ b/src/infrastructure/Request/repository/RequestCustomRepository.test.ts @@ -0,0 +1,63 @@ +import { execute } from "./RequestCustomRepository"; +import { packages } from "../../../application/variable/Packages"; +import type { IRequest } from "../../../interface/IRequest"; +import { describe, expect, it } from "vitest"; + +describe("RequestCustomRepository Test", () => +{ + it("execute public test", async () => + { + // mock + const object: IRequest = { + "type": "custom", + "name": "CustomRepository", + "path": "next2d", + "method": "publicGet", + "access": "public", + "class": "CustomClass" + }; + + const CustomClass = class CustomClass + { + publicGet () + { + return "publicGet"; + } + }; + + packages.clear(); + packages.set("CustomClass", CustomClass); + + const responseDTO = await execute(object); + expect(responseDTO.name).toBe("CustomRepository"); + expect(responseDTO.response).toBe("publicGet"); + }); + + it("execute static test", async () => + { + // mock + const object: IRequest = { + "type": "custom", + "name": "CustomRepository", + "path": "next2d", + "method": "staticGet", + "access": "static", + "class": "CustomClass" + }; + + const CustomClass = class CustomClass + { + static staticGet () + { + return "staticGet"; + } + }; + + packages.clear(); + packages.set("CustomClass", CustomClass); + + const responseDTO = await execute(object) + expect(responseDTO.name).toBe("CustomRepository"); + expect(responseDTO.response).toBe("staticGet"); + }); +}); diff --git a/src/infrastructure/Request/repository/RequestCustomRepository.ts b/src/infrastructure/Request/repository/RequestCustomRepository.ts new file mode 100644 index 0000000..c13564d --- /dev/null +++ b/src/infrastructure/Request/repository/RequestCustomRepository.ts @@ -0,0 +1,65 @@ +import type { IRequest } from "src/interface/IRequest"; +import { packages } from "../../../application/variable/Packages"; +import { cache } from "../../../application/variable/Cache"; +import { ResponseDTO } from "../../Response/dto/ResponseDTO"; +import { execute as callbackService } from "../../../domain/callback/service/CallbackService"; + +/** + * @description 指定先の外部データを非同期で取得 + * Asynchronous acquisition of external data at specified destination + * + * @param {IRequest} request_object + * @return {Promise} + * @method + * @public + */ +export const execute = async (request_object: IRequest): Promise => +{ + if (!request_object.class + || !request_object.access + || !request_object.method + || !request_object.name + ) { + throw new Error("`class`, `access`, `method` and `name` must be set for custom requests."); + } + + const name = request_object.name; + + /** + * キャッシュを利用する場合はキャッシュデータをチェック + * Check cache data if cache is used + */ + if (request_object.cache) { + + if (cache.size && cache.has(name)) { + + const value: any = cache.get(name); + + if (request_object.callback) { + await callbackService(request_object.callback, value); + } + + return new ResponseDTO(name, value); + } + } + + const className = request_object.class; + if (!packages.has(className)) { + throw new Error("package not found."); + } + + const CallbackClass: any = packages.get(className); + const value = request_object.access === "static" + ? await CallbackClass[request_object.method]() + : await new CallbackClass()[request_object.method](); + + if (request_object.cache) { + cache.set(name, value); + } + + if (request_object.callback) { + await callbackService(request_object.callback, value); + } + + return new ResponseDTO(name, value); +}; \ No newline at end of file diff --git a/__tests__/infrastructure/repository/JsonRepositoryTest.ts b/src/infrastructure/Request/repository/RequestJsonRepository.test.ts similarity index 63% rename from __tests__/infrastructure/repository/JsonRepositoryTest.ts rename to src/infrastructure/Request/repository/RequestJsonRepository.test.ts index 8e1e1ef..426c6dc 100644 --- a/__tests__/infrastructure/repository/JsonRepositoryTest.ts +++ b/src/infrastructure/Request/repository/RequestJsonRepository.test.ts @@ -1,25 +1,14 @@ -import "@next2d/player"; -import { JsonRepository } from "../../../src/infrastructure/repository/JsonRepository"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; +import type { IRequest } from "../../../interface/IRequest"; +import { execute } from "./RequestJsonRepository"; +import { describe, expect, it, vi } from "vitest"; -interface Object { - type: string; - name: string; - path: string; - cache?: boolean; - callback?: string | string[]; - method?: string; - body?: object; - headers?: HeadersInit; -} - -describe("JsonRepository Test", () => +describe("RequestJsonRepository Test", () => { - test("execute fetch get test", () => + it("execute fetch get test", async () => { // mock - const object: Object = { - "type": RequestType.JSON, + const object: IRequest = { + "type": "json", "name": "JsonRepository", "path": "next2d", "method": "GET" @@ -27,7 +16,6 @@ describe("JsonRepository Test", () => const responseMock = (url: any, options: any) => { - expect(url).toBe(object.path); expect(options.method).toBe(object.method); @@ -38,17 +26,18 @@ describe("JsonRepository Test", () => } }); }; - global.fetch = jest.fn().mockImplementation(responseMock); + global.fetch = vi.fn().mockImplementation(responseMock); - const jsonRepository = new JsonRepository(); - jsonRepository.execute(object); + const responseDTO = await execute(object); + expect(responseDTO.name).toBe("JsonRepository"); + expect(responseDTO.response).toBe("success fetch json"); }); - test("execute fetch post test", () => + it("execute fetch post test", async () => { // mock - const object: Object = { - "type": RequestType.JSON, + const object: IRequest = { + "type": "json", "name": "JsonRepository", "path": "next2d", "method": "POST", @@ -75,17 +64,18 @@ describe("JsonRepository Test", () => } }); }; - global.fetch = jest.fn().mockImplementation(responseMock); + global.fetch = vi.fn().mockImplementation(responseMock); - const jsonRepository = new JsonRepository(); - jsonRepository.execute(object); + const responseDTO = await execute(object); + expect(responseDTO.name).toBe("JsonRepository"); + expect(responseDTO.response).toBe("success fetch json"); }); - test("execute fetch put test", () => + it("execute fetch put test", async () => { // mock - const object: Object = { - "type": RequestType.JSON, + const object: IRequest = { + "type": "json", "name": "JsonRepository", "path": "next2d", "method": "PUT", @@ -99,7 +89,6 @@ describe("JsonRepository Test", () => const responseMock = (url: any, options: any) => { - expect(url).toBe(object.path); expect(options.method).toBe(object.method); expect(options.body).toBe(JSON.stringify(object.body)); @@ -112,9 +101,10 @@ describe("JsonRepository Test", () => } }); }; - global.fetch = jest.fn().mockImplementation(responseMock); + global.fetch = vi.fn().mockImplementation(responseMock); - const jsonRepository = new JsonRepository(); - jsonRepository.execute(object); + const responseDTO = await execute(object); + expect(responseDTO.name).toBe("JsonRepository"); + expect(responseDTO.response).toBe("success fetch json"); }); }); \ No newline at end of file diff --git a/src/infrastructure/Request/repository/RequestJsonRepository.ts b/src/infrastructure/Request/repository/RequestJsonRepository.ts new file mode 100644 index 0000000..9c30745 --- /dev/null +++ b/src/infrastructure/Request/repository/RequestJsonRepository.ts @@ -0,0 +1,71 @@ +import type { IRequest } from "../../../interface/IRequest"; +import { cache } from "../../../application/variable/Cache"; +import { ResponseDTO } from "../../Response/dto/ResponseDTO"; +import { execute as callbackService } from "../../../domain/callback/service/CallbackService"; + +/** + * @description 指定先のJSONを非同期で取得 + * Asynchronously obtain JSON of the specified destination + * + * @param {IRequest} request_object + * @return {Promise} + * @method + * @public + */ +export const execute = async (request_object: IRequest): Promise => +{ + if (!request_object.path || !request_object.name) { + throw new Error("`path` and `name` must be set for json requests."); + } + + const name = request_object.name; + + /** + * キャッシュを利用する場合はキャッシュデータをチェック + * Check cache data if cache is used + */ + if (request_object.cache) { + if (cache.size && cache.has(name)) { + + const value: any = cache.get(name); + + if (request_object.callback) { + await callbackService(request_object.callback, value); + } + + return new ResponseDTO(name, value); + } + } + + const options: RequestInit = {}; + + const method = options.method = request_object.method + ? request_object.method.toUpperCase() + : "GET"; + + const body = request_object.body + && method === "POST" || method === "PUT" + ? JSON.stringify(request_object.body) + : null; + + if (body) { + options.body = body; + } + + if (request_object.headers) { + options.headers = request_object.headers; + } + + const response = await fetch(request_object.path, options); + const value = await response.json(); + + if (request_object.cache) { + cache.set(name, value); + } + + if (request_object.callback) { + await callbackService(request_object.callback, value); + } + + return new ResponseDTO(name, value); +}; \ No newline at end of file diff --git a/src/infrastructure/Request/usecase/RequestUseCase.test.ts b/src/infrastructure/Request/usecase/RequestUseCase.test.ts new file mode 100644 index 0000000..ca08d02 --- /dev/null +++ b/src/infrastructure/Request/usecase/RequestUseCase.test.ts @@ -0,0 +1,77 @@ +import { execute } from "./RequestUseCase"; +import { $setPackages, packages } from "../../../application/variable/Packages"; +import { cache } from "../../../application/variable/Cache"; +import { $setConfig } from "../../../application/variable/Config"; +import { describe, expect, it } from "vitest"; +import type { IConfig } from "../../../interface/IConfig"; + +describe("RequestUseCase Test", () => +{ + it("request test", async () => + { + const TestRepository = { + "get": () => { + return "success custom"; + } + }; + + packages.clear(); + packages.set("TestRepository", TestRepository); + + $setPackages(Array.from(packages)); + + cache.clear(); + cache.set("JSONRepository", "success json"); + cache.set("ContentRepository", "success content"); + + // mock + const config: IConfig = { + "platform": "web", + "spa": true, + "stage": { + "width": 240, + "height": 240, + "fps": 12, + "options": {} + }, + "routing": { + "test": { + "requests": [ + { + "type": "custom", + "class": "TestRepository", + "access": "static", + "method": "get", + "name": "TestRepository" + }, + { + "type": "json", + "cache": true, + "name": "JSONRepository", + "path": "sample" + } + ] + } + } + }; + + $setConfig(config); + + const responses = await execute("test"); + expect(responses.length).toBe(2); + + const customResponse = responses[0]; + if (!customResponse) { + throw new Error("stop test"); + } + expect(customResponse.name).toBe("TestRepository"); + expect(customResponse.response).toBe("success custom"); + + const jsonResponse = responses[1]; + if (!jsonResponse) { + throw new Error("stop test"); + } + expect(jsonResponse.name).toBe("JSONRepository"); + expect(jsonResponse.response).toBe("success json"); + }); +}); diff --git a/src/infrastructure/Request/usecase/RequestUseCase.ts b/src/infrastructure/Request/usecase/RequestUseCase.ts new file mode 100644 index 0000000..ddd2978 --- /dev/null +++ b/src/infrastructure/Request/usecase/RequestUseCase.ts @@ -0,0 +1,62 @@ +import type { ResponseDTO } from "../../Response/dto/ResponseDTO"; +import { execute as requestContentRepository } from "../repository/RequestContentRepository"; +import { execute as requestCustomRepository } from "../repository/RequestCustomRepository"; +import { execute as requestJsonRepository } from "../repository/RequestJsonRepository"; +import { execute as configParserRequestsPropertyService } from "../../../application/Config/service/ConfigParserRequestsPropertyService"; + +/** + * @description Routing設定で指定したタイプへリクエストを実行 + * Execute requests to the type specified in Routing settings + * + * @param {string} name + * @return {Promise} + * @method + * @public + */ +export const execute = async (name: string): Promise => +{ + const responses: ResponseDTO[] = []; + const requests = configParserRequestsPropertyService(name); + for (let idx = 0; idx < requests.length; ++idx) { + + const requestObject = requests[idx]; + switch (requestObject.type) { + + case "json": + { + const response = await requestJsonRepository(requestObject); + if (!response) { + continue; + } + responses.push(response); + } + break; + + case "content": + { + const response = await requestContentRepository(requestObject); + if (!response) { + continue; + } + responses.push(response); + } + break; + + case "custom": + { + const response = await requestCustomRepository(requestObject); + if (!response) { + continue; + } + responses.push(response); + } + break; + + default: + break; + + } + } + + return responses; +}; \ No newline at end of file diff --git a/src/infrastructure/dto/ResponseDTO.test.ts b/src/infrastructure/Response/dto/ResponseDTO.test.ts similarity index 77% rename from src/infrastructure/dto/ResponseDTO.test.ts rename to src/infrastructure/Response/dto/ResponseDTO.test.ts index a77fde5..2778376 100644 --- a/src/infrastructure/dto/ResponseDTO.test.ts +++ b/src/infrastructure/Response/dto/ResponseDTO.test.ts @@ -1,15 +1,16 @@ import { ResponseDTO } from "./ResponseDTO"; +import { describe, expect, it } from "vitest"; describe("ResponseDTOTest", () => { - test("execute test case1", () => + it("execute test case1", () => { const responseDTO = new ResponseDTO(); expect(responseDTO.name).toBe(""); expect(responseDTO.response).toBe(null); }); - test("execute test case2", () => + it("execute test case2", () => { const responseDTO = new ResponseDTO("sample", 100); expect(responseDTO.name).toBe("sample"); diff --git a/src/infrastructure/dto/ResponseDTO.ts b/src/infrastructure/Response/dto/ResponseDTO.ts similarity index 61% rename from src/infrastructure/dto/ResponseDTO.ts rename to src/infrastructure/Response/dto/ResponseDTO.ts index e968256..a625e67 100644 --- a/src/infrastructure/dto/ResponseDTO.ts +++ b/src/infrastructure/Response/dto/ResponseDTO.ts @@ -3,36 +3,9 @@ * Converts external data to Objects (DTO), non-variable, disposable class * * @class - * @memberof infrastructure.dto */ export class ResponseDTO { - private readonly _$name: string; - private readonly _$response: any; - - /** - * @param {string} [name=""] - * @param {*} [response=null] - * @constructor - * @public - */ - constructor (name: string = "", response: any = null) - { - /** - * @type {string} - * @default "" - * @private - */ - this._$name = name; - - /** - * @type {*} - * @default null - * @private - */ - this._$response = response; - } - /** * @description キャッシュのキー名 * Key name of cache @@ -42,10 +15,7 @@ export class ResponseDTO * @readonly * @public */ - get name (): string - { - return this._$name; - } + public readonly name: string; /** * @description レスポンスデータ @@ -56,8 +26,17 @@ export class ResponseDTO * @readonly * @public */ - get response (): any | null + public readonly response: any; + + /** + * @param {string} [name=""] + * @param {*} [response=null] + * @constructor + * @public + */ + constructor (name: string = "", response: any = null) { - return this._$response; + this.name = name; + this.response = response; } } \ No newline at end of file diff --git a/__tests__/application/service/RemoveResponseTest.ts b/src/infrastructure/Response/usecase/ResponseRemoveVariableUseCase.test.ts similarity index 72% rename from __tests__/application/service/RemoveResponseTest.ts rename to src/infrastructure/Response/usecase/ResponseRemoveVariableUseCase.test.ts index be0337a..9e5ab40 100644 --- a/__tests__/application/service/RemoveResponseTest.ts +++ b/src/infrastructure/Response/usecase/ResponseRemoveVariableUseCase.test.ts @@ -1,15 +1,13 @@ -import "@next2d/player"; -import { - response, - loaderInfoMap -} from "../../../src"; -import { RemoveResponse } from "../../../src/application/service/RemoveResponse"; -import { RequestType } from "../../../src/infrastructure/constant/RequestType"; -import { $setConfig } from "../../../src/application/variable/Config"; +import { execute } from "./ResponseRemoveVariableUseCase"; +import { loaderInfoMap } from "../../../application/variable/LoaderInfoMap"; +import { $setConfig } from "../../../application/variable/Config"; +import { IConfig } from "../../../interface/IConfig"; +import { response } from "../../Response/variable/Response"; +import { describe, expect, it } from "vitest"; -describe("RemoveResponseTest", () => +describe("ResponseRemoveVariableUseCase", () => { - test("execute test", () => + it("execute test", () => { // mock loaderInfoMap.clear(); @@ -30,8 +28,8 @@ describe("RemoveResponseTest", () => response.clear(); response.set("test1", { - "_$loaderInfo": { - "_$data": { + "loaderInfo": { + "data": { "symbols": symbols } } @@ -40,7 +38,7 @@ describe("RemoveResponseTest", () => expect(response.size).toBe(2); // mock - const config = { + const config: IConfig = { "platform": "web", "spa": true, "stage": { @@ -53,15 +51,15 @@ describe("RemoveResponseTest", () => "test": { "requests": [ { - "type": RequestType.CONTENT, + "type": "content", "name": "test1" }, { - "type": RequestType.JSON, + "type": "json", "name": "test2" }, { - "type": RequestType.CONTENT, + "type": "content", "name": "test3", "cache": true } @@ -73,7 +71,7 @@ describe("RemoveResponseTest", () => $setConfig(config); // execute - new RemoveResponse().execute("test"); + execute("test"); // test expect(response.size).toBe(0); diff --git a/src/infrastructure/Response/usecase/ResponseRemoveVariableUseCase.ts b/src/infrastructure/Response/usecase/ResponseRemoveVariableUseCase.ts new file mode 100644 index 0000000..a37ba69 --- /dev/null +++ b/src/infrastructure/Response/usecase/ResponseRemoveVariableUseCase.ts @@ -0,0 +1,56 @@ +import type { DisplayObject } from "@next2d/display"; +import { execute as configParserRequestsPropertyService } from "../../../application/Config/service/ConfigParserRequestsPropertyService"; +import { loaderInfoMap } from "../../../application/variable/LoaderInfoMap"; +import { response } from "../variable/Response"; + +/** + * @description レスポンスデータを削除、キャッシュ設定があれば削除しない + * Remove response data, do not remove if cache setting is present + * + * @param {string} name + * @return {void} + * @method + * @public + */ +export const execute = (name: string): void => +{ + const requests = configParserRequestsPropertyService(name); + for (let idx = 0; idx < requests.length; ++idx) { + + const object = requests[idx]; + + if (object.type !== "content") { + continue; + } + + if (object.cache + || !object.name + || !response.has(object.name) + ) { + continue; + } + + /** + * キャッシュしないパッケージはインメモリから削除 + * Remove non-cached packages from in-memory + */ + const content = response.get(object.name) as D; + const contentLoaderInfo = content.loaderInfo; + if (contentLoaderInfo && contentLoaderInfo.data) { + const symbols: Map = contentLoaderInfo.data.symbols; + if (symbols.size) { + for (const name of symbols.keys()) { + loaderInfoMap.delete(name); + } + } + } + } + + /** + * レスポンスデータを初期化 + * Initialize response data + */ + if (response.size) { + response.clear(); + } +}; \ No newline at end of file diff --git a/src/application/variable/Response.ts b/src/infrastructure/Response/variable/Response.ts similarity index 50% rename from src/application/variable/Response.ts rename to src/infrastructure/Response/variable/Response.ts index 11056fa..09a4b9b 100644 --- a/src/application/variable/Response.ts +++ b/src/infrastructure/Response/variable/Response.ts @@ -1 +1,5 @@ +/** + * @type {Map} + * @protected + */ export const response: Map = new Map(); \ No newline at end of file diff --git a/src/infrastructure/repository/ContentRepository.ts b/src/infrastructure/repository/ContentRepository.ts deleted file mode 100644 index e4e69fe..0000000 --- a/src/infrastructure/repository/ContentRepository.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { RequestImpl } from "src/interface/RequestImpl"; -import { Loader } from "@next2d/display"; -import { - Event, - IOErrorEvent -} from "@next2d/events"; -import { - URLRequestHeader, - URLRequest -} from "@next2d/net"; - -/** - * @description 指定先のJSONを非同期で取得 - * Asynchronously obtain JSON of the specified destination - * - * @param {object} request_object - * @return {Promise} - * @method - * @public - */ -export const execute = (request_object: RequestImpl): Promise => -{ - return new Promise((resolve, reject) => - { - if (!request_object.path) { - return reject(); - } - - const request: URLRequest = new URLRequest(request_object.path); - - const method: string = request_object.method - ? request_object.method.toUpperCase() - : "GET"; - - switch (method) { - - case "DELETE": - case "GET": - case "HEAD": - case "OPTIONS": - case "POST": - case "PUT": - request.method = method; - break; - - default: - request.method = "GET"; - break; - - } - - if (request_object.headers) { - for (const [name, value] of Object.entries(request_object.headers)) { - request - .requestHeaders - .push(new URLRequestHeader(name, value)); - } - } - - if (request_object.body) { - request.data = JSON.stringify(request_object.body); - } - - const loader: Loader = new Loader(); - loader - .contentLoaderInfo - .addEventListener(Event.COMPLETE, (event: Event) => - { - return resolve(event.currentTarget.content); - }); - - loader - .contentLoaderInfo - .addEventListener(IOErrorEvent.IO_ERROR, reject); - - loader.load(request); - }); -}; \ No newline at end of file diff --git a/src/infrastructure/repository/CustomRepository.ts b/src/infrastructure/repository/CustomRepository.ts deleted file mode 100644 index 88fbc1f..0000000 --- a/src/infrastructure/repository/CustomRepository.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { RequestImpl } from "src/interface/RequestImpl"; -import { packages } from "../../application/variable/Packages"; - -/** - * @description 指定先の外部データを非同期で取得 - * Asynchronous acquisition of external data at specified destination - * - * @param {object} request_object - * @return {Promise} - * @method - * @public - */ -export const execute = (request_object: RequestImpl): Promise => -{ - return new Promise((resolve) => - { - if (!request_object.class - || !request_object.access - || !request_object.method - ) { - return resolve(null); - } - - const name: string = request_object.class; - if (!name || !packages.has(name)) { - return resolve(null); - } - - const CallbackClass: any = packages.get(name); - const promise: Promise = request_object.access === "static" - ? Promise.resolve(CallbackClass[request_object.method]()) - : Promise.resolve(new CallbackClass()[request_object.method]()); - - return promise - .then((value: any) => - { - return resolve(value); - }); - }); -}; \ No newline at end of file diff --git a/src/infrastructure/repository/JsonRepository.ts b/src/infrastructure/repository/JsonRepository.ts deleted file mode 100644 index f6db23d..0000000 --- a/src/infrastructure/repository/JsonRepository.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { RequestImpl } from "src/interface/RequestImpl"; - -/** - * @description 指定先のJSONを非同期で取得 - * Asynchronously obtain JSON of the specified destination - * - * @param {object} request_object - * @return {Promise} - * @method - * @public - */ -export const execute = async (request_object: RequestImpl): Promise => -{ - if (!request_object.path) { - throw new Error("`path` must be set for json requests."); - } - - const options: RequestInit = {}; - - const method: string = options.method = request_object.method - ? request_object.method.toUpperCase() - : "GET"; - - const body: any = request_object.body - && method === "POST" || method === "PUT" - ? JSON.stringify(request_object.body) - : null; - - if (body) { - options.body = body; - } - - if (request_object.headers) { - options.headers = request_object.headers; - } - - const response: Response = await fetch(request_object.path, options); - return await response.json(); -}; \ No newline at end of file diff --git a/src/infrastructure/service/ContentService.ts b/src/infrastructure/service/ContentService.ts deleted file mode 100644 index 2ad895d..0000000 --- a/src/infrastructure/service/ContentService.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { execute as contentRepository } from "../repository/ContentRepository"; -import { execute as callback } from "../../domain/callback/Callback"; -import { ResponseDTO } from "../dto/ResponseDTO"; -import { cache } from "../../application/variable/Cache"; -import { loaderInfoMap } from "../../application/variable/LoaderInfoMap"; -import type { LoaderInfo } from "@next2d/display"; -import type { RequestImpl } from "src/interface/RequestImpl"; - -/** - * @description RepositoryからJSONを取得して、configのcallbackがあれば実行 - * キャッシュ設定がOnの時はJSONをキャッシュにセット - * Get JSON from Repository and run config callback if any. - * If cache setting is On, set JSON to cache. - * - * @param {object} request_object - * @return {Promise} - * @method - * @public - */ -export const execute = async (request_object: RequestImpl): Promise => -{ - if (!request_object.name) { - throw new Error("`name` must be set for content requests."); - } - - /** - * キャッシュを利用する場合はキャッシュデータをチェック - * Check cache data if cache is used - */ - if (request_object.cache) { - - if (cache.size && cache.has(request_object.name)) { - - const value: any = cache.get(request_object.name); - - /** - * コールバック設定があれば実行 - * Execute callback settings if any. - */ - if (request_object.callback) { - const promises: Promise[]|void>[] = []; - promises.push(callback( - request_object.callback, value - )); - - await Promise.all(promises); - } - - return new ResponseDTO(request_object.name, value); - } - } - - /** - * 指定のコンテンツデータを取得 - * Obtain specified content data - */ - const content = await contentRepository(request_object); - - /** - * キャッシュ設定がonならキャッシュに登録 - * If the cache setting is on, register it in the cache. - */ - if (request_object.cache) { - cache.set(request_object.name, content); - } - - /** - * Animation Toolで設定したシンボルをマップに登録 - * Register the symbols set by Animation Tool to the map - */ - const loaderInfo: LoaderInfo = content._$loaderInfo as NonNullable; - if (loaderInfo._$data) { - const symbols: Map = loaderInfo._$data.symbols; - if (symbols.size) { - for (const name of symbols.keys()) { - loaderInfoMap.set(name, loaderInfo); - } - } - } - - /** - * コールバック設定があれば実行 - * Execute callback settings if any. - */ - if (request_object.callback) { - const promises: Promise[]|void>[] = []; - promises.push(callback( - request_object.callback, content - )); - - await Promise.all(promises); - } - - return new ResponseDTO(request_object.name, content); -}; \ No newline at end of file diff --git a/src/infrastructure/service/CustomService.ts b/src/infrastructure/service/CustomService.ts deleted file mode 100644 index 26eefcf..0000000 --- a/src/infrastructure/service/CustomService.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { RequestImpl } from "src/interface/RequestImpl"; -import { ResponseDTO } from "../dto/ResponseDTO"; -import { cache } from "../../application/variable/Cache"; -import { execute as callback } from "../../domain/callback/Callback"; -import { execute as customRepository } from "../repository/CustomRepository"; - -/** - * @description Repositoryから外部データを取得して、configのcallbackがあれば実行 - * キャッシュ設定がOnの時はJSONをキャッシュにセット - * Retrieve external data from Repository and run config callback if any. - * If cache setting is On, set JSON to cache. - * - * @param {object} request_object - * @return {Promise} - * @method - * @public - */ -export const execute = async (request_object: RequestImpl): Promise => -{ - if (!request_object.name) { - throw new Error("`name` must be set for custom requests."); - } - - /** - * キャッシュを利用する場合はキャッシュデータをチェック - * Check cache data if cache is used - */ - if (request_object.cache) { - - if (cache.size && cache.has(request_object.name)) { - - const value: any = cache.get(request_object.name); - - if (request_object.callback) { - const promises: Promise[]|void>[] = []; - promises.push(callback( - request_object.callback, value - )); - - await Promise.all(promises); - } - - return new ResponseDTO(request_object.name, value); - } - } - - const response: any = await customRepository(request_object); - - if (request_object.cache) { - cache.set(request_object.name, response); - } - - if (request_object.callback) { - const promises: Promise[]|void>[] = []; - promises.push(callback( - request_object.callback, response - )); - - await Promise.all(promises); - } - - return new ResponseDTO(request_object.name, response); -}; \ No newline at end of file diff --git a/src/infrastructure/service/JsonService.ts b/src/infrastructure/service/JsonService.ts deleted file mode 100644 index 32f13e5..0000000 --- a/src/infrastructure/service/JsonService.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { execute as jsonRepository } from "../repository/JsonRepository"; -import { execute as callback } from "../../domain/callback/Callback"; -import { ResponseDTO } from "../dto/ResponseDTO"; -import { cache } from "../../application/variable/Cache"; -import { RequestImpl } from "src/interface/RequestImpl"; - -/** - * @description RepositoryからJSONを取得して、configのcallbackがあれば実行 - * キャッシュ設定がOnの時はJSONをキャッシュにセット - * Get JSON from Repository and run config callback if any. - * If cache setting is On, set JSON to cache. - * - * @param {object} request_object - * @return {Promise} - * @method - * @public - */ -export const execute = async (request_object: RequestImpl): Promise => -{ - if (!request_object.name) { - throw new Error("`name` must be set for json requests."); - } - - /** - * キャッシュを利用する場合はキャッシュデータをチェック - * Check cache data if cache is used - */ - if (request_object.cache) { - if (cache.size && cache.has(request_object.name)) { - - const value: any = cache.get(request_object.name); - - if (request_object.callback) { - const promises: Promise[]|void>[] = []; - promises.push(callback( - request_object.callback, value - )); - - await Promise.all(promises); - } - - return new ResponseDTO(request_object.name, value); - } - } - - const response: any = await jsonRepository(request_object); - - if (request_object.cache) { - cache.set(request_object.name, response); - } - - if (request_object.callback) { - const promises: Promise[]|void>[] = []; - promises.push(callback( - request_object.callback, response - )); - - await Promise.all(promises); - } - - return new ResponseDTO(request_object.name, response); -}; \ No newline at end of file diff --git a/src/infrastructure/usecase/RequestUseCase.ts b/src/infrastructure/usecase/RequestUseCase.ts deleted file mode 100644 index f411534..0000000 --- a/src/infrastructure/usecase/RequestUseCase.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { execute as contentService } from "../service/ContentService"; -import { execute as customService } from "../service/CustomService"; -import { execute as jsonService } from "../service/JsonService"; -import { execute as requestParser } from "../../domain/parser/RequestParser"; -import type { ResponseDTO } from "../dto/ResponseDTO"; -import type { RequestImpl } from "src/interface/RequestImpl"; - -/** - * @description Routing設定で指定したタイプへリクエストを実行 - * Execute requests to the type specified in Routing settings - * - * @param {string} name - * @return {Promise} - * @method - * @public - */ -export const execute = (name: string): Promise[] => -{ - const promises: Promise[] = []; - const requests: RequestImpl[] = requestParser(name); - for (let idx: number = 0; idx < requests.length; ++idx) { - - const requestObject: RequestImpl = requests[idx]; - switch (requestObject.type) { - - case "custom": - promises.push(customService(requestObject)); - break; - - case "json": - promises.push(jsonService(requestObject)); - break; - - case "content": - promises.push(contentService(requestObject)); - break; - - default: - break; - } - } - - return promises; -}; \ No newline at end of file diff --git a/src/interface/ConfigImpl.ts b/src/interface/ConfigImpl.ts deleted file mode 100644 index 445d8bc..0000000 --- a/src/interface/ConfigImpl.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { StageImpl } from "./StageImpl"; -import { RoutingImpl } from "./RoutingImpl"; -import { GotoViewImpl } from "./GotoViewImpl"; - -interface BaseConfigImpl { - [key: string]: any -} - -export interface ConfigImpl extends BaseConfigImpl { - platform: string; - stage: StageImpl; - routing?: { - [key: string]: RoutingImpl - }; - defaultTop?: string; - spa: boolean; - loading?: { - callback: string; - }; - gotoView?: GotoViewImpl; -} \ No newline at end of file diff --git a/src/interface/IConfig.ts b/src/interface/IConfig.ts new file mode 100644 index 0000000..72f65a4 --- /dev/null +++ b/src/interface/IConfig.ts @@ -0,0 +1,21 @@ +import type { IStage } from "./IStage"; +import type { IRouting } from "./IRouting"; +import type { IGotoView } from "./IGotoView"; + +interface IBaseConfig { + [key: string]: any +} + +export interface IConfig extends IBaseConfig { + platform: string; + stage: IStage; + spa: boolean; + defaultTop?: string; + gotoView?: IGotoView; + routing?: { + [key: string]: IRouting + }; + loading?: { + callback: string; + }; +} \ No newline at end of file diff --git a/src/interface/IContent.ts b/src/interface/IContent.ts new file mode 100644 index 0000000..2eb415a --- /dev/null +++ b/src/interface/IContent.ts @@ -0,0 +1,6 @@ +import type { MovieClipContent } from "../application/content/MovieClipContent"; +import type { ShapeContent } from "../application/content/ShapeContent"; +import type { TextFieldContent } from "../application/content/TextFieldContent"; +import type { VideoContent } from "../application/content/VideoContent"; + +export type IContent = MovieClipContent | ShapeContent | TextFieldContent | VideoContent; \ No newline at end of file diff --git a/src/interface/GotoViewImpl.ts b/src/interface/IGotoView.ts similarity index 51% rename from src/interface/GotoViewImpl.ts rename to src/interface/IGotoView.ts index ba098af..d94f966 100644 --- a/src/interface/GotoViewImpl.ts +++ b/src/interface/IGotoView.ts @@ -1,3 +1,3 @@ -export interface GotoViewImpl { +export interface IGotoView { callback: string | string[]; } \ No newline at end of file diff --git a/src/interface/LoadingImpl.ts b/src/interface/ILoading.ts similarity index 56% rename from src/interface/LoadingImpl.ts rename to src/interface/ILoading.ts index 12a8926..5227f28 100644 --- a/src/interface/LoadingImpl.ts +++ b/src/interface/ILoading.ts @@ -1,4 +1,4 @@ -export interface LoadingImpl { +export interface ILoading { start: Function; end: Function; } \ No newline at end of file diff --git a/src/interface/OptionsImpl.ts b/src/interface/IOptions.ts similarity index 73% rename from src/interface/OptionsImpl.ts rename to src/interface/IOptions.ts index efbeda2..0278b5c 100644 --- a/src/interface/OptionsImpl.ts +++ b/src/interface/IOptions.ts @@ -1,4 +1,4 @@ -export interface OptionsImpl { +export interface IOptions { base?: string; fullScreen?: boolean; tagId?: string; diff --git a/src/interface/IPackages.ts b/src/interface/IPackages.ts new file mode 100644 index 0000000..75153ce --- /dev/null +++ b/src/interface/IPackages.ts @@ -0,0 +1 @@ +export type IPackages = Array> \ No newline at end of file diff --git a/src/interface/QueryObjectImpl.ts b/src/interface/IQueryObject.ts similarity index 55% rename from src/interface/QueryObjectImpl.ts rename to src/interface/IQueryObject.ts index 00d3021..836ed90 100644 --- a/src/interface/QueryObjectImpl.ts +++ b/src/interface/IQueryObject.ts @@ -1,4 +1,4 @@ -export interface QueryObjectImpl { +export interface IQueryObject { name: string; queryString: string; } \ No newline at end of file diff --git a/src/interface/RequestImpl.ts b/src/interface/IRequest.ts similarity index 58% rename from src/interface/RequestImpl.ts rename to src/interface/IRequest.ts index 9b5c80b..44cedd3 100644 --- a/src/interface/RequestImpl.ts +++ b/src/interface/IRequest.ts @@ -1,7 +1,7 @@ -import { RequestTypeImpl } from "./RequestTypeImpl"; +import type { IRequestType } from "./IRequestType"; -export interface RequestImpl { - type: RequestTypeImpl; +export interface IRequest { + type: IRequestType; path?: string; name?: string; cache?: boolean; @@ -10,5 +10,5 @@ export interface RequestImpl { access?: string; method?: string; headers?: HeadersInit; - body?: object; + body?: any; } \ No newline at end of file diff --git a/src/interface/IRequestType.ts b/src/interface/IRequestType.ts new file mode 100644 index 0000000..936eecb --- /dev/null +++ b/src/interface/IRequestType.ts @@ -0,0 +1 @@ +export type IRequestType = "json" | "content" | "custom" | "cluster"; \ No newline at end of file diff --git a/src/interface/IRouting.ts b/src/interface/IRouting.ts new file mode 100644 index 0000000..24bce51 --- /dev/null +++ b/src/interface/IRouting.ts @@ -0,0 +1,7 @@ +import type { IRequest } from "./IRequest"; + +export interface IRouting { + private?: boolean; + requests?: IRequest[]; + redirect?: string; +} \ No newline at end of file diff --git a/src/interface/IStage.ts b/src/interface/IStage.ts new file mode 100644 index 0000000..4215be4 --- /dev/null +++ b/src/interface/IStage.ts @@ -0,0 +1,8 @@ +import type { IOptions } from "./IOptions"; + +export interface IStage { + width: number; + height: number; + fps: number; + options?: IOptions; +} \ No newline at end of file diff --git a/src/interface/RequestTypeImpl.ts b/src/interface/RequestTypeImpl.ts deleted file mode 100644 index 2024ee9..0000000 --- a/src/interface/RequestTypeImpl.ts +++ /dev/null @@ -1 +0,0 @@ -export type RequestTypeImpl = "json" | "content" | "custom" | "cluster"; \ No newline at end of file diff --git a/src/interface/RoutingImpl.ts b/src/interface/RoutingImpl.ts deleted file mode 100644 index 4e6b886..0000000 --- a/src/interface/RoutingImpl.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { RequestImpl } from "./RequestImpl"; - -export interface RoutingImpl { - private?: boolean; - requests?: RequestImpl[]; - redirect?: string; -} \ No newline at end of file diff --git a/src/interface/StageImpl.ts b/src/interface/StageImpl.ts deleted file mode 100644 index fd552e4..0000000 --- a/src/interface/StageImpl.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { OptionsImpl } from "./OptionsImpl"; - -export interface StageImpl { - width: number; - height: number; - fps: number; - options?: OptionsImpl; -} \ No newline at end of file diff --git a/src/view/View.test.ts b/src/view/View.test.ts new file mode 100644 index 0000000..a6dc762 --- /dev/null +++ b/src/view/View.test.ts @@ -0,0 +1,10 @@ +import { View } from "./View"; +import { describe, expect, it } from "vitest"; + +describe("View Test", () => +{ + it("initialize call test", () => { + const view = new View(); + expect(typeof view.initialize).toBe("function"); + }); +}); \ No newline at end of file diff --git a/src/view/View.ts b/src/view/View.ts index 2197ef2..ca1cbc1 100644 --- a/src/view/View.ts +++ b/src/view/View.ts @@ -1,14 +1,13 @@ -import { MovieClip } from "@next2d/display"; +import { Sprite } from "@next2d/display"; /** - * Viewの親クラス、抽象クラスとして存在しています。 - * It exists as a parent class of View and as an abstract class. + * @description Viewの親クラス、抽象クラスとして存在しています。 + * It exists as a parent class of View and as an abstract class. * * @class - * @memberof view * @extends {MovieClip} */ -export class View extends MovieClip +export class View extends Sprite { /** * @constructor diff --git a/src/view/ViewModel.test.ts b/src/view/ViewModel.test.ts new file mode 100644 index 0000000..6a4a130 --- /dev/null +++ b/src/view/ViewModel.test.ts @@ -0,0 +1,20 @@ +import { View } from "./View"; +import { ViewModel } from "./ViewModel"; +import { describe, expect, it } from "vitest"; + +describe("ViewModel Test", () => +{ + it("bind call test", async () => + { + const view = new View(); + const viewModel = new ViewModel(); + expect(await viewModel.bind(view)).toBe(undefined); + }); + + it("unbind call test", async () => + { + const view = new View(); + const viewModel = new ViewModel(); + expect(await viewModel.unbind(view)).toBe(view); + }); +}); \ No newline at end of file diff --git a/src/view/ViewModel.ts b/src/view/ViewModel.ts index 78996a6..e63e51e 100644 --- a/src/view/ViewModel.ts +++ b/src/view/ViewModel.ts @@ -1,11 +1,10 @@ import type { View } from "./View"; /** - * ViewModelの親クラス、抽象クラスとして存在しています。 - * It exists as a parent class of ViewModel and as an abstract class. + * @description ViewModelの親クラス、抽象クラスとして存在しています。 + * It exists as a parent class of ViewModel and as an abstract class. * * @class - * @memberof view */ export class ViewModel { @@ -14,45 +13,25 @@ export class ViewModel * Called at the timing when the root Sprite is attached. * * @param {View} view - * @return {Promise} + * @return {Promise} * @method * @abstract */ - bind (view: View): Promise - { - return this.factory(view); - } + // @ts-ignore + // eslint-disable-next-line unused-imports/no-unused-vars + async bind (view: View): Promise { return void 0 } /** * @description 新しいViewクラスがアタッチされる前にコールされます。 * Called before a new View class is attached. * * @param {View} view - * @return {void} - * @method - * @public - */ - // @ts-ignore - // eslint-disable-next-line no-unused-vars,no-empty-function - unbind (view: View): void {} - - /** - * @description bind関数で非同期で処理を開始する共通関数です。 - * Common function to start processing asynchronously with bind functions. - * - * @param {View} view * @return {Promise} * @method - * @public + * @abstract */ - factory (view: View): Promise + async unbind (view: View): Promise { - return new Promise((resolve) => - { - requestAnimationFrame((): void => - { - return resolve(view); - }); - }); + return view; } -} +} \ No newline at end of file diff --git a/test.setup.ts b/test.setup.ts new file mode 100644 index 0000000..7298aa0 --- /dev/null +++ b/test.setup.ts @@ -0,0 +1,32 @@ +// test/global-setup.ts +class MockOffscreenCanvas { + width: number; + height: number; + + constructor (width: number, height: number) + { + this.width = width; + this.height = height; + } + + getContext () { + // CanvasRenderingContext2D などをモック + return { + // 必要に応じてメソッドを追加 + "fillRect": (x: number, y: number, w: number, h: number) => {}, + "transferControlToOffscreen": () => { + return {}; + } + }; + } +} + +if (typeof globalThis.OffscreenCanvas === "undefined") { + (globalThis as any).OffscreenCanvas = MockOffscreenCanvas; +} + +if (!HTMLCanvasElement.prototype.transferControlToOffscreen) { + HTMLCanvasElement.prototype.transferControlToOffscreen = function () { + return this; + }; +} \ No newline at end of file diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json deleted file mode 100644 index 16a9068..0000000 --- a/tsconfig.eslint.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [ - "src/**/*.ts", - ".eslintrc.js" - ], - "exclude": [ - "node_modules", - "src/**/*.test.ts", - "dist" - ] -} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 25304a3..36f1234 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ESNext", + "target": "ES2020", "useDefineForClassFields": true, "module": "ESNext", "lib": ["ES2020", "DOM", "DOM.Iterable"], @@ -9,6 +9,9 @@ /* Bundler mode */ "moduleResolution": "Bundler", "resolveJsonModule": true, + "strictFunctionTypes": false, + "esModuleInterop": true, + "declaration": true, "isolatedModules": true, /* Linting */ @@ -17,9 +20,8 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, - "declaration": true, "baseUrl": ".", - "outDir": "./dist", + "outDir": "./dist/src", "types": [ "vitest/globals" @@ -31,6 +33,10 @@ ], "exclude": [ "node_modules", - "src/**/*.test.ts" + "**/dist/**", + "scripts", + "dist", + "src/**/*.test.ts", + ".github", ] } \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 6d71f23..27cd40f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,11 +1,18 @@ /// +/// +/// -import { defineConfig } from "vite"; +import { defineConfig } from "vitest/config"; export default defineConfig({ "test": { "globals": true, "environment": "jsdom", + "setupFiles": [ + "test.setup.ts", + "@vitest/web-worker", + "vitest-webgl-canvas-mock" + ], "include": ["src/**/*.test.ts"] } }); \ No newline at end of file