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 @@ -
Request
Request
User
User
[Source] src/App.js
[Function] gotoView({Path})
[Source] src/App.js...
YES
YES
NO
NO
use loading
(Default value is true)
use loading...
[Source] config.loading.{ClassName}
[Function] start
[Source] config.loading.{ClassName}...
JSON
Get external JSON data
JSON...
CONTENT
Get JSON data exported by NoCodeTool
CONTENT...
CUSTOM
Requests to external APIs
CUSTOM...
YES
YES
NO
NO
use cache
(Default value is false)
use cache...
cache
cache
Global
Global
NO
NO
Cached
Cached
[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...
YES
YES
NO
NO
use callback
(Default value is empty)
use callback...
[Source] config.loading.{ClassName}
[Function] start
[Source] config.loading.{ClassName}...
YES
YES
NO
NO
use loading
(Default value is true)
use loading...
[Source] config.loading.{ClassName}
[Function] end
[Source] config.loading.{ClassName}...
Response
Response
Start drawing
Start drawing
YES
YES
Remove 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 +
Request
User
[Source] src/App.js
[Function] gotoView({Path})
YES
NO
use loading
(Default value is true)
[Source] config.loading.{ClassName}
[Function] start
JSON
Get external JSON data
CONTENT
Get JSON data exported by Animation Tool
CUSTOM
Requests to external APIs
YES
NO
use cache
(Default value is false)
cache
Global
NO
Cached
[Source] src/view/{Path}View.js
[Function] initialize
[Source] src/view/{Path}ViewModel.js
[Function] bind
[Source] src/view/{PrevPath}ViewModel.js
[Function] unbind
YES
NO
use callback
(Default value is empty)
[Source] config.loading.{ClassName}
[Function] start
YES
NO
use loading
(Default value is true)
[Source] config.loading.{ClassName}
[Function] end
Response
Start drawing
YES
Remove 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