diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 3cd5493..bc66554 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,7 +1,7 @@
# These are supported funding model platforms
github: [Next2D]
-patreon: next2d
+patreon: # next2d
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index fb4d2a5..6285f6b 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -13,12 +13,12 @@ name: "CodeQL"
on:
push:
- branches: [ main, develop ]
+ branches: [ "main", "develop" ]
pull_request:
# The branches below must be a subset of the branches above
- branches: [ main, develop ]
+ branches: [ "main", "develop" ]
schedule:
- - cron: '38 23 * * 1'
+ - cron: '44 22 * * 5'
jobs:
analyze:
@@ -32,10 +32,11 @@ jobs:
strategy:
fail-fast: false
matrix:
- language: [ 'javascript' ]
- # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
- # Learn more:
- # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+ language: [ 'javascript-typescript' ]
+ # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ]
+ # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both
+ # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+ # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
diff --git a/.gitignore b/.gitignore
index 8fea6bf..54f07af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,24 @@
-.DS_Store
-.idea
-.nvmrc
-Thumbs.db
-coverage
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
node_modules
-Footer.build.file
-Header.build.file
-next2d-framework.js
-package-lock.json
-dist
\ No newline at end of file
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
index 80b7c10..8ece253 100644
--- a/.npmignore
+++ b/.npmignore
@@ -5,10 +5,8 @@
.github
node_modules
__tests__
-coverage
src
Framework_Flowchart.svg
-babel.config.js
-jest.config.js
-jest.setup.js
-webpack.config.js
\ No newline at end of file
+tsconfig.eslint.json
+tsconfig.json
+vite.config.ts
\ No newline at end of file
diff --git a/DOCS.md b/DOCS.md
deleted file mode 100644
index ea6f74c..0000000
--- a/DOCS.md
+++ /dev/null
@@ -1,144 +0,0 @@
-#### Quick Start
-
-${{ framework-api.detail }}$
-
-```sh
-npx create-next2d-app app-name
-cd app-name
-npm start
-```
-
-#### ${{ framework-api.dir-detail }}$
-
-```sh
-project
-├── src
-│ ├── index.js
-│ ├── App.js
-│ ├── Packages.js // It will be generated automatically.
-│ │
-│ ├── component
-│ │ └── default empty
-│ │
-│ ├── config
-│ │ ├── config.json // Configuration files for each environment.
-│ │ ├── routing.json // Request settings before loading the view.
-│ │ ├── stage.json // Display(Stage) area setting.
-│ │ └── Config.js // It will be generated automatically.
-│ │
-│ ├── content // Symbolic access to JSON created with NoCode Tool
-│ │ ├── TopContent.js
-│ │ └── HomeContent.js
-│ │
-│ ├── image
-│ │ └── default empty
-│ │
-│ ├── model // business logic
-│ │ ├── api
-│ │ │ └── HomeText.js
-│ │ └── callback
-│ │ └── Background.js
-│ │
-│ └── view // Per-page View, ViewModel files.
-│ ├── top
-│ │ ├── TopView.js
-│ │ └── TopViewModel.js
-│ └── home
-│ ├── HomeView.js
-│ └── HomeViewModel.js
-│
-└── __tests__ // Unit Test directory
- └── model
- └── default empty
-```
-
-#### ${{ framework-api.chart-detail }}$
-
-
-#### ${{ framework-api.command.title }}$
-
-* ${{ framework-api.command.text1 }}$
-```sh
-npm start
-```
-
-* ${{ framework-api.command.text2 }}$
-```sh
-npm run generate
-```
-
-* ${{ framework-api.command.text3 }}$
-```sh
-npm run build -- --env="prd"
-```
-
-* ${{ framework-api.command.text4 }}$
-```sh
-npm test
-```
-
-### ${{ framework-api.conf-detail }}$
-
-#### stage.json
-
-| ${{ player-api.options.th1 }}$ | ${{ player-api.options.th2 }}$ | ${{ player-api.options.th3 }}$ | ${{ player-api.options.th4 }}$ |
-| --- | --- | --- | --- |
-| `width` | number | 240 | ${{ framework-api.stage.text1 }}$ |
-| `height` | number | 240 | ${{ framework-api.stage.text2 }}$ |
-| `fps` | number | 12 |${{ framework-api.stage.text3 }}$ |
-
-##### Option settings
-
-| ${{ player-api.options.th1 }}$ | ${{ player-api.options.th2 }}$ | ${{ player-api.options.th3 }}$ | ${{ player-api.options.th4 }}$ |
-| --- | --- | --- | --- |
-| `base` | string | empty | ${{ player-api.options.text1 }}$ |
-| `fullScreen` | boolean | false | ${{ player-api.options.text2 }}$ |
-| `tagId` | string | null | ${{ player-api.options.text3 }}$ |
-| `bgColor` | array | null | ${{ player-api.options.text4 }}$ |
-
-#### config.json
-
-| ${{ framework-api.config.detail }}$
-
-| ${{ player-api.options.th1 }}$ | ${{ player-api.options.th2 }}$ | ${{ player-api.options.th3 }}$ | ${{ player-api.options.th4 }}$ |
-| --- | --- | --- | --- |
-| `spa` | boolean | true | ${{ framework-api.config.text1 }}$ |
-| `loading`.`callback` | string | Loading | ${{ framework-api.config.text2 }}$ |
-| `gotoView`.`callback` | string or array | ["callback.Background"] | ${{ framework-api.config.text3 }}$ |
-
-#### routing.json
-
-${{ framework-api.routing.detail }}$
-
-##### Example
-
-${{ framework-api.routing.example }}$
-
-```json
-{
- "quest/list": {
- "requests": []
- }
-}
-````
-
-#### ${{ framework-api.routing.detail2 }}$
-
-| ${{ player-api.options.th1 }}$ | ${{ player-api.options.th2 }}$ | ${{ player-api.options.th3 }}$ | ${{ player-api.options.th4 }}$ |
-| --- | --- | --- | --- |
-| `private` | boolean | false | ${{ framework-api.routing.text1 }}$ |
-| `redirect` | string | empty | ${{ framework-api.routing.text2 }}$ |
-| `requests` | array | null | ${{ framework-api.routing.text3 }}$ |
-
-#### ${{ framework-api.routing.detail3 }}$
-
-| ${{ player-api.options.th1 }}$ | ${{ player-api.options.th2 }}$ | ${{ player-api.options.th3 }}$ | ${{ player-api.options.th4 }}$ |
-| --- | --- | --- | --- |
-| `type` | string | `content` | ${{ framework-api.routing.text4 }}$ |
-| `path` | string | empty | ${{ framework-api.routing.text5 }}$ |
-| `name` | string | empty | ${{ framework-api.routing.text6 }}$ |
-| `cache` | boolean | false | ${{ framework-api.routing.text7 }}$ |
-| `callback` | string or array | null | ${{ framework-api.routing.text8 }}$ |
-| `class` | string | empty | ${{ framework-api.routing.text9 }}$ |
-| `access` | string | `public` | ${{ framework-api.routing.text10 }}$ |
-| `method` | string | empty | ${{ framework-api.routing.text11 }}$ |
diff --git a/LICENSE b/LICENSE
index a536abe..d520559 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2021 Next2D
+Copyright (c) 2021 - 2023 Next2D
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/babel.config.js b/babel.config.js
deleted file mode 100644
index 72bf3f7..0000000
--- a/babel.config.js
+++ /dev/null
@@ -1,15 +0,0 @@
-module.exports = {
- "presets": [
- [
- "@babel/preset-env",
- {
- "targets": {
- "node": "current"
- }
- }
- ]
- ],
- "plugins": [
- "@babel/plugin-transform-modules-commonjs"
- ]
-};
\ No newline at end of file
diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index 9f4a611..0000000
--- a/jest.config.js
+++ /dev/null
@@ -1,15 +0,0 @@
-module.exports = {
- "preset": "ts-jest",
- "setupFilesAfterEnv": ["./jest.setup.js"],
- "moduleNameMapper": {
- "^\\@/(.+)": "/src/$1"
- },
- "transformIgnorePatterns": [
- "/node_modules/(?!(next2d|@next2d))"
- ],
- "transform": {
- "\\.jsx?$": "babel-jest",
- "^.+\\.(ts|tsx)$": "ts-jest"
- },
- "testEnvironment": "node"
-};
diff --git a/jest.setup.js b/jest.setup.js
deleted file mode 100644
index 34a5181..0000000
--- a/jest.setup.js
+++ /dev/null
@@ -1,487 +0,0 @@
-globalThis.$windowEventMap = new Map();
-globalThis.OffscreenCanvas = class OffscreenCanvas
-{
- getContext ()
- {
- return {};
- }
-};
-
-globalThis.cancelAnimationFrame = () =>
-{
- return undefined;
-};
-
-const xhrMockClass = () => ({
- "open" : jest.fn(),
- "send" : jest.fn(),
- "setRequestHeader": jest.fn(),
- "addEventListener": jest.fn()
-});
-
-globalThis.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass);
-
-globalThis.window = {
- "document": {
- "createElement": () =>
- {
- const attribute = new Map();
- return {
- "getAttribute": (name) =>
- {
- return attribute.has(name)
- ? attribute.get(name)
- : null;
- },
- "setAttribute": (name, value) =>
- {
- attribute.set(name, value);
- },
- "insertBefore": (element) =>
- {
- if (element.id) {
- globalThis.$elements.set(element.id, element);
- }
- },
- "getContext": () => {
- return {
- "measureText": () => {
- return {
- "width": 0
- };
- }
- };
- },
- "style": {},
- "children": []
- };
- }
- },
- "devicePixelRatio": 2,
- "OffscreenCanvas": () =>
- {
- return undefined;
- },
- "addEventListener": (type, callback) =>
- {
- globalThis.$windowEventMap.set(type, callback);
- },
- "next2d": {
- "createRootMovieClip": () => {
- return Promise.resolve();
- },
- "display": {
- "MovieClip": class MovieClip
- {
- constructor()
- {
- this.name = "";
- this.namespace = "next2d.display.MovieClip";
- }
-
- _$sync ()
- {
- return undefined;
- }
-
- _$getChildren ()
- {
- return undefined;
- }
- },
- "Loader": class Loader
- {
- constructor ()
- {
- this.event = new Map();
- }
-
- get contentLoaderInfo ()
- {
- return {
- "addEventListener": (name, callback) =>
- {
- this.event.set(name, callback);
- }
- };
- }
-
- loadImage ()
- {
- this.event.get("complete")({
- "currentTarget": {
- "content": {
- "_$loaderInfo": {
- "_$data": {
- "symbols": new Map([["app", "app"]])
- }
- },
- "text": "NoCode Tool image content"
- }
- }
- });
- }
-
- load ()
- {
- this.event.get("complete")({
- "currentTarget": {
- "content": {
- "_$loaderInfo": {
- "_$data": {
- "symbols": new Map([["app", "app"]])
- }
- },
- "text": "NoCode Tool content"
- }
- }
- });
- }
- },
- "Shape": class Shape
- {
- get graphics ()
- {
- return this;
- }
-
- beginBitmapFill ()
- {
- return this;
- }
-
- beginFill ()
- {
- return this;
- }
-
- drawRect ()
- {
- return this;
- }
-
- endFill ()
- {
- return this;
- }
- },
- "BitmapData": class BitmapData
- {
- draw (source, matrix, color_transform, canvas = {}, callback)
- {
- callback(canvas);
- }
- },
- "Sprite": class Sprite
- {
- addChild (display_object)
- {
- return display_object;
- }
-
- get graphics ()
- {
- return this;
- }
-
- beginFill ()
- {
- return this;
- }
-
- drawRect ()
- {
- return this;
- }
-
- endFill ()
- {
- return this;
- }
- }
- },
- "player": {
- "x": 0,
- "y": 0,
- "scaleX": 1,
- "scaleY": 1
- }
- }
-};
-
-globalThis.next2d = {
- "createRootMovieClip": function ()
- {
- const object = {
- "_$created": true,
- "_$createWorkerInstance": () =>
- {
- return undefined;
- },
- "stage": {
- "canvasWidth": 100,
- "canvasHeight": 100,
- "_$player": {
- "_$matrix": [1,0,0,1,10,10]
- }
- },
- "addChild": (child) =>
- {
- return child;
- },
- "numChildren": 1,
- "removeChild": (number) =>
- {
- object.numChildren = number;
- },
- "getChildAt": () =>
- {
- return 0;
- }
- };
-
- return object;
- },
- "display": {
- "MovieClip": class MovieClip
- {
- constructor()
- {
- this.name = "";
- this.namespace = "next2d.display.MovieClip";
- }
-
- _$sync ()
- {
- return undefined;
- }
-
- _$getChildren ()
- {
- return undefined;
- }
- },
- "Loader": class Loader
- {
- constructor ()
- {
- this.event = new Map();
- }
-
- get contentLoaderInfo ()
- {
- return {
- "addEventListener": (name, callback) =>
- {
- this.event.set(name, callback);
- }
- };
- }
-
- loadImage ()
- {
- this.event.get("complete")({
- "currentTarget": {
- "content": {
- "_$loaderInfo": {
- "_$data": {
- "symbols": new Map([["app", "app"]])
- }
- },
- "text": "NoCode Tool image content"
- }
- }
- });
- }
-
- load ()
- {
- this.event.get("complete")({
- "currentTarget": {
- "content": {
- "_$loaderInfo": {
- "_$data": {
- "symbols": new Map([["app", "app"]])
- }
- },
- "text": "NoCode Tool content"
- }
- }
- });
- }
- },
- "Shape": class Shape
- {
- get graphics ()
- {
- return this;
- }
-
- beginBitmapFill ()
- {
- return this;
- }
-
- beginFill ()
- {
- return this;
- }
-
- drawRect ()
- {
- return this;
- }
-
- endFill ()
- {
- return this;
- }
- },
- "BitmapData": class BitmapData
- {
- draw (source, matrix, color_transform, canvas = {}, callback)
- {
- callback(canvas);
- }
- },
- "Sprite": class Sprite
- {
- addChild (display_object)
- {
- return display_object;
- }
-
- get graphics ()
- {
- return this;
- }
-
- beginFill ()
- {
- return this;
- }
-
- drawRect ()
- {
- return this;
- }
-
- endFill ()
- {
- return this;
- }
- }
- },
- "geom": {
- "Matrix": class Matrix
- {
-
- }
- },
- "events": {
- "Event": class Event {
- static get COMPLETE ()
- {
- return "complete";
- }
- static get REMOVED ()
- {
- return "removed";
- }
- },
- "IOErrorEvent": class IOErrorEvent
- {
- static get IO_ERROR () {
- return "io_error";
- }
- }
- },
- "net": {
- "URLRequest": class URLRequest
- {
- constructor()
- {
- this.method = "GET";
- this.requestHeaders = [];
- this.data = null;
- }
- },
- "URLRequestHeader": class URLRequestHeader
- {
- constructor (name, value)
- {
- this.name = name;
- this.value = value;
- }
- },
- "URLRequestMethod": {
- "GET": "GET",
- "PUT": "PUT",
- "POST": "POST"
- }
- },
- "fw": {
- "loaderInfo": new Map(),
- "application": "app",
- "cache": new Map([["cache", "cache"]]),
- "config": {
- "stage": {
- "width": 240,
- "height": 240,
- "fps": 12,
- "options": {}
- }
- },
- "context": "context",
- "packages": new Map([["class", "class"]]),
- "response": new Map([["response", "response"]]),
- "variable": new Map([["variable", "variable"]]),
- "query": new Map([["query", "query"]])
- }
-};
-
-globalThis.location = {
- "pathname": "/"
-};
-
-globalThis.history = {
- "pushState": () => {}
-};
-
-globalThis.$elements = new Map();
-globalThis.document = {
- "getElementById": (id) =>
- {
- return globalThis.$elements.has(id)
- ? globalThis.$elements.get(id)
- : null;
- },
- "createElement": () =>
- {
- const attribute = new Map();
- return {
- "getAttribute": (name) =>
- {
- return attribute.has(name)
- ? attribute.get(name)
- : null;
- },
- "setAttribute": (name, value) =>
- {
- attribute.set(name, value);
- },
- "insertBefore": (element) =>
- {
- if (element.id) {
- globalThis.$elements.set(element.id, element);
- }
- },
- "children": []
- };
- }
-};
-
-globalThis.requestAnimationFrame = (callback) =>
-{
- return callback();
-};
\ No newline at end of file
diff --git a/jsdoc.conf.js b/jsdoc.conf.js
deleted file mode 100644
index 086d3b3..0000000
--- a/jsdoc.conf.js
+++ /dev/null
@@ -1,40 +0,0 @@
-"use strict";
-
-module.exports = {
- "plugins": [
- "plugins/markdown"
- ],
- "markdown": {
- "hardwrap": true
- },
- "templates": {
- "cleverLinks" : false,
- "monospaceLinks": false,
- "applicationName": "Next2D Framework",
- "path": "../../../",
- "openGraph": {
- "title": "Framework API Documentation",
- "description": "Framework API Documentation.",
- "type": "website",
- "image": "https://next2d.app/assets/img/ogp.png",
- "url": "https://next2d.app/"
- },
- "meta": {
- "title": "Framework API Documentation",
- "description": "Next2D Framework API Documentation.",
- "keyword": "Next2D, WebGL, JavaScript, HTML5, MVVM, DDD, CleanArchitecture"
- },
- "linenums": true,
- "default" : {
- "outputSourceFiles" : true
- }
- },
- "opts": {
- "encoding": "utf8",
- "recurse": true,
- "private": false,
- "lenient": true,
- "destination": "../next2d/dist/docs/framework/",
- "template": "node_modules/@next2d/jsdoc-template"
- }
-};
diff --git a/package.json b/package.json
index 24db33a..c9cce14 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,14 @@
{
"name": "@next2d/framework",
- "description": "It is a framework dedicated to Next2D that enables scene management by URL (SPA), which has been difficult with conventional Canvas/WebGL applications, and simplifies readability and shareability by fixing the development pattern (MVVM).",
- "version": "1.6.2",
+ "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.0",
"homepage": "https://next2d.app",
"bugs": "https://github.com/Next2D/Framework/issues/new",
- "author": "Toshiyuki Ienaga (https://github.com/ienaga/)",
+ "author": "Toshiyuki Ienaga (https://github.com/ienaga/)",
"license": "MIT",
"main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "type": "module",
"keywords": [
"Next2D",
"Next2D Framework"
@@ -14,10 +16,8 @@
"scripts": {
"lint": "eslint src/**/*.ts",
"publish": "node ./scripts/version.js && tsc",
- "test": "jest",
- "jsdoc": "tsc && jsdoc -c jsdoc.conf.js -r dist DOCS.md"
+ "test": "npx vitest"
},
- "types": "dist",
"files": [
"dist"
],
@@ -25,26 +25,14 @@
"type": "git",
"url": "git+https://github.com/Next2D/Framework.git"
},
- "dependencies": {
- "@next2d/player": "*"
- },
"devDependencies": {
- "@babel/core": "^7.22.5",
- "@babel/plugin-transform-modules-commonjs": "^7.22.5",
- "@babel/preset-env": "^7.22.5",
- "@next2d/jsdoc-template": "^1.0.7",
- "@types/jest": "^29.5.2",
- "@typescript-eslint/eslint-plugin": "^5.60.0",
- "@typescript-eslint/parser": "^5.60.0",
- "eslint": "^8.43.0",
- "eslint-webpack-plugin": "^4.0.1",
- "jest": "^29.5.0",
- "jsdoc": "^4.0.2",
- "ts-jest": "^29.1.0",
- "ts-loader": "^9.4.3",
- "ts-node": "^10.9.1",
- "typescript": "^5.1.3",
- "webpack": "^5.88.0",
- "webpack-cli": "^5.1.4"
+ "@next2d/player": "*",
+ "@typescript-eslint/eslint-plugin": "^6.9.1",
+ "@typescript-eslint/parser": "^6.9.1",
+ "eslint": "^8.53.0",
+ "jsdom": "^22.1.0",
+ "typescript": "^5.2.2",
+ "vite": "^4.5.0",
+ "vitest": "^0.34.6"
}
}
diff --git a/scripts/version.js b/scripts/version.js
index 287a9dd..828391e 100644
--- a/scripts/version.js
+++ b/scripts/version.js
@@ -2,7 +2,7 @@
"use strict";
-const fs = require("fs");
+import * as fs from "fs";
/**
* @param {string} dir
@@ -16,7 +16,9 @@ const execute = () =>
if (fs.existsSync(indexPath)) {
const src = fs.readFileSync(indexPath, "utf8");
- const packageJson = require(`${process.cwd()}/package.json`);
+ const packageJson = JSON.parse(
+ fs.readFileSync(`${process.cwd()}/package.json`, { "encoding": "utf8" })
+ );
const texts = src.split("\n");
for (let idx = 0; idx < texts.length; ++idx) {
diff --git a/src/application/Application.ts b/src/application/Application.ts
index 71f7b5b..b9f3d66 100644
--- a/src/application/Application.ts
+++ b/src/application/Application.ts
@@ -1,21 +1,29 @@
-import { QueryParser } from "../domain/parser/QueryParser";
-import { RequestUseCase } from "../infrastructure/usecase/RequestUseCase";
-import { Callback } from "../domain/callback/Callback";
-import { Loading } from "../domain/loading/Loading";
-import { Capture } from "../domain/screen/Capture";
-import { RemoveResponse } from "./service/RemoveResponse";
-import { $setPackages } from "./variable/Packages";
-import { config, $setConfig } from "./variable/Config";
-import { context, $createContext } from "./variable/Context";
-import { response } from "./variable/Response";
import type { ResponseDTO } from "../infrastructure/dto/ResponseDTO";
import type { View } from "../view/View";
import type { ConfigImpl } from "../interface/ConfigImpl";
-
-interface QueryObject {
- name: string;
- queryString: string;
-}
+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";
/**
* シーン遷移のコントロールを行うクラス。
@@ -26,12 +34,6 @@ interface QueryObject {
*/
export class Application
{
- private readonly _$queryParser: QueryParser;
- private readonly _$requestUseCase: RequestUseCase;
- private readonly _$callback: Callback;
- private readonly _$loading: Loading;
- private readonly _$capture: Capture;
- private readonly _$removeResponse: RemoveResponse;
private _$popstate: boolean;
private _$currentName: string;
@@ -39,72 +41,49 @@ export class Application
* @constructor
* @public
*/
- constructor (config: ConfigImpl, packages: any[])
+ constructor ()
{
- $setConfig(config);
- $setPackages(packages);
-
/**
- * @type {QueryParser}
- * @private
- */
- this._$queryParser = new QueryParser();
-
- /**
- * @type {RequestUseCase}
- * @private
- */
- this._$requestUseCase = new RequestUseCase();
-
- /**
- * @type {Callback}
- * @private
- */
- this._$callback = new Callback();
-
- /**
- * @type {Loading}
- * @private
- */
- this._$loading = new Loading();
-
- /**
- * @type {Capture}
+ * @type {boolean}
+ * @default false
* @private
*/
- this._$capture = new Capture();
+ this._$popstate = false;
/**
- * @type {RemoveResponse}
+ * @type {string}
+ * @default "top"
* @private
*/
- this._$removeResponse = new RemoveResponse();
+ this._$currentName = "top";
+ }
- /**
- * @type {boolean}
- * @default false
- * @private
- */
- this._$popstate = false;
+ /**
+ * @description 初期起動関数
+ * initial invoking function
+ *
+ * @return {Application}
+ * @method
+ * @public
+ */
+ initialize (config: ConfigImpl, packages: any[]): Application
+ {
+ $setConfig(config);
+ $setPackages(packages);
/**
* SPAが有効の場合は、遷移の履歴を残す
* Keep history of transitions if SPA setting is enabled
*/
if (config.spa) {
- window.addEventListener("popstate", () =>
+ window.addEventListener("popstate", (): void =>
{
this._$popstate = true;
this.gotoView();
});
}
- /**
- * @type {string}
- * @default "top"
- * @private
- */
- this._$currentName = "top";
+ return this;
}
/**
@@ -130,121 +109,107 @@ export class Application
* @method
* @public
*/
- gotoView (name: string = ""): Promise
+ async gotoView (name: string = ""): Promise
{
- const promises: Promise[] = [];
if (config.loading) {
- /**
- * ローディング表示を起動
- * Launch loading display
- */
- this._$loading.start();
+
+ const promises: Promise[] = [];
/**
* 現時点の描画をBitmapにして処理の負担を減らす
* Reduce the processing burden by making the current drawing a Bitmap.
*/
- promises.push(this._$capture.execute());
+ promises.push(captureExecute());
+
+ /**
+ * ローディング表示を起動
+ * Launch loading display
+ */
+ promises.push(loadingStart());
+
+ await Promise.all(promises);
}
- return Promise
- .all(promises)
- .then((): Promise =>
- {
- /**
- * 前の画面で取得したレスポンスデータを初期化
- * Initialize the response data obtained on the previous screen
- */
- this
- ._$removeResponse
- .execute(this._$currentName);
-
- return Promise.resolve();
- })
- .then((): Promise =>
- {
- /**
- * 指定されたパス、もしくはURLからアクセス先を算出
- * Calculate the access point from the specified path or URL
- */
- const object: QueryObject = this._$queryParser.execute(name);
-
- this._$currentName = object.name;
-
- /**
- * 遷移履歴をセット
- * Set transition history
- */
- if (config.spa && !this._$popstate) {
- history.pushState("", "",
- `${location.origin}/${this._$currentName}${object.queryString}`
- );
- }
-
- // update
- this._$popstate = false;
-
- return Promise.resolve();
- })
- .then((): Promise[]> =>
- {
- /**
- * routing.jsonで設定したリクエスト処理を実行
- * Execute request processing set by routing.json
- */
- return Promise
- .all(this._$requestUseCase.execute(this._$currentName));
- })
- .then((responses): Promise =>
- {
- /**
- * レスポンス情報をマップに登録
- * 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);
- }
-
- return Promise.resolve();
- })
- .then((): Promise =>
- {
- /**
- * ViewとViewModelを起動
- * Start View and ViewModel
- */
- return Promise.resolve(
- context.addChild(this._$currentName)
- );
- })
- .then((view: View | void): Promise[]> =>
- {
- /**
- * コールバック設定があれば実行
- * Execute callback settings if any.
- */
- const promises: Promise[] = [];
- if (view && config.gotoView) {
- promises.push(this._$callback.execute(
- config.gotoView.callback, view
- ));
- }
-
- return Promise.all(promises);
- })
- .then(() =>
- {
- /**
- * ローディング表示を終了
- * End loading display
- */
- this._$loading.end();
- });
+ /**
+ * 前の画面で取得したレスポンスデータを初期化
+ * 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 Promise.all(promises);
+ }
+
+ /**
+ * ローディング表示を終了
+ * End loading display
+ */
+ await loadingEnd();
+
+ /**
+ * 前の画面のキャプチャーを終了
+ * End previous screen capture
+ */
+ captureDispose();
}
}
diff --git a/src/application/Context.ts b/src/application/Context.ts
index 7e7722e..1178e41 100644
--- a/src/application/Context.ts
+++ b/src/application/Context.ts
@@ -1,14 +1,15 @@
-import { ToCamelCase } from "../domain/convert/ToCamelCase";
+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";
/**
- * メインコンテキスト、ViewとViewModelのunbind、bindをコントロールします。
- * Controls unbind and bind of the main context, View and ViewModel.
+ * @description メインコンテキスト、ViewとViewModelのunbind、bindをコントロールします。
+ * Controls unbind and bind of the main context, View and ViewModel.
+ *
* @class
- * @memberof application
+ * @memberof context
*/
export class Context
{
@@ -16,7 +17,6 @@ export class Context
private _$viewModel: ViewModel | null;
private _$viewName: string;
private readonly _$root: Sprite;
- private readonly _$toCamelCase: ToCamelCase;
/**
* @param {Sprite} root
@@ -49,16 +49,9 @@ export class Context
/**
* @type {Sprite}
- * @default null
* @private
*/
this._$root = root;
-
- /**
- * @type {ToCamelCase}
- * @private
- */
- this._$toCamelCase = new ToCamelCase();
}
/**
@@ -125,55 +118,57 @@ export class Context
* @method
* @public
*/
- addChild (name: string): Promise
+ async boot (name: string): Promise
{
- this._$viewName = this._$toCamelCase.execute(name);
+ this._$viewName = toCamelCase(name);
- const viewName: string = `${this._$viewName}View`;
+ const viewName: string = `${this._$viewName}View`;
const viewModelName: string = `${viewName}Model`;
if (!packages.size
|| !packages.has(viewName)
|| !packages.has(viewModelName)
) {
- return Promise.resolve();
+ throw new Error("not found view or viewMode.");
}
- const PrevView: View | null = this._$view;
- const PrevViewModel: ViewModel | null = this._$viewModel;
+ /**
+ * 現在のページを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();
- return Promise
- .all([this._$viewModel.bind(this._$view)])
- .then(() =>
- {
- if (!this._$view) {
- return ;
- }
-
- const root: Sprite | null = this._$root;
- if (!root) {
- throw new Error("the root is null.");
- }
-
- root.addChild(this._$view);
-
- while (root.numChildren > 1) {
- root.removeChild(root.getChildAt(0));
- }
-
- root.mouseChildren = true;
+ /**
+ * ViewModelにViewをbindしてページを生成
+ * Bind a View to a ViewModel to generate a page
+ */
+ await Promise.all([this._$viewModel.bind(this._$view)]);
- if (PrevViewModel && PrevView) {
- PrevViewModel.unbind(PrevView);
- }
+ /**
+ * stageの一番背面にviewをセット
+ * Set the view at the very back of the stage
+ */
+ this._$root.addChildAt(this._$view, 0);
- return this._$view;
- });
+ return this._$view;
}
}
\ No newline at end of file
diff --git a/src/application/content/ContentBuilder.ts b/src/application/content/ContentBuilder.ts
index 026aaa6..660e2d4 100644
--- a/src/application/content/ContentBuilder.ts
+++ b/src/application/content/ContentBuilder.ts
@@ -12,39 +12,30 @@ import type {
* @class
* @memberof application.content
*/
-export class ContentBuilder
+export const execute = (instance: DisplayObjectImpl): void =>
{
- /**
- * @param {object} instance
- * @return {object}
- * @method
- * @static
- */
- static 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 name = instance.namespace;
+ if (!loaderInfoMap.has(name)) {
+ return ;
+ }
- const characterId: number | void = loaderInfo._$data.symbols.get(name);
- if (!characterId) {
- return ;
- }
+ // Set the target LoaderInfo class
+ const loaderInfo: LoaderInfo | void = loaderInfoMap.get(name);
+ if (!loaderInfo || !loaderInfo._$data) {
+ return ;
+ }
- const character: Character = loaderInfo._$data.characters[characterId];
- if (!character) {
- return ;
- }
+ const characterId: number | void = loaderInfo._$data.symbols.get(name);
+ if (!characterId) {
+ return ;
+ }
- instance._$loaderInfo = loaderInfo;
- instance._$characterId = characterId;
- instance._$sync(character);
+ 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 b22c24a..540e328 100644
--- a/src/application/content/MovieClipContent.ts
+++ b/src/application/content/MovieClipContent.ts
@@ -1,5 +1,5 @@
import { MovieClip } from "@next2d/display";
-import { ContentBuilder } from "./ContentBuilder";
+import { execute as contentBuilder } from "./ContentBuilder";
/**
* @description NoCode Toolで作成したMovieClipの動的生成の補完を行うクラス。
@@ -19,7 +19,7 @@ export class MovieClipContent extends MovieClip
{
super();
- ContentBuilder.execute(this);
+ contentBuilder(this);
// initial processing
this.initialize();
diff --git a/src/application/content/ShapeContent.ts b/src/application/content/ShapeContent.ts
index f8d003e..aca96a9 100644
--- a/src/application/content/ShapeContent.ts
+++ b/src/application/content/ShapeContent.ts
@@ -1,5 +1,5 @@
import { Shape } from "@next2d/display";
-import { ContentBuilder } from "./ContentBuilder";
+import { execute as contentBuilder } from "./ContentBuilder";
/**
* @description NoCode Toolで作成したShapeの動的生成の補完を行うクラス。
@@ -19,7 +19,7 @@ export class ShapeContent extends Shape
{
super();
- ContentBuilder.execute(this);
+ contentBuilder(this);
// initial processing
this.initialize();
diff --git a/src/application/content/TextFieldContent.ts b/src/application/content/TextFieldContent.ts
index 1fa8c81..b20e702 100644
--- a/src/application/content/TextFieldContent.ts
+++ b/src/application/content/TextFieldContent.ts
@@ -1,5 +1,5 @@
import { TextField } from "@next2d/display";
-import { ContentBuilder } from "./ContentBuilder";
+import { execute as contentBuilder } from "./ContentBuilder";
/**
* @description NoCode Toolで作成したTextFieldの動的生成の補完を行うクラス。
@@ -19,7 +19,7 @@ export class TextFieldContent extends TextField
{
super();
- ContentBuilder.execute(this);
+ contentBuilder(this);
// initial processing
this.initialize();
diff --git a/src/application/content/VideoContent.ts b/src/application/content/VideoContent.ts
index a47d8a6..52b6d79 100644
--- a/src/application/content/VideoContent.ts
+++ b/src/application/content/VideoContent.ts
@@ -1,5 +1,5 @@
import { Video } from "@next2d/media";
-import { ContentBuilder } from "./ContentBuilder";
+import { execute as contentBuilder } from "./ContentBuilder";
/**
* @description NoCode Toolで作成したVideoの動的生成の補完を行うクラス。
@@ -19,7 +19,7 @@ export class VideoContent extends Video
{
super();
- ContentBuilder.execute(this);
+ contentBuilder(this);
// initial processing
this.initialize();
diff --git a/src/application/service/RemoveResponse.ts b/src/application/service/RemoveResponse.ts
index 565442b..132a6b6 100644
--- a/src/application/service/RemoveResponse.ts
+++ b/src/application/service/RemoveResponse.ts
@@ -1,85 +1,55 @@
-import { RequestType } from "../../infrastructure/constant/RequestType";
-import { RequestParser } from "../../domain/parser/RequestParser";
+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";
-
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- class?: string;
- access?: string;
- method?: string;
- callback?: string | string[];
-}
+import { RequestImpl } from "src/interface/RequestImpl";
/**
- * @class
- * @memberof application.service
+ * @param {string} name
+ * @return {void}
+ * @method
+ * @public
*/
-export class RemoveResponse
+export const execute = (name: string): void =>
{
- private readonly _$requestParser: RequestParser;
-
- /**
- * @constructor
- * @public
- */
- constructor ()
- {
- /**
- * @type {RequestParser}
- * @private
- */
- this._$requestParser = new RequestParser();
- }
-
- /**
- * @param {string} name
- * @return {void}
- * @method
- * @public
- */
- execute (name: string): void
- {
- const requests: Object[] = this._$requestParser.execute(name);
- for (let idx: number = 0; idx < requests.length; ++idx) {
-
- const object: Object = requests[idx];
+ const requests: RequestImpl[] = requestParser(name);
+ for (let idx: number = 0; idx < requests.length; ++idx) {
- if (object.type !== RequestType.CONTENT) {
- continue;
- }
+ const object: RequestImpl = requests[idx];
- if (object.cache || !response.has(object.name)) {
- continue;
- }
+ if (object.type !== "content") {
+ 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);
- }
- }
- }
+ if (object.cache
+ || !object.name
+ || !response.has(object.name)
+ ) {
+ continue;
}
/**
- * レスポンスデータをマップに格納
- * Stores response data in a map
+ * キャッシュしないパッケージはインメモリから削除
+ * Remove non-cached packages from in-memory
*/
- if (response.size) {
- response.clear();
+ 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);
+ }
+ }
}
}
-}
\ No newline at end of file
+
+ /**
+ * レスポンスデータを初期化
+ * Initialize response data
+ */
+ if (response.size) {
+ response.clear();
+ }
+};
\ No newline at end of file
diff --git a/src/application/variable/Context.ts b/src/application/variable/Context.ts
index 14606da..6bf6295 100644
--- a/src/application/variable/Context.ts
+++ b/src/application/variable/Context.ts
@@ -14,20 +14,16 @@ export let context: Context;
* @method
* @private
*/
-export const $createContext = (config: ConfigImpl): Promise =>
+export const $createContext = async (config: ConfigImpl): Promise =>
{
- return window
+ const root: Sprite = await window
.next2d
.createRootMovieClip(
config.stage.width,
config.stage.height,
config.stage.fps,
config.stage.options
- )
- .then((root: Sprite): Promise =>
- {
- context = new Context(root);
+ );
- return Promise.resolve();
- });
+ context = new Context(root);
};
\ No newline at end of file
diff --git a/src/application/variable/Parser.ts b/src/application/variable/Parser.ts
deleted file mode 100644
index 5fd9955..0000000
--- a/src/application/variable/Parser.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { ConfigParser } from "../../domain/parser/ConfigParser";
-
-export const parser: ConfigParser = new ConfigParser();
\ No newline at end of file
diff --git a/src/domain/callback/Callback.test.ts b/src/domain/callback/Callback.test.ts
new file mode 100644
index 0000000..ba6982f
--- /dev/null
+++ b/src/domain/callback/Callback.test.ts
@@ -0,0 +1,80 @@
+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/Callback.ts b/src/domain/callback/Callback.ts
index fcba224..f529cb6 100644
--- a/src/domain/callback/Callback.ts
+++ b/src/domain/callback/Callback.ts
@@ -1,45 +1,39 @@
import { packages } from "../../application/variable/Packages";
-import { parser } from "../../application/variable/Parser";
/**
- * @class
- * @memberof domain.callback
+ * @description configで指定されたクラスのexecute関数を実行
+ * Execute function of the class specified in config.
+ *
+ * @param {string|array} [callback=""]
+ * @param {*} [value=null]
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class Callback
-{
- /**
- * @description configで指定されたクラスのexecute関数を実行
- * Execute function of the class specified in config.
- *
- * @param {string|array} [callback=""]
- * @param {*} [value=null]
- * @return {Promise}
- * @method
- * @public
- */
- execute (callback: string | string[] = "", value: any = null): Promise[]|void>
- {
- if (!callback) {
- return Promise.resolve();
- }
-
- const callbacks: string[] = typeof callback === "string"
- ? [callback]
- : callback;
+export const execute = (
+ callback: string | string[] = "",
+ value: any = null
+): Promise[]|void> => {
- const promises: Promise[] = [];
+ if (!callback) {
+ return Promise.resolve();
+ }
- for (let idx: number = 0; idx < callbacks.length; ++idx) {
+ const callbacks: string[] = typeof callback === "string"
+ ? [callback]
+ : callback;
- const name: string = parser.execute(callbacks[idx]);
- if (!packages.has(name)) {
- continue;
- }
+ const promises: Promise[] = [];
+ for (let idx: number = 0; idx < callbacks.length; ++idx) {
- const CallbackClass: any = packages.get(name);
- promises.push(new CallbackClass().execute(value));
+ const name: string = callbacks[idx];
+ if (!packages.has(name)) {
+ continue;
}
- return Promise.all(promises);
+ const CallbackClass: any = packages.get(name);
+ promises.push(new CallbackClass().execute(value));
}
-}
\ No newline at end of file
+
+ 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
new file mode 100644
index 0000000..91dddbf
--- /dev/null
+++ b/src/domain/convert/ToCamelCase.test.ts
@@ -0,0 +1,19 @@
+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/convert/ToCamelCase.ts b/src/domain/convert/ToCamelCase.ts
index d7eb091..fbc423f 100644
--- a/src/domain/convert/ToCamelCase.ts
+++ b/src/domain/convert/ToCamelCase.ts
@@ -1,30 +1,23 @@
/**
- * @class
- * @memberof domain.convert
+ * @description キャメルケースに変換
+ * Convert to CamelCase
+ *
+ * @param {string} name
+ * @return {string}
+ * @method
+ * @public
*/
-export class ToCamelCase
+export const execute = (name: string): string =>
{
- /**
- * @description キャメルケースに変換
- * Convert to CamelCase
- *
- * @param {string} name
- * @return {string}
- * @method
- * @public
- */
- execute (name: string): string
- {
- const names: string[] = name.split("/");
+ const names: string[] = name.split("/");
- let viewName: string = "";
- for (let idx: number = 0; names.length > idx; ++idx) {
- name = names[idx];
- viewName += name
- .charAt(0)
- .toUpperCase() + name.slice(1);
- }
-
- return viewName;
+ let viewName: string = "";
+ for (let idx: number = 0; names.length > idx; ++idx) {
+ name = names[idx];
+ viewName += name
+ .charAt(0)
+ .toUpperCase() + name.slice(1);
}
-}
\ No newline at end of file
+
+ return viewName;
+};
\ No newline at end of file
diff --git a/src/domain/loading/Loading.ts b/src/domain/loading/Loading.ts
index a0870b8..3fbda7c 100644
--- a/src/domain/loading/Loading.ts
+++ b/src/domain/loading/Loading.ts
@@ -1,67 +1,91 @@
+import type { LoadingImpl } from "src/interface/LoadingImpl";
import { config } from "../../application/variable/Config";
import { packages } from "../../application/variable/Packages";
-import { parser } from "../../application/variable/Parser";
import { DefaultLoading } from "../screen/DefaultLoading";
/**
- * @class
- * @memberof domain.loading
+ * @type {object}
+ * @default null
+ * @private
*/
-export class Loading
+let $instance: LoadingImpl | null = null;
+
+/**
+ * @description ページ遷移時のローディング演出を開始
+ * Starts loading performance at page transitions
+ *
+ * @return {Promise}
+ * @method
+ * @public
+ */
+export const start = (): Promise =>
{
- /**
- * @description デフォルトのローディング演出を開始
- * Starts default loading direction
- *
- * @return {void}
- * @method
- * @public
- */
- start (): void
+ return new Promise((resolve): void =>
{
if (!config || !config.loading) {
- return ;
+ return resolve();
}
- const callback: string | void = config.loading.callback;
- if (!callback) {
- return ;
+ const name: string | void = config.loading.callback;
+ if (!name) {
+ return resolve();
}
- const name: string = parser.execute(callback);
+ if (!$instance) {
+ const CallbackClass: any = packages.has(name)
+ ? packages.get(name)
+ : DefaultLoading;
+
+ $instance = new CallbackClass();
+ }
+
+ if (!$instance) {
+ return resolve();
+ }
- const CallbackClass: any = packages.has(name)
- ? packages.get(name)
- : DefaultLoading;
+ $instance.start();
- new CallbackClass().start();
- }
+ setTimeout(() =>
+ {
+ resolve();
+ }, 500);
+ });
+};
- /**
- * @description デフォルトのローディング演出を終了
- * End default loading direction
- *
- * @return {void}
- * @method
- * @public
- */
- end (): void
+/**
+ * @description ページ遷移時のローディング演出を終了
+ * Terminate loading direction at page transition
+ *
+ * @return {Promise}
+ * @method
+ * @public
+ */
+export const end = (): Promise =>
+{
+ return new Promise((resolve): void =>
{
if (!config || !config.loading) {
- return ;
+ return resolve();
}
- const callback: string|undefined = config.loading.callback;
- if (!callback) {
- return ;
+ const name: string | undefined = config.loading.callback;
+ if (!name) {
+ return resolve();
}
- const name: string = parser.execute(callback);
+ if (!$instance) {
+
+ const CallbackClass: any = packages.has(name)
+ ? packages.get(name)
+ : DefaultLoading;
- const CallbackClass: any = packages.has(name)
- ? packages.get(name)
- : DefaultLoading;
+ $instance = new CallbackClass();
+ }
+
+ if (!$instance) {
+ return resolve();
+ }
- new CallbackClass().end();
- }
-}
\ No newline at end of file
+ resolve($instance.end());
+ });
+};
\ No newline at end of file
diff --git a/src/domain/parser/ConfigParser.ts b/src/domain/parser/ConfigParser.ts
deleted file mode 100644
index 1bf91b2..0000000
--- a/src/domain/parser/ConfigParser.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { config } from "../../application/variable/Config";
-
-/**
- * configファイルに設定した変数パスのパーサークラス
- * Parser class for variable paths set in config file
- *
- * @class
- * @memberof domain.parser
- */
-export class ConfigParser
-{
- /**
- * @description 指定されたstringを分解して、configの変数パスの値を返す
- * Disassembles the given string and returns the value of the config variable path
- *
- * @param {string} [value=""]
- * @return {string}
- * @method
- * @public
- */
- execute (value: string = ""): string
- {
- if (value.indexOf("{{") === -1) {
- return value;
- }
-
- const regexp = new RegExp(/{{(.*?)}}/, "g");
- const values: RegExpMatchArray | null = value.match(regexp);
- if (!values) {
- return value;
- }
-
- let returnValue: string = value;
- for (let idx: number = 0; idx < values.length; ++idx) {
-
- const value: string = values[idx];
-
- const names: string[] = value
- .replace(/\{|\{|\}|\}/g, "")
- .replace(/ /g, "")
- .split(".");
-
- if (!names.length) {
- continue;
- }
-
- let configValue: any = config;
- for (let idx: number = 0; idx < names.length; ++idx) {
- const name: string = names[idx];
- if (name in configValue) {
- configValue = configValue[name];
- }
- }
-
- if (config === configValue) {
- continue;
- }
-
- returnValue = returnValue.replace(value, configValue);
- }
-
- return returnValue;
- }
-}
\ No newline at end of file
diff --git a/src/domain/parser/QueryParser.test.ts b/src/domain/parser/QueryParser.test.ts
new file mode 100644
index 0000000..855b5b0
--- /dev/null
+++ b/src/domain/parser/QueryParser.test.ts
@@ -0,0 +1,251 @@
+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";
+
+Object.defineProperty(window, "location", {
+ "get": vi.fn().mockReturnValue({
+ "search": "",
+ "pathname": ""
+ })
+});
+
+describe("QueryParserTest", () =>
+{
+ test("parse query test case1", () =>
+ {
+ query.clear();
+ query.set("test", 123);
+ expect(query.size).toBe(1);
+
+ const object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = 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 object: QueryObjectImpl = execute("./");
+
+ expect(query.size).toBe(0);
+ expect(object.name).toBe("top");
+ });
+});
\ No newline at end of file
diff --git a/src/domain/parser/QueryParser.ts b/src/domain/parser/QueryParser.ts
index b21a560..5158ae2 100644
--- a/src/domain/parser/QueryParser.ts
+++ b/src/domain/parser/QueryParser.ts
@@ -1,95 +1,89 @@
+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";
-interface Object {
- name: string;
- queryString: string;
-}
-
/**
- * @class
- * @memberof domain.parser
+ * @description 指定されたQueryStringか、URLのQueryStringをquery mapに登録
+ * Register the specified QueryString or URL QueryString in the query map
+ *
+ * @param {string} [name=""]
+ * @return {object}
+ * @method
+ * @public
*/
-export class QueryParser
+export const execute = (name: string = ""): QueryObjectImpl =>
{
/**
- * @description 指定されたQueryStringか、URLのQueryStringをquery mapに登録
- * Register the specified QueryString or URL QueryString in the query map
- *
- * @param {string} [name=""]
- * @return {object}
- * @method
- * @public
+ * 前のシーンのクエリデータを初期化
+ * Initialize query data from previous scene
*/
- execute (name: string = ""): Object
- {
- if (query.size) {
- query.clear();
- }
+ if (query.size) {
+ query.clear();
+ }
- /**
- * QueryStringがあれば分解
- * Disassemble QueryString if available
- */
- let queryString: string = "";
- if (!name && location.search) {
- queryString = location.search;
- const parameters = queryString.slice(1).split("&");
- for (let idx = 0; idx < parameters.length; ++idx) {
- const pair: string[] = parameters[idx].split("=");
- query.set(pair[0], pair[1]);
- }
+ /**
+ * QueryStringがあれば分解
+ * Disassemble QueryString if available
+ */
+ let queryString: string = "";
+ 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("=");
+ query.set(pair[0], pair[1]);
}
+ }
- if (!name) {
- const names: string[] = location.pathname.split("/");
- names.shift();
- name = `${names.join("/")}`;
- if (name && config && config.routing) {
- const routing: any = config.routing[name];
- if (!routing) {
- name = "top";
- }
-
- if (routing && routing.private) {
- name = routing.redirect || "top";
- }
+ if (!name) {
+ const names: string[] = location.pathname.split("/");
+ names.shift();
+ name = `${names.join("/")}`;
+ if (name && config && config.routing) {
+ const routing: RoutingImpl = config.routing[name];
+ if (!routing) {
+ name = "top";
}
- if (!name) {
- name = "top";
+ if (routing && routing.private) {
+ name = routing.redirect || "top";
}
}
- /**
- * 任意で設定したQueryStringを分解
- * Decompose an arbitrarily set QueryString
- */
- if (name.indexOf("?") > -1) {
+ if (!name) {
+ name = "top";
+ }
+ }
- const names: string[] = name.split("?");
+ /**
+ * 任意で設定したQueryStringを分解
+ * Decompose an arbitrarily set QueryString
+ */
+ if (name.indexOf("?") > -1) {
- name = names[0];
- queryString = `?${names[1]}`;
+ const names: string[] = name.split("?");
- const parameters: string[] = names[1].split("&");
- for (let idx = 0; idx < parameters.length; ++idx) {
- const pair: string[] = parameters[idx].split("=");
- query.set(pair[0], pair[1]);
- }
- }
+ name = names[0];
+ queryString = `?${names[1]}`;
- if (name.slice(0, 1) === ".") {
- name = name.split("/").slice(1).join("/") || "top";
+ const parameters: string[] = names[1].split("&");
+ for (let idx: number = 0; idx < parameters.length; ++idx) {
+ const pair: string[] = parameters[idx].split("=");
+ query.set(pair[0], pair[1]);
}
+ }
- if (name.indexOf("@") > -1) {
- name = name.replace("@", "");
- }
+ if (name.slice(0, 1) === ".") {
+ name = name.split("/").slice(1).join("/") || "top";
+ }
- return {
- "name": name,
- "queryString": queryString
- };
+ if (name.indexOf("@") > -1) {
+ name = name.replace("@", "");
}
-}
\ No newline at end of file
+
+ return {
+ "name": name,
+ "queryString": queryString
+ };
+};
\ No newline at end of file
diff --git a/src/domain/parser/RequestParser.test.ts b/src/domain/parser/RequestParser.test.ts
new file mode 100644
index 0000000..8b477db
--- /dev/null
+++ b/src/domain/parser/RequestParser.test.ts
@@ -0,0 +1,138 @@
+import { execute } from "./RequestParser";
+import { $setConfig } from "../../../src/application/variable/Config";
+
+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 requests: Object[] = 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 requests: Object[] = 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": "json",
+ "name": "TopTest",
+ "path": "local"
+ }
+ ]
+ }
+ }
+ };
+
+ $setConfig(config);
+
+ const requests: Object[] = execute("top");
+ expect(requests.length).toBe(1);
+
+ const object: Object = requests[0];
+ expect(object.type).toBe("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": "content",
+ "path": "{{ content.endPoint }}content/sample.json",
+ "name": "MainContent",
+ "cache": true
+ }
+ ]
+ },
+ "top": {
+ "requests": [
+ {
+ "type": "cluster",
+ "path": "@sample"
+ },
+ {
+ "type": "json",
+ "path": "{{ api.endPoint }}api/top.json",
+ "name": "TopText"
+ }
+ ]
+ }
+ }
+ };
+
+ $setConfig(config);
+
+ const requests: Object[] = execute("top");
+ expect(requests.length).toBe(2);
+
+ const object1: Object = requests[0];
+ expect(object1.type).toBe("content");
+ expect(object1.name).toBe("MainContent");
+
+ const object2: Object = requests[1];
+ expect(object2.type).toBe("json");
+ expect(object2.name).toBe("TopText");
+ });
+});
\ No newline at end of file
diff --git a/src/domain/parser/RequestParser.ts b/src/domain/parser/RequestParser.ts
index 8d1df93..f48a64c 100644
--- a/src/domain/parser/RequestParser.ts
+++ b/src/domain/parser/RequestParser.ts
@@ -1,62 +1,51 @@
-import { RequestType } from "../../infrastructure/constant/RequestType";
+import { RequestImpl } from "src/interface/RequestImpl";
import { config } from "../../application/variable/Config";
-import type { RequestTypeImpl } from "../../interface/RequestTypeImpl";
-
-interface Object {
- type: RequestTypeImpl;
- name: string;
- path: string;
- cache: boolean;
- class: string;
- access: string;
- method: string;
- callback?: string | string[];
-}
+import type { RoutingImpl } from "src/interface/RoutingImpl";
/**
- * @class
- * @memberof domain.parser
+ * @description routing.jsonに設定されたrequestsを返却します。
+ * クラスターの指定があった場合は返却する配列にマージして返却
+ * Returns requests set in routing.json.
+ * If a cluster is specified, it is merged into the array to be returned
+ *
+ * @param {string} name
+ * @return {array}
+ * @method
+ * @public
*/
-export class RequestParser
+export const execute = (name: string): RequestImpl[] =>
{
- /**
- * @description routing.jsonに設定されたrequestsを返却します。
- * クラスターの指定があった場合は返却する配列にマージして返却
- * Returns requests set in routing.json.
- * If a cluster is specified, it is merged into the array to be returned
- *
- * @param {string} name
- * @return {array}
- * @method
- * @public
- */
- execute (name: string): Object[]
- {
- if (!config || !config.routing) {
- return [];
- }
+ const requests: RequestImpl[] = [];
- const routing: any = config.routing[name];
- if (!routing || !routing.requests) {
- return [];
- }
+ if (!config || !config.routing) {
+ return requests;
+ }
+
+ const routing: RoutingImpl = config.routing[name];
+ if (!routing || !routing.requests) {
+ return requests;
+ }
- const requests: Object[] = [];
- for (let idx = 0; idx < routing.requests.length; idx++) {
+ for (let idx: number = 0; idx < routing.requests.length; idx++) {
- const object: Object = routing.requests[idx];
+ const request: RequestImpl = routing.requests[idx];
- if (object.type !== RequestType.CLUSTER) {
- requests.push(object);
- continue;
- }
+ if (request.type !== "cluster") {
+ requests.push(request);
+ continue;
+ }
- const results: Object[] = new RequestParser().execute(object.path);
- for (let idx = 0; idx < results.length; ++idx) {
- requests.push(results[idx]);
- }
+ if (!request.path) {
+ continue;
}
- return requests;
+ /**
+ * クラスターの場合は分解して配列に追加
+ * For clusters, disassemble and add to array
+ */
+ const results: RequestImpl[] = execute(request.path);
+ requests.push(...results);
}
-}
\ No newline at end of file
+
+ return requests;
+};
\ No newline at end of file
diff --git a/src/domain/screen/Capture.ts b/src/domain/screen/Capture.ts
index 5066aae..e77e043 100644
--- a/src/domain/screen/Capture.ts
+++ b/src/domain/screen/Capture.ts
@@ -4,60 +4,103 @@ 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();
+
/**
- * @class
- * @memberof domain.screen
+ * @type {number}
+ * @default 0
+ * @private
*/
-export class Capture
+let cacheX: number = 0;
+
+/**
+ * @type {number}
+ * @default 0
+ * @private
+ */
+let cacheY: number = 0;
+
+/**
+ * @description 現時点の描画キャプチャーを生成
+ * Generate current drawing capture
+ *
+ * @return {Promise}
+ * @method
+ * @public
+ */
+export const execute = (): Promise =>
{
- /**
- * @description 現時点の描画キャプチャーを生成
- * Generate current drawing capture
- *
- * @return {Promise}
- * @method
- * @public
- */
- execute (): Promise
+ return new Promise((resolve) =>
{
- return new Promise((resolve) =>
- {
- const width: number = config.stage.width;
- const height: number = config.stage.height;
-
- const mask: any = new Shape();
- mask
+ 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);
+ }
- const player: Player = $currentPlayer();
-
- const tx: number = player.x;
- if (tx) {
- const scaleX: number = player.scaleX;
- mask.scaleX = (width + tx * 2 / scaleX) / width;
- mask.x = -tx / scaleX;
- }
-
- const ty: number = player.y;
- if (ty) {
- const scaleY: number = player.scaleY;
- mask.scaleY = (height + ty * 2 / scaleY) / height;
- mask.y = -ty / scaleY;
- }
-
- const root: Sprite = context.root;
- if (root) {
- root.mouseChildren = false;
- root.addChild(mask);
- }
-
- setTimeout(() =>
- {
- resolve();
- }, 350);
- });
+ /**
+ * マウス操作を有効化
+ * Enable Mouse Operation
+ */
+ root.mouseChildren = true;
}
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/src/domain/screen/DefaultLoading.ts b/src/domain/screen/DefaultLoading.ts
index 1c17f60..5feabda 100644
--- a/src/domain/screen/DefaultLoading.ts
+++ b/src/domain/screen/DefaultLoading.ts
@@ -1,5 +1,98 @@
-import { $currentPlayer } from "@next2d/util";
-import type { Player } from "@next2d/core";
+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.2,
+ 0.7,
+ Easing.inOutCubic
+ );
+ sprite.setLocalVariable("reduceJob", reduceJob);
+
+ const expandJob: Job = Tween.add(
+ sprite,
+ getStartObject(),
+ getEndObject(),
+ 0.2,
+ 0.7,
+ 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
@@ -7,21 +100,6 @@ import type { Player } from "@next2d/core";
*/
export class DefaultLoading
{
- private readonly _$elementId: string;
-
- /**
- * @constructor
- * @public
- */
- constructor ()
- {
- /**
- * @type {string}
- * @private
- */
- this._$elementId = "__next2d__framework_loading";
- }
-
/**
* @description Canvasが設置されたDOMにローディング演出を登録、既にDOMがあれば演出を表示
* Register loading direction in the DOM where Canvas is installed,
@@ -33,82 +111,56 @@ export class DefaultLoading
*/
start (): void
{
- const element: HTMLElement | null = document.getElementById(this._$elementId);
- if (!element) {
-
- const player: Player = $currentPlayer();
-
- const parent: HTMLElement | null = document
- .getElementById(player.contentElementId);
+ 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();
+ }, 200 * idx);
+ } else {
+ expandJob.start();
+ }
- if (!parent) {
- return ;
+ const shape: Shape = sprite.getChildAt(0);
+ if (shape.width === minSize) {
+ continue;
}
- const loader: HTMLDivElement = document.createElement("div");
-
- loader.id = this._$elementId;
-
- loader.innerHTML = `
-`;
-
- parent.insertBefore(loader, parent.children[0]);
-
- } else {
-
- element.setAttribute("style", "");
+ 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);
}
/**
@@ -121,11 +173,19 @@ export class DefaultLoading
*/
end (): void
{
- const element: HTMLElement | null = document
- .getElementById(this._$elementId);
+ // 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 (element) {
- element.setAttribute("style", "display:none;");
+ 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 ebbf0d5..4a1e71b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,40 +1,39 @@
import "@next2d/player";
import { Application } from "./application/Application";
-import { DefaultLoading } from "./domain/screen/DefaultLoading";
import { View } from "./view/View";
import { ViewModel } from "./view/ViewModel";
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 { ConfigImpl } from "./interface/ConfigImpl";
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 1.6.1 %c https://next2d.app",
+console.log("%c Next2D Framework %c 2.0.0 %c https://next2d.app",
"color: #fff; background: #5f5f5f",
"color: #fff; background: #4bc729",
"");
+const app: Application = new Application();
export {
- Application,
- DefaultLoading,
+ app,
View,
ViewModel,
MovieClipContent,
ShapeContent,
TextFieldContent,
VideoContent,
- ConfigImpl,
packages,
context,
cache,
query,
response,
- loaderInfoMap
+ loaderInfoMap,
+ ConfigImpl
};
diff --git a/src/infrastructure/constant/RequestType.ts b/src/infrastructure/constant/RequestType.ts
deleted file mode 100644
index 8bbf0a1..0000000
--- a/src/infrastructure/constant/RequestType.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import type { RequestTypeImpl } from "../../interface/RequestTypeImpl";
-
-/**
- * リクエストタイプの定数
- * Request Type Constants
- *
- * @class
- * @memberof infrastructure.constant
- */
-export class RequestType
-{
- /**
- * @description リクエストの集合体
- * Aggregation of requests.
- *
- * @return {string}
- * @default "cluster"
- * @const
- * @static
- */
- static get CLUSTER (): RequestTypeImpl
- {
- return "cluster";
- }
-
- /**
- * @description NoCode Toolで書き出したJSONコンテンツ
- * JSON content exported by NoCode Tool.
- *
- * @return {string}
- * @default "content"
- * @const
- * @static
- */
- static get CONTENT (): RequestTypeImpl
- {
- return "content";
- }
-
- /**
- * @description カスタムリクエストタイプ
- * custom request type.
- *
- * @return {string}
- * @default "custom"
- * @const
- * @static
- */
- static get CUSTOM (): RequestTypeImpl
- {
- return "custom";
- }
-
- /**
- * @description JSONのフォーマットを指定
- * Specify JSON format.
- *
- * @return {string}
- * @default "json"
- * @const
- * @static
- */
- static get JSON (): RequestTypeImpl
- {
- return "json";
- }
-}
diff --git a/src/infrastructure/dto/ResponseDTO.test.ts b/src/infrastructure/dto/ResponseDTO.test.ts
new file mode 100644
index 0000000..a77fde5
--- /dev/null
+++ b/src/infrastructure/dto/ResponseDTO.test.ts
@@ -0,0 +1,18 @@
+import { ResponseDTO } from "./ResponseDTO";
+
+describe("ResponseDTOTest", () =>
+{
+ test("execute test case1", () =>
+ {
+ const responseDTO = new ResponseDTO();
+ expect(responseDTO.name).toBe("");
+ expect(responseDTO.response).toBe(null);
+ });
+
+ test("execute test case2", () =>
+ {
+ const responseDTO = new ResponseDTO("sample", 100);
+ expect(responseDTO.name).toBe("sample");
+ expect(responseDTO.response).toBe(100);
+ });
+});
\ No newline at end of file
diff --git a/src/infrastructure/dto/ResponseDTO.ts b/src/infrastructure/dto/ResponseDTO.ts
index f60f617..e968256 100644
--- a/src/infrastructure/dto/ResponseDTO.ts
+++ b/src/infrastructure/dto/ResponseDTO.ts
@@ -1,6 +1,6 @@
/**
- * 外部データをObjectに変換(DTO)、可変性はない使い捨てのクラス
- * Converts external data to Object (DTO), disposable class with no variability
+ * @description 外部データをObjectに変換(DTO)、可変性のない使い捨てのクラス
+ * Converts external data to Objects (DTO), non-variable, disposable class
*
* @class
* @memberof infrastructure.dto
@@ -34,10 +34,11 @@ export class ResponseDTO
}
/**
- * @description キャッシュする場合のキー名
- * Key name if caching
+ * @description キャッシュのキー名
+ * Key name of cache
*
* @return {string}
+ * @default ""
* @readonly
* @public
*/
@@ -51,10 +52,11 @@ export class ResponseDTO
* response data
*
* @return {*}
+ * @default null
* @readonly
* @public
*/
- get response (): any
+ get response (): any | null
{
return this._$response;
}
diff --git a/src/infrastructure/repository/ContentRepository.ts b/src/infrastructure/repository/ContentRepository.ts
index 3297d21..e4e69fe 100644
--- a/src/infrastructure/repository/ContentRepository.ts
+++ b/src/infrastructure/repository/ContentRepository.ts
@@ -1,4 +1,5 @@
-import { parser } from "../../application/variable/Parser";
+import type { RequestImpl } from "src/interface/RequestImpl";
+import { Loader } from "@next2d/display";
import {
Event,
IOErrorEvent
@@ -7,89 +8,71 @@ import {
URLRequestHeader,
URLRequest
} from "@next2d/net";
-import { Loader } from "@next2d/display";
-
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- callback?: string|string[];
- method?: string;
- body?: object;
- headers?: HeadersInit;
-}
/**
- * NoCodeToolで制作したJSON取得時のリクエストとレスポンスの管理クラス
- * Request and Response management class for JSON acquisition
+ * @description 指定先のJSONを非同期で取得
+ * Asynchronously obtain JSON of the specified destination
*
- * @class
- * @memberof infrastructure.repository
+ * @param {object} request_object
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class ContentRepository
+export const execute = (request_object: RequestImpl): Promise =>
{
- /**
- * @description 指定先のJSONを非同期で取得
- * Asynchronously obtain JSON of the specified destination
- *
- * @param {object} object
- * @return {Promise}
- * @method
- * @public
- */
- execute (object: Object): Promise
+ return new Promise((resolve, reject) =>
{
- return new Promise((resolve, reject) =>
- {
- const request: URLRequest = new URLRequest(`${parser.execute(object.path)}`);
+ if (!request_object.path) {
+ return reject();
+ }
- const method = object.method
- ? parser.execute(object.method).toUpperCase()
- : "GET";
+ const request: URLRequest = new URLRequest(request_object.path);
- switch (method) {
+ const method: string = request_object.method
+ ? request_object.method.toUpperCase()
+ : "GET";
- case "DELETE":
- case "GET":
- case "HEAD":
- case "OPTIONS":
- case "POST":
- case "PUT":
- request.method = method;
- break;
+ switch (method) {
- default:
- request.method = "GET";
- break;
+ case "DELETE":
+ case "GET":
+ case "HEAD":
+ case "OPTIONS":
+ case "POST":
+ case "PUT":
+ request.method = method;
+ break;
- }
+ default:
+ request.method = "GET";
+ break;
- if (object.headers) {
- for (const [name, value] of Object.entries(object.headers)) {
- request
- .requestHeaders
- .push(new URLRequestHeader(name, value));
- }
- }
+ }
- if (object.body) {
- request.data = JSON.stringify(object.body);
+ 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: any) =>
- {
- return resolve(event.currentTarget.content);
- });
+ 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
+ .contentLoaderInfo
+ .addEventListener(IOErrorEvent.IO_ERROR, reject);
- loader.load(request);
- });
- }
-}
\ No newline at end of file
+ loader.load(request);
+ });
+};
\ No newline at end of file
diff --git a/src/infrastructure/repository/CustomRepository.ts b/src/infrastructure/repository/CustomRepository.ts
index 612faa3..88fbc1f 100644
--- a/src/infrastructure/repository/CustomRepository.ts
+++ b/src/infrastructure/repository/CustomRepository.ts
@@ -1,56 +1,40 @@
-import { parser } from "../../application/variable/Parser";
+import type { RequestImpl } from "src/interface/RequestImpl";
import { packages } from "../../application/variable/Packages";
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- class: string;
- access: string;
- method: string;
- callback?: string|string[];
- body?: object;
- headers?: HeadersInit;
-}
-
/**
- * 外部データ取得時のリクエストとレスポンスの管理クラス
- * Request and Response management class for JSON acquisition
+ * @description 指定先の外部データを非同期で取得
+ * Asynchronous acquisition of external data at specified destination
*
- * @class
- * @memberof infrastructure.repository
+ * @param {object} request_object
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class CustomRepository
+export const execute = (request_object: RequestImpl): Promise =>
{
- /**
- * @description 指定先の外部データを非同期で取得
- * Asynchronous acquisition of external data at specified destination
- *
- * @param {object} object
- * @return {Promise}
- * @method
- * @public
- */
- execute (object: Object): Promise
+ return new Promise((resolve) =>
{
- return new Promise((resolve) =>
- {
- const className: string = parser.execute(object.class);
- if (!packages.has(className)) {
- return resolve(null);
- }
+ 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(className);
- const promise: Promise = parser.execute(object.access) === "static"
- ? Promise.resolve(CallbackClass[parser.execute(object.method)]())
- : Promise.resolve(new CallbackClass()[parser.execute(object.method)]());
+ 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
+ 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
index 77cf488..f6db23d 100644
--- a/src/infrastructure/repository/JsonRepository.ts
+++ b/src/infrastructure/repository/JsonRepository.ts
@@ -1,59 +1,39 @@
-import { parser } from "../../application/variable/Parser";
-
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- callback?: string | string[];
- method?: string;
- body?: object;
- headers?: HeadersInit;
-}
+import type { RequestImpl } from "src/interface/RequestImpl";
/**
- * JSON取得時のリクエストとレスポンスの管理クラス
- * Request and Response management class for JSON acquisition
+ * @description 指定先のJSONを非同期で取得
+ * Asynchronously obtain JSON of the specified destination
*
- * @class
- * @memberof infrastructure.repository
+ * @param {object} request_object
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class JsonRepository
+export const execute = async (request_object: RequestImpl): Promise =>
{
- /**
- * @description 指定先のJSONを非同期で取得
- * Asynchronously obtain JSON of the specified destination
- *
- * @param {object} object
- * @return {Promise}
- * @method
- * @public
- */
- execute (object: Object): Promise
- {
- const options: RequestInit = {};
+ if (!request_object.path) {
+ throw new Error("`path` must be set for json requests.");
+ }
- const method: string = options.method = object.method
- ? parser.execute(object.method).toUpperCase()
- : "GET";
+ const options: RequestInit = {};
- const body: any = object.body
- && method === "POST" || method === "PUT"
- ? JSON.stringify(object.body)
- : null;
+ const method: string = options.method = request_object.method
+ ? request_object.method.toUpperCase()
+ : "GET";
- if (body) {
- options.body = body;
- }
+ const body: any = request_object.body
+ && method === "POST" || method === "PUT"
+ ? JSON.stringify(request_object.body)
+ : null;
- if (object.headers) {
- options.headers = object.headers;
- }
+ if (body) {
+ options.body = body;
+ }
- return fetch(`${parser.execute(object.path)}`, options)
- .then((response: Response) =>
- {
- return response.json();
- });
+ if (request_object.headers) {
+ options.headers = request_object.headers;
}
-}
\ No newline at end of file
+
+ 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
index 1a965d0..2ad895d 100644
--- a/src/infrastructure/service/ContentService.ts
+++ b/src/infrastructure/service/ContentService.ts
@@ -1,128 +1,95 @@
-import { ContentRepository } from "../repository/ContentRepository";
-import { Callback } from "../../domain/callback/Callback";
+import { execute as contentRepository } from "../repository/ContentRepository";
+import { execute as callback } from "../../domain/callback/Callback";
import { ResponseDTO } from "../dto/ResponseDTO";
-import { parser } from "../../application/variable/Parser";
import { cache } from "../../application/variable/Cache";
import { loaderInfoMap } from "../../application/variable/LoaderInfoMap";
import type { LoaderInfo } from "@next2d/display";
-
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- callback?: string | string[];
- method?: string;
- body?: object;
- headers?: HeadersInit;
-}
+import type { RequestImpl } from "src/interface/RequestImpl";
/**
- * NoCodeToolで制作したJSON取得時のロジッククラス
- * Logic class for JSON acquisition produced by NoCodeTool
+ * @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.
*
- * @class
- * @memberof infrastructure.service
+ * @param {object} request_object
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class ContentService
+export const execute = async (request_object: RequestImpl): Promise =>
{
- private _$repository: ContentRepository;
- private _$callback: Callback;
-
- /**
- * @constructor
- * @public
- */
- constructor ()
- {
- /**
- * @type {ContentRepository}
- * @private
- */
- this._$repository = new ContentRepository();
-
- /**
- * @type {Callback}
- * @private
- */
- this._$callback = new Callback();
+ if (!request_object.name) {
+ throw new Error("`name` must be set for content requests.");
}
/**
- * @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} object
- * @return {Promise}
- * @method
- * @public
+ * キャッシュを利用する場合はキャッシュデータをチェック
+ * Check cache data if cache is used
*/
- execute (object: Object): Promise
- {
- /**
- * キャッシュを利用する場合はキャッシュデータをチェック
- * Check cache data if cache is used
- */
- if (object.cache && object.name) {
+ if (request_object.cache) {
- const name: string = parser.execute(object.name);
- if (cache.size && cache.has(name)) {
+ if (cache.size && cache.has(request_object.name)) {
- const value: any = cache.get(name);
+ const value: any = cache.get(request_object.name);
+ /**
+ * コールバック設定があれば実行
+ * Execute callback settings if any.
+ */
+ if (request_object.callback) {
const promises: Promise[]|void>[] = [];
- if (object.callback) {
- promises.push(this._$callback.execute(
- object.callback, value
- ));
- }
+ promises.push(callback(
+ request_object.callback, value
+ ));
- return Promise
- .all(promises)
- .then((): ResponseDTO =>
- {
- return new ResponseDTO(name, value);
- });
+ await Promise.all(promises);
}
+
+ return new ResponseDTO(request_object.name, value);
}
+ }
- return this
- ._$repository
- .execute(object)
- .then((content: any) =>
- {
- const name: string = parser.execute(object.name);
- if (object.cache && object.name) {
- cache.set(name, content);
- }
+ /**
+ * 指定のコンテンツデータを取得
+ * Obtain specified content data
+ */
+ const content = await contentRepository(request_object);
- const loaderInfo: LoaderInfo = content._$loaderInfo;
+ /**
+ * キャッシュ設定がonならキャッシュに登録
+ * If the cache setting is on, register it in the cache.
+ */
+ if (request_object.cache) {
+ cache.set(request_object.name, content);
+ }
- // DisplayObjectContainer
- if (loaderInfo._$data) {
- const symbols: Map = loaderInfo._$data.symbols;
- if (symbols.size) {
- for (const name of symbols.keys()) {
- loaderInfoMap.set(name, loaderInfo);
- }
- }
- }
+ /**
+ * 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);
+ }
+ }
+ }
- const promises: Promise[]|void>[] = [];
- if (object.callback) {
- promises.push(this._$callback.execute(
- object.callback, content
- ));
- }
+ /**
+ * コールバック設定があれば実行
+ * Execute callback settings if any.
+ */
+ if (request_object.callback) {
+ const promises: Promise[]|void>[] = [];
+ promises.push(callback(
+ request_object.callback, content
+ ));
- return Promise
- .all(promises)
- .then((): ResponseDTO =>
- {
- return new ResponseDTO(name, content);
- });
- });
+ await Promise.all(promises);
}
-}
\ No newline at end of file
+
+ 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
index 8253869..26eefcf 100644
--- a/src/infrastructure/service/CustomService.ts
+++ b/src/infrastructure/service/CustomService.ts
@@ -1,116 +1,63 @@
-import { CustomRepository } from "../repository/CustomRepository";
-import { Callback } from "../../domain/callback/Callback";
+import type { RequestImpl } from "src/interface/RequestImpl";
import { ResponseDTO } from "../dto/ResponseDTO";
-import { parser } from "../../application/variable/Parser";
import { cache } from "../../application/variable/Cache";
-
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- class: string;
- access: string;
- method: string;
- callback?: string | string[];
- body?: object;
- headers?: HeadersInit;
-}
+import { execute as callback } from "../../domain/callback/Callback";
+import { execute as customRepository } from "../repository/CustomRepository";
/**
- * JSON取得時のロジッククラス
- * Logic class for JSON acquisition
+ * @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.
*
- * @class
- * @memberof infrastructure.service
+ * @param {object} request_object
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class CustomService
+export const execute = async (request_object: RequestImpl): Promise =>
{
- private readonly _$repository: CustomRepository;
- private readonly _$callback: Callback;
-
- /**
- * @constructor
- * @public
- */
- constructor ()
- {
- /**
- * @type {CustomRepository}
- * @private
- */
- this._$repository = new CustomRepository();
-
- /**
- * @type {Callback}
- * @private
- */
- this._$callback = new Callback();
+ if (!request_object.name) {
+ throw new Error("`name` must be set for custom requests.");
}
/**
- * @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} object
- * @return {Promise}
- * @method
- * @public
+ * キャッシュを利用する場合はキャッシュデータをチェック
+ * Check cache data if cache is used
*/
- execute (object: Object): Promise
- {
- /**
- * キャッシュを利用する場合はキャッシュデータをチェック
- * Check cache data if cache is used
- */
- if (object.cache && object.name) {
+ if (request_object.cache) {
- const name: string = parser.execute(object.name);
- if (cache.size && cache.has(name)) {
+ if (cache.size && cache.has(request_object.name)) {
- const value: any = cache.get(name);
+ const value: any = cache.get(request_object.name);
+ if (request_object.callback) {
const promises: Promise[]|void>[] = [];
- if (object.callback) {
- promises.push(this._$callback.execute(
- object.callback, value
- ));
- }
+ promises.push(callback(
+ request_object.callback, value
+ ));
- return Promise
- .all(promises)
- .then((): ResponseDTO =>
- {
- return new ResponseDTO(name, value);
- });
+ await Promise.all(promises);
}
+
+ return new ResponseDTO(request_object.name, value);
}
+ }
- return this
- ._$repository
- .execute(object)
- .then((response: any) =>
- {
- const name:string = parser.execute(object.name);
- if (object.cache && object.name) {
- cache.set(name, response);
- }
+ const response: any = await customRepository(request_object);
- const promises: Promise[]|void>[] = [];
- if (object.callback) {
- promises.push(this._$callback.execute(
- object.callback, response
- ));
- }
+ if (request_object.cache) {
+ cache.set(request_object.name, response);
+ }
- return Promise
- .all(promises)
- .then((): ResponseDTO =>
- {
- return new ResponseDTO(name, response);
- });
- });
+ if (request_object.callback) {
+ const promises: Promise[]|void>[] = [];
+ promises.push(callback(
+ request_object.callback, response
+ ));
+
+ await Promise.all(promises);
}
-}
\ No newline at end of file
+
+ 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
index a60fa97..32f13e5 100644
--- a/src/infrastructure/service/JsonService.ts
+++ b/src/infrastructure/service/JsonService.ts
@@ -1,114 +1,62 @@
-import { JsonRepository } from "../repository/JsonRepository";
-import { Callback } from "../../domain/callback/Callback";
+import { execute as jsonRepository } from "../repository/JsonRepository";
+import { execute as callback } from "../../domain/callback/Callback";
import { ResponseDTO } from "../dto/ResponseDTO";
-import { parser } from "../../application/variable/Parser";
import { cache } from "../../application/variable/Cache";
-
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- callback?: string | string[];
- method?: string;
- body?: object;
- headers?: HeadersInit;
-}
+import { RequestImpl } from "src/interface/RequestImpl";
/**
- * JSON取得時のロジッククラス
- * Logic class for JSON acquisition
+ * @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.
*
- * @class
- * @memberof infrastructure.service
+ * @param {object} request_object
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class JsonService
+export const execute = async (request_object: RequestImpl): Promise =>
{
- private readonly _$repository: JsonRepository;
- private readonly _$callback: Callback;
-
- /**
- * @constructor
- * @public
- */
- constructor ()
- {
- /**
- * @type {JsonRepository}
- * @private
- */
- this._$repository = new JsonRepository();
-
- /**
- * @type {Callback}
- * @private
- */
- this._$callback = new Callback();
+ if (!request_object.name) {
+ throw new Error("`name` must be set for json requests.");
}
/**
- * @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} object
- * @return {Promise}
- * @method
- * @public
+ * キャッシュを利用する場合はキャッシュデータをチェック
+ * Check cache data if cache is used
*/
- execute (object: Object): Promise
- {
- /**
- * キャッシュを利用する場合はキャッシュデータをチェック
- * Check cache data if cache is used
- */
- if (object.cache && object.name) {
-
- const name: string = parser.execute(object.name);
- if (cache.size && cache.has(name)) {
+ if (request_object.cache) {
+ if (cache.size && cache.has(request_object.name)) {
- const value: any = cache.get(name);
+ const value: any = cache.get(request_object.name);
+ if (request_object.callback) {
const promises: Promise[]|void>[] = [];
- if (object.callback) {
- promises.push(this._$callback.execute(
- object.callback, value
- ));
- }
+ promises.push(callback(
+ request_object.callback, value
+ ));
- return Promise
- .all(promises)
- .then((): ResponseDTO =>
- {
- return new ResponseDTO(name, value);
- });
+ await Promise.all(promises);
}
+
+ return new ResponseDTO(request_object.name, value);
}
+ }
- return this
- ._$repository
- .execute(object)
- .then((response: JSON) =>
- {
- const name: string = parser.execute(object.name);
- if (object.cache && object.name) {
- cache.set(name, response);
- }
+ const response: any = await jsonRepository(request_object);
- const promises: Promise[]|void>[] = [];
- if (object.callback) {
- promises.push(this._$callback.execute(
- object.callback, response
- ));
- }
+ 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
+ ));
- return Promise
- .all(promises)
- .then((): ResponseDTO =>
- {
- return new ResponseDTO(name, response);
- });
- });
+ await Promise.all(promises);
}
-}
\ No newline at end of file
+
+ 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
index 77fa84c..f411534 100644
--- a/src/infrastructure/usecase/RequestUseCase.ts
+++ b/src/infrastructure/usecase/RequestUseCase.ts
@@ -1,112 +1,44 @@
-import { RequestType } from "../constant/RequestType";
-import { ContentService } from "../service/ContentService";
-import { CustomService } from "../service/CustomService";
-import { JsonService } from "../service/JsonService";
-import { Callback } from "../../domain/callback/Callback";
-import { RequestParser } from "../../domain/parser/RequestParser";
-import { parser } from "../../application/variable/Parser";
+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";
-
-interface Object {
- type: string;
- name: string;
- path: string;
- cache?: boolean;
- class: string;
- access: string;
- method: string;
- callback?: string | string[];
-}
+import type { RequestImpl } from "src/interface/RequestImpl";
/**
- * ページの切り替え時の外部リクエストクラス
- * External request class when switching pages
+ * @description Routing設定で指定したタイプへリクエストを実行
+ * Execute requests to the type specified in Routing settings
*
- * @class
- * @memberof infrastructure.usecase
+ * @param {string} name
+ * @return {Promise}
+ * @method
+ * @public
*/
-export class RequestUseCase
+export const execute = (name: string): Promise[] =>
{
- private readonly _$callback: Callback;
- private readonly _$contentService: ContentService;
- private readonly _$customService: CustomService;
- private readonly _$jsonService: JsonService;
- private readonly _$requestParser: RequestParser;
-
- /**
- * @constructor
- * @public
- */
- constructor ()
- {
- /**
- * @type {Callback}
- * @private
- */
- this._$callback = new Callback();
-
- /**
- * @type {ContentService}
- * @private
- */
- this._$contentService = new ContentService();
-
- /**
- * @type {CustomService}
- * @private
- */
- this._$customService = new CustomService();
-
- /**
- * @type {JsonService}
- * @private
- */
- this._$jsonService = new JsonService();
+ const promises: Promise[] = [];
+ const requests: RequestImpl[] = requestParser(name);
+ for (let idx: number = 0; idx < requests.length; ++idx) {
- /**
- * @type {RequestParser}
- * @private
- */
- this._$requestParser = new RequestParser();
- }
-
- /**
- * @description Routing設定で指定したタイプへリクエストを実行
- * Execute requests to the type specified in Routing settings
- *
- * @param {string} name
- * @return {Promise}
- * @method
- * @public
- */
- execute (name: string): Promise[]
- {
- const promises: Promise[] = [];
- const requests: Object[] = this._$requestParser.execute(name);
- for (let idx: number = 0; idx < requests.length; ++idx) {
-
- const object: Object = requests[idx];
- switch (parser.execute(object.type)) {
+ const requestObject: RequestImpl = requests[idx];
+ switch (requestObject.type) {
- case RequestType.CUSTOM:
- promises.push(
- this._$customService.execute(object)
- );
- break;
+ case "custom":
+ promises.push(customService(requestObject));
+ break;
- case RequestType.JSON:
- promises.push(
- this._$jsonService.execute(object)
- );
- break;
+ case "json":
+ promises.push(jsonService(requestObject));
+ break;
- case RequestType.CONTENT:
- promises.push(this._$contentService.execute(object));
- break;
+ case "content":
+ promises.push(contentService(requestObject));
+ break;
- }
+ default:
+ break;
}
-
- return promises;
}
-}
\ No newline at end of file
+
+ return promises;
+};
\ No newline at end of file
diff --git a/src/interface/ConfigImpl.ts b/src/interface/ConfigImpl.ts
index e877e9b..ebbf461 100644
--- a/src/interface/ConfigImpl.ts
+++ b/src/interface/ConfigImpl.ts
@@ -1,6 +1,5 @@
import { StageImpl } from "./StageImpl";
import { RoutingImpl } from "./RoutingImpl";
-import { LoadingImpl } from "./LoadingImpl";
import { GotoViewImpl } from "./GotoViewImpl";
interface BaseConfigImpl {
@@ -14,6 +13,8 @@ export interface ConfigImpl extends BaseConfigImpl {
[key: string]: RoutingImpl
};
spa: boolean;
- loading?: LoadingImpl;
+ loading?: {
+ callback: string;
+ };
gotoView?: GotoViewImpl;
}
\ No newline at end of file
diff --git a/src/interface/LoadingImpl.ts b/src/interface/LoadingImpl.ts
index 64e0859..12a8926 100644
--- a/src/interface/LoadingImpl.ts
+++ b/src/interface/LoadingImpl.ts
@@ -1,3 +1,4 @@
export interface LoadingImpl {
- callback: string;
+ start: Function;
+ end: Function;
}
\ No newline at end of file
diff --git a/src/interface/QueryObjectImpl.ts b/src/interface/QueryObjectImpl.ts
new file mode 100644
index 0000000..00d3021
--- /dev/null
+++ b/src/interface/QueryObjectImpl.ts
@@ -0,0 +1,4 @@
+export interface QueryObjectImpl {
+ name: string;
+ queryString: string;
+}
\ No newline at end of file
diff --git a/src/interface/RequestImpl.ts b/src/interface/RequestImpl.ts
index 347f7d1..9b5c80b 100644
--- a/src/interface/RequestImpl.ts
+++ b/src/interface/RequestImpl.ts
@@ -9,4 +9,6 @@ export interface RequestImpl {
class?: string;
access?: string;
method?: string;
+ headers?: HeadersInit;
+ body?: object;
}
\ No newline at end of file
diff --git a/src/interface/RoutingImpl.ts b/src/interface/RoutingImpl.ts
index 4884e9e..4e6b886 100644
--- a/src/interface/RoutingImpl.ts
+++ b/src/interface/RoutingImpl.ts
@@ -3,4 +3,5 @@ import { RequestImpl } from "./RequestImpl";
export interface RoutingImpl {
private?: boolean;
requests?: RequestImpl[];
+ redirect?: string;
}
\ No newline at end of file
diff --git a/src/view/ViewModel.ts b/src/view/ViewModel.ts
index 1526210..78996a6 100644
--- a/src/view/ViewModel.ts
+++ b/src/view/ViewModel.ts
@@ -32,6 +32,7 @@ export class ViewModel
* @method
* @public
*/
+ // @ts-ignore
// eslint-disable-next-line no-unused-vars,no-empty-function
unbind (view: View): void {}
@@ -48,7 +49,8 @@ export class ViewModel
{
return new Promise((resolve) =>
{
- requestAnimationFrame((): void => {
+ requestAnimationFrame((): void =>
+ {
return resolve(view);
});
});
diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json
index 7383046..16a9068 100644
--- a/tsconfig.eslint.json
+++ b/tsconfig.eslint.json
@@ -6,6 +6,7 @@
],
"exclude": [
"node_modules",
+ "src/**/*.test.ts",
"dist"
]
}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 1cb4ad3..25304a3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,21 +1,36 @@
{
"compilerOptions": {
- "strict": true,
- "resolveJsonModule": true,
- "esModuleInterop": true,
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "Bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+
"declaration": true,
- "allowJs": true,
- "target": "es6",
- "module": "es6",
- "moduleResolution": "node",
"baseUrl": ".",
- "outDir": "./dist/"
+ "outDir": "./dist",
+
+ "types": [
+ "vitest/globals"
+ ]
},
"include": [
"src/**/*.ts",
- "src/index.ts",
"@types/**/*.ts"
],
- "exclude": ["node_modules"]
+ "exclude": [
+ "node_modules",
+ "src/**/*.test.ts"
+ ]
}
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..6d71f23
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,11 @@
+///
+
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ "test": {
+ "globals": true,
+ "environment": "jsdom",
+ "include": ["src/**/*.test.ts"]
+ }
+});
\ No newline at end of file
diff --git a/webpack.config.js b/webpack.config.js
deleted file mode 100644
index 23e1d8f..0000000
--- a/webpack.config.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const path = require("path");
-const ESLintPlugin = require("eslint-webpack-plugin");
-
-module.exports = {
- "mode": "production",
- "entry": path.resolve(__dirname, "src/index.ts"),
- "output": {
- "filename": "next2d-framework.js",
- "path": path.resolve(__dirname, "dist")
- },
- "plugins": [
- new ESLintPlugin({
- "extensions": [".ts", ".js"],
- "exclude": "node_modules",
- "fix": true
- })
- ],
- "module": {
- "rules": [
- {
- "test": /\.ts$/,
- "use": "ts-loader",
- "exclude": /node_modules/
- }
- ]
- },
- "resolve": {
- "alias": {
- "@": path.resolve(__dirname, "src")
- },
- "extensions": [".ts", ".js"]
- },
- "devServer": {
- "static": {
- "directory": path.resolve(__dirname, "dist")
- },
- "compress": false,
- "open": true
- }
-};