@yamato-daiwa/universal-reactive 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Distributable/Component.d.ts +9 -0
- package/Distributable/Decorators/StateField.d.ts +2 -0
- package/Distributable/Decorators/View.d.ts +3 -0
- package/Distributable/GeneralizedView.d.ts +6 -0
- package/Distributable/Tools/initializeFrontendApplication.d.ts +5 -0
- package/Distributable/index.d.ts +5 -0
- package/Distributable/index.js +1 -0
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/package.json +43 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type GeneralizedView from "./GeneralizedView";
|
|
2
|
+
export default abstract class Component {
|
|
3
|
+
/** @description Initialized by `View` decorator. */
|
|
4
|
+
readonly $$mount: (mountingPoint: Element) => void;
|
|
5
|
+
/** @description Initialized by `View` decorator. */
|
|
6
|
+
protected readonly $$DOM: ReadonlyArray<Element>;
|
|
7
|
+
/** @description Initialized by `View` decorator. */
|
|
8
|
+
protected readonly $$view: GeneralizedView;
|
|
9
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { default as GeneralizedView } from "./GeneralizedView";
|
|
2
|
+
export { default as Component } from "./Component";
|
|
3
|
+
export { default as initializeFrontendApplication } from "./Tools/initializeFrontendApplication";
|
|
4
|
+
export { default as StateField } from "./Decorators/StateField";
|
|
5
|
+
export { default as View } from "./Decorators/View";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class e{}function t(e){return void 0===e}function n(e){return"string"==typeof e}function r(e){return"string"==typeof e&&e.length>0}function o(e,{mustConsiderNaN_AsNumber:t}){return"number"==typeof e&&(!isNaN(e)||t)}function i(e){return"bigint"==typeof e}function a(e){return"boolean"==typeof e}function c(e){return void 0!==e}function s(e){return null===e}function l(e){return null!==e}class u{static DOUBLE_SPACE=" ";#e=0;get currentIndentationMultiplier(){return this.#e}incrementIndent(){this.#e++}decrementIndent(){this.#e--}insertIndent(){return u.DOUBLE_SPACE.repeat(this.#e)}incrementIndentAndInsert(){return this.incrementIndent(),this.insertIndent()}decrementIndentAndInsert(){return this.decrementIndent(),this.insertIndent()}insertIncrementedIndentWithoutUpdatingOfIndentationMultiplier(){return u.DOUBLE_SPACE.repeat(this.#e+1)}addCurrentIndentationToEachLineOf(e){return function(e){return e.split("\n")}(e).map(e=>`${this.insertIndent()}${e}`).join("\n")}}function m(e){const t=Array.from(e);return t.pop(),t.join("")}class d{static stringifyAndFormat(e,t){switch(typeof e){case"string":return`"${e}"`;case"symbol":case"number":return e.toString();case"bigint":return`${e.toString()}n`;case"boolean":return`${e}`;case"undefined":return"undefined";case"function":return["String","Number","BigInt","Boolean","Array"].includes(e.name)?`[${e.name}]`:e.toString();case"object":return e instanceof Error||e instanceof RegExp?e.toString():null===e?"null":e instanceof Array?d.stringifyAsArray(e,t):e instanceof Set?d.stringifyAndFormatSet(e,t):e instanceof Map?d.stringifyAndFormatMap(e,t):e instanceof Date?e.toISOString():d.stringifyAsPlainObject(e,t)}}static stringifyAsArray(e,t=new u){let n="[";t.incrementIndent();for(const r of e)n=n+`\n${t.insertIndent()}`+`${d.stringifyAndFormat(r,t)},`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAndFormatSet(e,t=new u){let n=`Set(${e.size}) [`;t.incrementIndent();for(const r of e)n=n+`\n${t.insertIndent()}`+`${d.stringifyAndFormat(r,t)},`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAndFormatMap(e,t=new u){let n=`Map(${e.size}) [`;t.incrementIndent();for(const[r,o]of e.entries())n=n+`\n${t.insertIndent()}[\n`+t.incrementIndentAndInsert()+`${d.stringifyAndFormat(r,t)},\n`+t.insertIndent()+`${d.stringifyAndFormat(o,t)}\n`+`${t.decrementIndentAndInsert()}],`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}]`}static stringifyAsPlainObject(e,t=new u){let n="{";t.incrementIndent();for(const[r,o]of Object.entries(e))n=n+`\n${t.insertIndent()}`+`${r}: ${d.stringifyAndFormat(o,t)},`;return n=m(n),t.decrementIndent(),`${n}\n${t.insertIndent()}}`}}function g(e){return d.stringifyAndFormat(e)}const p={badgesDefaultTitles:{error:"Error",warning:"Warning",success:"Success",info:"Info",debug:"Debug",generic:"Common"},errorType:"Error type",occurrenceLocation:"Occurrence location",caughtError:"Caught error",innerError:"Inner error",appendedData:"Appended data"};class f{static implementation=null;static localization=p;static setImplementation(e){return f.implementation=e,f}static setLocalization(e){return f.localization=e,f}static throwErrorWithFormattedMessage(e,t={}){if(c(f.implementation?.throwErrorWithFormattedMessage))return f.implementation.throwErrorWithFormattedMessage(e,t);let n;c(e.innerError)&&(n=g(e.innerError),e.innerError instanceof Error&&r(e.innerError.stack)&&(n=e.innerError.stack.includes(n)?e.innerError.stack:`${n}\n${e.innerError.stack}`));const o=f.generateFormattedErrorFromThrownErrorLog(e,n);if("errorInstance"in e)throw e.errorInstance.message=o,e.errorInstance;const i=new Error(o);throw i.name=e.errorType,!0===t.mustLogErrorBeforeThrowing&&f.logErrorLikeMessage({title:i.name,description:i.message}),i}static logError(e){l(f.implementation)?f.implementation.logError(e):n(e)?console.error(e):!1!==e.mustOutputIf&&console.error(f.formatErrorLog(e))}static logErrorLikeMessage(e){l(f.implementation)?f.implementation.logErrorLikeMessage(e):n(e)?console.error(e):!1!==e.mustOutputIf&&console.error(f.formatGenericLog(e,f.localization.badgesDefaultTitles.error))}static logWarning(e){l(f.implementation)?f.implementation.logWarning(e):n(e)?console.warn(e):!1!==e.mustOutputIf&&console.warn(f.formatGenericLog(e,f.localization.badgesDefaultTitles.warning))}static logInfo(e){l(f.implementation)?f.implementation.logInfo(e):n(e)?console.info(e):!1!==e.mustOutputIf&&console.info(f.formatGenericLog(e,f.localization.badgesDefaultTitles.info))}static logSuccess(e){l(f.implementation)?f.implementation.logSuccess(e):n(e)?console.info(e):!1!==e.mustOutputIf&&console.info(f.formatGenericLog(e,f.localization.badgesDefaultTitles.success))}static logDebug(e){l(f.implementation)?f.implementation.logDebug(e):n(e)||o(e,{mustConsiderNaN_AsNumber:!0})||i(e)||a(e)||s(e)||t(e)?console.debug(e):!1!==e.mustOutputIf&&console.debug(f.formatGenericLog(e,f.localization.badgesDefaultTitles.debug))}static logGeneric(e){l(f.implementation)?f.implementation.logGeneric(e):n(e)||o(e,{mustConsiderNaN_AsNumber:!0})||i(e)||a(e)||s(e)||t(e)?console.log(e):!1!==e.mustOutputIf&&console.log(f.formatGenericLog(e,f.localization.badgesDefaultTitles.generic))}static logPromiseError(e){l(f.implementation)&&c(f.implementation.logPromiseError)?f.implementation.logPromiseError(e):console.error(e)}static highlightText(e){return l(f.implementation)?f.implementation.highlightText(e):e}static generateFormattedErrorFromThrownErrorLog(e,t){return[e.title,...!0===e.compactLayout?[" "]:["\n"],..."errorInstance"in e?[e.errorInstance.message]:[e.description],`\n\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`,...c(t)?[`\n\n${f.localization.innerError}:\n${t}`]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[],"\n"].join("")}static formatErrorLog(e){return[...f.generateBadgeIfMust(e.badge,f.localization.badgesDefaultTitles.error),e.title,...!0===e.compactLayout?[" "]:["\n"],e.description,`\n\n${f.localization.errorType}: ${e.errorType}`,`\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`,...c(e.caughtError)?[`\n\n${f.localization.caughtError}:\n${g(e.caughtError)}`+(e.caughtError instanceof Error&&r(e.caughtError.stack)?`\n${e.caughtError.toString()}\n${e.caughtError.stack}`:"")]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[]].join("")}static formatGenericLog(e,t){return[...f.generateBadgeIfMust(e.badge,t),e.title,...!0===e.compactLayout?[" "]:["\n"],e.description,..."occurrenceLocation"in e?[`\n${f.localization.occurrenceLocation}: ${e.occurrenceLocation}`]:[],...c(e.additionalData)?[`\n\n${f.localization.appendedData}:\n${g(e.additionalData)}`]:[]].join("")}static generateBadgeIfMust(e,t){return!1===e?[]:[`[ ${e?.customText??t} ] `]}}const E=f,h={defaultTitle:"DOM Element not Found",generateDescription:({selector:e})=>`The DOM element with selector: ${e} not found.`};class I extends Error{static NAME="DOM_ElementRetrievingFailedError";static localization=h;constructor(e){super(),this.name=I.NAME,this.message="customMessage"in e?e.customMessage:I.localization.generateDescription(e)}}const $=I,y={defaultTitle:"Unexpected Event Occurred"};class b extends Error{static NAME="UnexpectedEventError";static localization=y;constructor(e){super(),this.name=b.NAME,this.message=e}}const M=b;function D({mountingPointSelector:e,rootComponent:n}){(new n).$$mount(function(e){let n;if(t(e.contextElement))n=document;else if("selector"in e.contextElement){const t=document.querySelectorAll(e.contextElement.selector);0===t.length?E.throwErrorWithFormattedMessage({errorInstance:new $({customMessage:`The context element has not been found by the selector "${e.contextElement.selector}".`}),title:$.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}):t.length>1&&E.logError({errorType:M.NAME,title:M.localization.defaultTitle,description:`Multiple elements are corresponding to context element selector "${e.contextElement.selector}" while the context element must be single.`,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),n=t[0]}else n=e.contextElement;const r=e.selector,o=n.querySelectorAll(r);0===o.length&&E.throwErrorWithFormattedMessage({errorInstance:new $({selector:r}),title:$.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),o.length>1&&E.logError({errorType:M.NAME,title:M.localization.defaultTitle,description:`Contrary to expectations, ${o.length} elements has been found for the selector "${r}". First one will be picked.`,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"});const i=o[0];return t(e.expectedDOM_ElementSubtype)||i instanceof e.expectedDOM_ElementSubtype||E.throwErrorWithFormattedMessage({errorInstance:new M(`Contrary to expectations, the picked element in not instance of "${e.expectedDOM_ElementSubtype.name}".`),title:M.localization.defaultTitle,occurrenceLocation:"getExpectedToBeSingleDOM_Element(compoundParameter)"}),i}({selector:e,contextElement:document}))}const A=(e,n)=>{let r=e[n];Object.defineProperty(e,n,{get:()=>r,set(e){if(e!==r||"object"==typeof e||"function"==typeof e||"object"==typeof r||"function"==typeof r){r=e;for(const e of function(e,n){const r=e.get(n);return t(r)&&E.throwErrorWithFormattedMessage({errorInstance:new M(`Contrary to expectations, there is no pair with key "${String(n)}" in target map.`),title:M.localization.defaultTitle,occurrenceLocation:"getExpectedToBeExistingMapValue(targetMap, targetKey)"}),r}(this.$$view.onStateFieldsChangedHandlers,n))e(r)}},enumerable:!0,configurable:!0})},w=e=>t=>{const n=t;Object.defineProperty(n.prototype,"$$view",{value:e,writable:!1,configurable:!1,enumerable:!1});const r=e.generateInitialDOM();Object.defineProperty(n.prototype,"$$DOM",{value:r,writable:!1,configurable:!1,enumerable:!1}),Object.defineProperty(n.prototype,"$$mount",{value(e){e.replaceWith(...r)},writable:!1,configurable:!1,enumerable:!1});for(const[t,r]of e.methodsReferences.entries())r(n.prototype[t].bind(n.prototype));return t};export{e as Component,A as StateField,w as View,D as initializeFrontendApplication};
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-present, Yamato Daiwa Co., Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Yamato Daiwa Universal Reactive
|
|
2
|
+
|
|
3
|
+
<figure align="center">
|
|
4
|
+
<img
|
|
5
|
+
src="https://github.com/user-attachments/assets/c129e15c-4969-4178-8213-c0acfd2b7b47"
|
|
6
|
+
alt="The decrative image shows that the library is in development."
|
|
7
|
+
>
|
|
8
|
+
<figcaption style="text-align: center;">The library is in development. See the "Roadmap" section for progress.</figcaption>
|
|
9
|
+
</figure>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## What is Being Developed
|
|
13
|
+
|
|
14
|
+
The object-oriented programming-based library for the frontend Web+ development alternative to React, Vue, Svelte and
|
|
15
|
+
the like.
|
|
16
|
+
|
|
17
|
+
No plans to position is as a framework because it is intended to be the tool taking care of typical frontend development
|
|
18
|
+
tasks without stealing too much attention and forcing of specific architecture, naming and directories structure.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## Features (May be Pros of Cons Depending on Your Preferences)
|
|
22
|
+
|
|
23
|
+
+ Class-based components. No functional API planned.
|
|
24
|
+
+ [Pug](https://pugjs.org/api/getting-started.html) is the only language for templates. No plaing HTML support planned.
|
|
25
|
+
+ No new file names extension like `.vue` or `.jsx`.
|
|
26
|
+
+ No new syntaxes like Vue single file components or JSX. Just plain Pug and TypeScript.
|
|
27
|
+
+ Project building tool like Webpack is required.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Planned
|
|
31
|
+
|
|
32
|
+
The sequence may be changed during the development.
|
|
33
|
+
|
|
34
|
+
+ [ ] Conditional rendering
|
|
35
|
+
+ [ ] Iterative rendering
|
|
36
|
+
+ [ ] Nested components
|
|
37
|
+
+ [ ] Routing
|
|
38
|
+
+ [ ] Shared state
|
|
39
|
+
+ [ ] SSR
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## Quick Tutorials for React/Vue/Svelte Experiencers
|
|
43
|
+
### Basic ~~"Hello, world"~~ Counter Application
|
|
44
|
+
#### Code
|
|
45
|
+
##### "Counter.ydfr.pug" — The Component Template
|
|
46
|
+
|
|
47
|
+
```pug
|
|
48
|
+
samp= $currentValue
|
|
49
|
+
|
|
50
|
+
.Counter-ActionBar
|
|
51
|
+
|
|
52
|
+
button(
|
|
53
|
+
type="button"
|
|
54
|
+
@click=onClickIncrementingButton
|
|
55
|
+
) Increment
|
|
56
|
+
|
|
57
|
+
button(
|
|
58
|
+
type="button"
|
|
59
|
+
@click=onClickDecrementingButton
|
|
60
|
+
) Decrement
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The YDUR components templates is been defined by [Pug](https://github.com/pugjs/pug), the template language.
|
|
64
|
+
No plans to support HTML.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
##### Counter.ts — The Component Logic
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import * as YDFR from "@yamato-daiwa/universal-reactive";
|
|
71
|
+
import componentTemplate from "./Counter.ydur.pug";
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@YDFR.View(componentTemplate)
|
|
75
|
+
export default class Counter extends YDFR.Component {
|
|
76
|
+
|
|
77
|
+
@YDFR.StateField
|
|
78
|
+
public $currentValue: number = 0;
|
|
79
|
+
|
|
80
|
+
public onClickIncrementingButton(): void {
|
|
81
|
+
this.$currentValue++;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public onClickDecrementingButton(): void {
|
|
85
|
+
this.$currentValue--;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
+ The component logic is the plain TypeScript class with decorators.
|
|
92
|
+
Besides its main role, you can use it as the plain TypeScript classes, for example, define
|
|
93
|
+
the public static members and call them from outside (when it makes sense).
|
|
94
|
+
* To import `componentTemplate` from Pug file correctly, you need the appropriate plugin for you project building
|
|
95
|
+
system.
|
|
96
|
+
Currently, the [Webpack loader](https://www.npmjs.com/package/@yamato-daiwa/universal-reactive-webpack-loader) is available.
|
|
97
|
+
The value of `componentTemplate` is not the string with HTML code — the YDUR templates compiler builds the JavaScript
|
|
98
|
+
object called "View" based on Pug code.
|
|
99
|
+
Such an approach is Svelte-like, one advantage of it is better performance than DOM diffing as in React.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
##### index.ts — The Entry Point
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import * as YDFR from "@yamato-daiwa/universal-reactive";
|
|
106
|
+
import Counter from "./GUI_Components/Counter";
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
YDFR.initializeFrontendApplication({
|
|
110
|
+
mountingPointSelector: "#APPLICATION_ROOT",
|
|
111
|
+
rootComponent: Counter
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
You need at least one component to create the application instance.
|
|
116
|
+
Once it defined, the application may created by one function.
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yamato-daiwa/universal-reactive",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "OOP-based library for frontend development.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"frontend"
|
|
7
|
+
],
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "Takeshi Tokugawa",
|
|
10
|
+
"email": "tokugawa.takesi@gmail.com"
|
|
11
|
+
},
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/TokugawaTakeshi/Yamato-Daiwa-Universal-Reactive",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/TokugawaTakeshi/Yamato-Daiwa-Universal-Reactive.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/TokugawaTakeshi/Yamato-Daiwa-Universal-Reactive/issues",
|
|
20
|
+
"email": "tokugawa.takesi@gmail.com"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"Distributable"
|
|
24
|
+
],
|
|
25
|
+
"module": "./Distributable/index.js",
|
|
26
|
+
"types": "./Distributable/index.d.ts",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@yamato-daiwa/es-extensions": "1.8.2",
|
|
29
|
+
"@yamato-daiwa/es-extensions-browserjs": "1.8.2"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@yamato-daiwa/automation": "0.8.0",
|
|
33
|
+
"@yamato-daiwa/frontend": "2.0.0-beta.11",
|
|
34
|
+
"@yamato-daiwa/style_guides": "0.10.1",
|
|
35
|
+
"rimraf": "6.0.1",
|
|
36
|
+
"typescript": "5.9.3"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"Lint": "eslint",
|
|
40
|
+
"Run Tests": "yda build --selectiveExecution Tests --mode LOCAL_DEVELOPMENT",
|
|
41
|
+
"Rebuild Distributable": "rimraf Distributable && yda build --selectiveExecution Distributable --mode PRODUCTION && tsc --project tsconfig.declarations.json --declaration --emitDeclarationOnly --outDir Distributable"
|
|
42
|
+
}
|
|
43
|
+
}
|