@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.
@@ -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,2 @@
1
+ declare const StateField: PropertyDecorator;
2
+ export default StateField;
@@ -0,0 +1,3 @@
1
+ import type GeneralizedView from "../GeneralizedView";
2
+ declare const View: (generalizedView: GeneralizedView) => ClassDecorator;
3
+ export default View;
@@ -0,0 +1,6 @@
1
+ type GeneralizedView = {
2
+ onStateFieldsChangedHandlers: Map<string, Set<(currentValue: unknown) => unknown>>;
3
+ methodsReferences: Map<string, (handler: () => unknown) => unknown>;
4
+ generateInitialDOM: () => Array<Element>;
5
+ };
6
+ export default GeneralizedView;
@@ -0,0 +1,5 @@
1
+ import type Component from "../Component";
2
+ export default function initializeFrontendApplication({ mountingPointSelector, rootComponent: RootComponent }: Readonly<{
3
+ mountingPointSelector: string;
4
+ rootComponent: new () => Component;
5
+ }>): void;
@@ -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
+ }