@qubit-ltd/common-decorator 3.8.10 → 3.9.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/README.md +633 -8
- package/README.zh_CN.md +432 -6
- package/dist/common-decorator.cjs +11212 -4724
- package/dist/common-decorator.cjs.map +1 -1
- package/dist/common-decorator.min.cjs +1 -1
- package/dist/common-decorator.min.cjs.map +1 -1
- package/dist/common-decorator.min.mjs +1 -1
- package/dist/common-decorator.min.mjs.map +1 -1
- package/dist/common-decorator.mjs +11215 -4727
- package/dist/common-decorator.mjs.map +1 -1
- package/doc/api/DefaultAssignmentOptions.html +2 -2
- package/doc/api/DefaultOptions.html +2 -2
- package/doc/api/DefaultToJsonOptions.html +2 -2
- package/doc/api/Enum.html +2 -2
- package/doc/api/Model.html +2 -2
- package/doc/api/Page.html +2 -2
- package/doc/api/global.html +675 -943
- package/doc/api/index.html +610 -10
- package/doc/common-decorator.min.visualization.html +1 -1
- package/doc/common-decorator.visualization.html +1 -1
- package/package.json +34 -29
package/doc/api/index.html
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
<label for="nav-trigger" class="overlay"></label>
|
|
25
25
|
|
|
26
26
|
<nav>
|
|
27
|
-
<li class="nav-link nav-home-link"><a href="index.html">Home</a></li><li class="nav-heading">Classes</li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="DefaultAssignmentOptions.html">DefaultAssignmentOptions</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="DefaultOptions.html">DefaultOptions</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.get">get</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.merge">merge</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.reset">reset</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.set">set</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="DefaultToJsonOptions.html">DefaultToJsonOptions</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Page.html">Page</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Page.html#assign">assign</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Page.html#.getFrom">getFrom</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Page.html#.newEmpty">newEmpty</a></span></li><li class="nav-heading">Namespaces</li><li class="nav-heading"><span class="nav-item-type type-namespace">N</span><span class="nav-item-name"><a href="Enum.html">Enum</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.has">Class.has</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.hasCode">Class.hasCode</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.hasName">Class.hasName</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.hasValue">Class.hasValue</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.of">Class.of</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.ofCode">Class.ofCode</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.ofName">Class.ofName</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.ofValue">Class.ofValue</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.values">Class.values</a></span></li><li class="nav-heading"><span class="nav-item-type type-namespace">N</span><span class="nav-item-name"><a href="Model.html">Model</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#assign">assign</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#clear">clear</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#clone">clone</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#equals">equals</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#generateId">generateId</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#isEmpty">isEmpty</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#normalize">normalize</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#normalizeField">normalizeField</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#toJSON">toJSON</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#toJsonString">toJsonString</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#validate">validate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#validateField">validateField</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.create">Class.create</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.createArray">Class.createArray</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.createPage">Class.createPage</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.isNullishOrEmpty">Class.isNullishOrEmpty</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.parseJsonString">Class.parseJsonString</a></span></li><li class="nav-heading"><a href="global.html">Globals</a></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#ElementType">ElementType</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Enumerable">Enumerable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Label">Label</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#NameField">NameField</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#NonEmpty">NonEmpty</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#NonEnumerable">NonEnumerable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Normalizable">Normalizable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Nullable">Nullable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Payload">Payload</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Readonly">Readonly</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Timeout">Timeout</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Type">Type</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Validatable">Validatable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#assign">assign</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#create">create</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createArray">createArray</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createPage">createPage</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#defaultNormalizer">defaultNormalizer</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#defaultValidator">defaultValidator</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#enumNormalizer">enumNormalizer</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#isEnumClass">isEnumClass</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#isEnumerator">isEnumerator</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#isValidPageSource">isValidPageSource</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#normalize">normalize</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#stringifyId">stringifyId</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#toJSON">toJSON</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#toJsonString">toJsonString</a></span></li>
|
|
27
|
+
<li class="nav-link nav-home-link"><a href="index.html">Home</a></li><li class="nav-heading">Classes</li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="DefaultAssignmentOptions.html">DefaultAssignmentOptions</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="DefaultOptions.html">DefaultOptions</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.get">get</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.merge">merge</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.reset">reset</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="DefaultOptions.html#.set">set</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="DefaultToJsonOptions.html">DefaultToJsonOptions</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Page.html">Page</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Page.html#assign">assign</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Page.html#.getFrom">getFrom</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Page.html#.newEmpty">newEmpty</a></span></li><li class="nav-heading">Namespaces</li><li class="nav-heading"><span class="nav-item-type type-namespace">N</span><span class="nav-item-name"><a href="Enum.html">Enum</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.has">Class.has</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.hasCode">Class.hasCode</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.hasName">Class.hasName</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.hasValue">Class.hasValue</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.of">Class.of</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.ofCode">Class.ofCode</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.ofName">Class.ofName</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.ofValue">Class.ofValue</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Enum.html#.Class.values">Class.values</a></span></li><li class="nav-heading"><span class="nav-item-type type-namespace">N</span><span class="nav-item-name"><a href="Model.html">Model</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#assign">assign</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#clear">clear</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#clone">clone</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#equals">equals</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#generateId">generateId</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#isEmpty">isEmpty</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#normalize">normalize</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#normalizeField">normalizeField</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#toJSON">toJSON</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#toJsonString">toJsonString</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#validate">validate</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#validateField">validateField</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.create">Class.create</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.createArray">Class.createArray</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.createPage">Class.createPage</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.isNullishOrEmpty">Class.isNullishOrEmpty</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="Model.html#.Class.parseJsonString">Class.parseJsonString</a></span></li><li class="nav-heading"><a href="global.html">Globals</a></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#ElementType">ElementType</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Label">Label</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#NameField">NameField</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#NonEmpty">NonEmpty</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Normalizable">Normalizable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Nullable">Nullable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Readonly">Readonly</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Timeout">Timeout</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Type">Type</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#Validatable">Validatable</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#assign">assign</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#create">create</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createArray">createArray</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createDeferredReadonlyInitializer">createDeferredReadonlyInitializer</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createImmediateReadonlyInitializer">createImmediateReadonlyInitializer</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#createPage">createPage</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#defaultNormalizer">defaultNormalizer</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#defaultValidator">defaultValidator</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#enumNormalizer">enumNormalizer</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#isEnumClass">isEnumClass</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#isEnumerator">isEnumerator</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#isValidPageSource">isValidPageSource</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#normalize">normalize</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#stringifyId">stringifyId</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#toJSON">toJSON</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#toJsonString">toJsonString</a></span></li>
|
|
28
28
|
</nav>
|
|
29
29
|
|
|
30
30
|
<div id="main">
|
|
@@ -56,8 +56,25 @@
|
|
|
56
56
|
<a href="https://coveralls.io/github/Haixing-Hu/js-common-decorator?branch=master"><img src="https://coveralls.io/repos/github/Haixing-Hu/js-common-decorator/badge.svg?branch=master" alt="Coverage Status"></a></p>
|
|
57
57
|
<p><a href="https://npmjs.com/package/@qubit-ltd/common-decorator">@qubit-ltd/common-decorator</a> is a JavaScript library of common decorators,
|
|
58
58
|
provides decorators to add common methods to domain classes. The library
|
|
59
|
-
supports the most recent (currently
|
|
59
|
+
supports the most recent (currently November 2023)
|
|
60
60
|
<a href="https://github.com/tc39/proposal-decorators">stage 3 proposal of JavaScript decorators</a>.</p>
|
|
61
|
+
<h2>Features</h2>
|
|
62
|
+
<ul>
|
|
63
|
+
<li><strong>Modern Decorator Support</strong>: Compatible with the latest Stage 3 proposal for JavaScript decorators</li>
|
|
64
|
+
<li><strong>Model Enhancement</strong>: <code>@Model</code> decorator adds common methods to domain model classes</li>
|
|
65
|
+
<li><strong>Enum Implementation</strong>: <code>@Enum</code> decorator provides Java-like enumeration capabilities</li>
|
|
66
|
+
<li><strong>Validation Support</strong>: <code>@Validatable</code> decorator enables field validation</li>
|
|
67
|
+
<li><strong>Normalization Support</strong>: <code>@Normalizable</code> decorator enables field normalization</li>
|
|
68
|
+
<li><strong>Type Safety</strong>: <code>@Type</code> and <code>@ElementType</code> decorators for type checking</li>
|
|
69
|
+
<li><strong>Serialization Utilities</strong>: Built-in JSON serialization/deserialization support</li>
|
|
70
|
+
</ul>
|
|
71
|
+
<h2>Installation</h2>
|
|
72
|
+
<pre class="prettyprint source lang-bash"><code># Using npm
|
|
73
|
+
npm install @qubit-ltd/common-decorator
|
|
74
|
+
|
|
75
|
+
# Using yarn
|
|
76
|
+
yarn add @qubit-ltd/common-decorator
|
|
77
|
+
</code></pre>
|
|
61
78
|
<h2><span id="content">Table of Contents</span></h2>
|
|
62
79
|
<ul>
|
|
63
80
|
<li><a href="#usage">Usage</a>
|
|
@@ -1178,13 +1195,13 @@ const opt3 = DefaultOptions.merge('assign', null);
|
|
|
1178
1195
|
expect(opt3.convertNaming).toBe(false);
|
|
1179
1196
|
</code></pre>
|
|
1180
1197
|
<h2><span id="configuration">Configuration</span></h2>
|
|
1181
|
-
<p>This library uses the most recent (currently
|
|
1198
|
+
<p>This library uses the most recent (currently November 2023)
|
|
1182
1199
|
<a href="https://github.com/tc39/proposal-decorators">stage 3 proposal of JavaScript decorators</a>. Therefore, you must configure
|
|
1183
1200
|
<a href="https://babeljs.io/">Babel</a> with <a href="https://babeljs.io/docs/babel-plugin-transform-class-properties">@babel/plugin-transform-class-properties</a> and the
|
|
1184
1201
|
<a href="https://babeljs.io/docs/babel-plugin-proposal-decorators">@babel/plugin-proposal-decorators</a> plugins.</p>
|
|
1185
|
-
<p><strong>NOTE:</strong> To support the <a href="https://github.com/tc39/proposal-decorator-metadata">stage 3 proposal of JavaScript decorator metadata</a
|
|
1186
|
-
the version of the <a href="https://babeljs.io/">Babel</a> plugin <a href="https://babeljs.io/docs/babel-plugin-proposal-decorators">@babel/plugin-proposal-decorators</a>
|
|
1187
|
-
at least <code>7.
|
|
1202
|
+
<p><strong>NOTE:</strong> To support the <a href="https://github.com/tc39/proposal-decorator-metadata">stage 3 proposal of JavaScript decorator metadata</a>
|
|
1203
|
+
at November 2023, the version of the <a href="https://babeljs.io/">Babel</a> plugin <a href="https://babeljs.io/docs/babel-plugin-proposal-decorators">@babel/plugin-proposal-decorators</a>
|
|
1204
|
+
must be at least <code>7.24.0</code>.</p>
|
|
1188
1205
|
<h3><span id="webpack">Bundling with <a href="https://webpack.js.org/">webpack</a></span></h3>
|
|
1189
1206
|
<ol>
|
|
1190
1207
|
<li>Install the required dependencies:<pre class="prettyprint source lang-shell"><code>yarn add @qubit-ltd/common-decorator
|
|
@@ -1200,7 +1217,7 @@ configuration file <code>babelrc.json</code> is as follows:<pre class="prettypri
|
|
|
1200
1217
|
],
|
|
1201
1218
|
"plugins": [
|
|
1202
1219
|
"@babel/plugin-transform-runtime",
|
|
1203
|
-
["@babel/plugin-proposal-decorators", { "version": "2023-
|
|
1220
|
+
["@babel/plugin-proposal-decorators", { "version": "2023-11" }],
|
|
1204
1221
|
"@babel/plugin-transform-class-properties"
|
|
1205
1222
|
]
|
|
1206
1223
|
}
|
|
@@ -1222,7 +1239,7 @@ file <code>babelrc.json</code> is as follows:<pre class="prettyprint source lang
|
|
|
1222
1239
|
],
|
|
1223
1240
|
"plugins": [
|
|
1224
1241
|
"@babel/plugin-transform-runtime",
|
|
1225
|
-
["@babel/plugin-proposal-decorators", { "version": "2023-
|
|
1242
|
+
["@babel/plugin-proposal-decorators", { "version": "2023-11" }],
|
|
1226
1243
|
"@babel/plugin-transform-class-properties"
|
|
1227
1244
|
]
|
|
1228
1245
|
}
|
|
@@ -1301,7 +1318,590 @@ export default defineConfig({
|
|
|
1301
1318
|
to open an issue or submit a pull request to the <a href="https://github.com/Haixing-Hu/js-common-decorator">GitHub repository</a>.</p>
|
|
1302
1319
|
<h2><span id="license">License</span></h2>
|
|
1303
1320
|
<p><a href="https://npmjs.com/package/@qubit-ltd/common-decorator">@qubit-ltd/common-decorator</a> is distributed under the Apache 2.0 license.
|
|
1304
|
-
See the <a href="LICENSE">LICENSE</a> file for more details.</p
|
|
1321
|
+
See the <a href="LICENSE">LICENSE</a> file for more details.</p>
|
|
1322
|
+
<h2>Front-end and Back-end Data Exchange Example</h2>
|
|
1323
|
+
<p>In real-world applications, data exchange between front-end and back-end is a common scenario. The following example demonstrates how to use this library to process data from RESTful APIs and send it back to the server.</p>
|
|
1324
|
+
<h3>Complete Example</h3>
|
|
1325
|
+
<p>Suppose we have an e-commerce application that needs to handle order data. The back-end API returns data in snake_case naming convention (e.g., <code>order_id</code>), while the front-end code uses camelCase (e.g., <code>orderId</code>). Additionally, order IDs use Java's Long type (which may exceed JavaScript's safe integer range).</p>
|
|
1326
|
+
<p>First, let's define our domain models:</p>
|
|
1327
|
+
<pre class="prettyprint source lang-javascript"><code>import { Model, Type, ElementType, Normalizable, Validatable, NonEmpty } from '@qubit-ltd/common-decorator';
|
|
1328
|
+
|
|
1329
|
+
// Configure default options for naming style conversion
|
|
1330
|
+
DefaultOptions.set('assign', {
|
|
1331
|
+
normalize: true,
|
|
1332
|
+
convertNaming: true,
|
|
1333
|
+
sourceNamingStyle: 'LOWER_UNDERSCORE', // JSON data format from back-end
|
|
1334
|
+
targetNamingStyle: 'LOWER_CAMEL' // Format used in front-end
|
|
1335
|
+
});
|
|
1336
|
+
|
|
1337
|
+
DefaultOptions.set('toJSON', {
|
|
1338
|
+
normalize: true,
|
|
1339
|
+
removeEmptyFields: true, // Automatically remove empty fields
|
|
1340
|
+
convertNaming: true,
|
|
1341
|
+
sourceNamingStyle: 'LOWER_CAMEL', // Format used in front-end
|
|
1342
|
+
targetNamingStyle: 'LOWER_UNDERSCORE' // Format to send to back-end
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
// Define the OrderItem model
|
|
1346
|
+
@Model
|
|
1347
|
+
class OrderItem {
|
|
1348
|
+
constructor() {
|
|
1349
|
+
this.id = null; // Java Long type, automatically converted to BigInt
|
|
1350
|
+
this.productId = null; // Front-end uses camelCase, corresponding to product_id in back-end
|
|
1351
|
+
this.productName = '';
|
|
1352
|
+
this.quantity = 0;
|
|
1353
|
+
this.unitPrice = 0;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
@Normalizable
|
|
1357
|
+
@Validatable
|
|
1358
|
+
@Type(String)
|
|
1359
|
+
get productName() {
|
|
1360
|
+
return this._productName;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
set productName(value) {
|
|
1364
|
+
this._productName = value;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
@Normalizable
|
|
1368
|
+
@Validatable
|
|
1369
|
+
@Type(Number)
|
|
1370
|
+
get quantity() {
|
|
1371
|
+
return this._quantity;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
set quantity(value) {
|
|
1375
|
+
this._quantity = value;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
@Normalizable
|
|
1379
|
+
@Validatable
|
|
1380
|
+
@Type(Number)
|
|
1381
|
+
get unitPrice() {
|
|
1382
|
+
return this._unitPrice;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
set unitPrice(value) {
|
|
1386
|
+
this._unitPrice = value;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// Calculate total price
|
|
1390
|
+
getTotalPrice() {
|
|
1391
|
+
return this.quantity * this.unitPrice;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// Define the Order model
|
|
1396
|
+
@Model
|
|
1397
|
+
class Order {
|
|
1398
|
+
constructor() {
|
|
1399
|
+
this.id = null; // Java Long type, automatically converted to BigInt
|
|
1400
|
+
this.orderNumber = ''; // Front-end uses camelCase, corresponding to order_number in back-end
|
|
1401
|
+
this.customerId = null;
|
|
1402
|
+
this.customerName = '';
|
|
1403
|
+
this.orderDate = null;
|
|
1404
|
+
this.orderItems = []; // Array of order items
|
|
1405
|
+
this.totalAmount = 0;
|
|
1406
|
+
this.status = '';
|
|
1407
|
+
this.note = ''; // Optional field, empty values will be removed when sent to back-end
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
@Normalizable
|
|
1411
|
+
@Validatable
|
|
1412
|
+
@NonEmpty
|
|
1413
|
+
@Type(String)
|
|
1414
|
+
get orderNumber() {
|
|
1415
|
+
return this._orderNumber;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
set orderNumber(value) {
|
|
1419
|
+
this._orderNumber = value;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
@Normalizable
|
|
1423
|
+
@Validatable
|
|
1424
|
+
@Type(String)
|
|
1425
|
+
get customerName() {
|
|
1426
|
+
return this._customerName;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
set customerName(value) {
|
|
1430
|
+
this._customerName = value;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
@Normalizable
|
|
1434
|
+
@Validatable
|
|
1435
|
+
@Type(Date)
|
|
1436
|
+
get orderDate() {
|
|
1437
|
+
return this._orderDate;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
set orderDate(value) {
|
|
1441
|
+
this._orderDate = value;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
@Normalizable
|
|
1445
|
+
@Validatable
|
|
1446
|
+
@ElementType(OrderItem)
|
|
1447
|
+
get orderItems() {
|
|
1448
|
+
return this._orderItems;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
set orderItems(value) {
|
|
1452
|
+
this._orderItems = value;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
// Example usage - Fetching data from back-end
|
|
1457
|
+
async function fetchOrder(orderId) {
|
|
1458
|
+
try {
|
|
1459
|
+
// Assume this is the response from a back-end API
|
|
1460
|
+
const response = await fetch(`/api/orders/${orderId}`);
|
|
1461
|
+
const data = await response.json();
|
|
1462
|
+
|
|
1463
|
+
// Sample data (in snake_case naming style)
|
|
1464
|
+
// {
|
|
1465
|
+
// "id": "9223372036854775807", // Note: Max value of Java Long, exceeds JS Number safe range
|
|
1466
|
+
// "order_number": "ORD-2023-001",
|
|
1467
|
+
// "customer_id": "5678",
|
|
1468
|
+
// "customer_name": "John Doe",
|
|
1469
|
+
// "order_date": "2023-08-15T14:30:00.000Z",
|
|
1470
|
+
// "order_items": [
|
|
1471
|
+
// {
|
|
1472
|
+
// "id": "8345678912345678901", // Another large integer
|
|
1473
|
+
// "product_id": "101",
|
|
1474
|
+
// "product_name": "Laptop",
|
|
1475
|
+
// "quantity": 1,
|
|
1476
|
+
// "unit_price": 999.99
|
|
1477
|
+
// },
|
|
1478
|
+
// {
|
|
1479
|
+
// "id": "8345678912345678902",
|
|
1480
|
+
// "product_id": "202",
|
|
1481
|
+
// "product_name": "Wireless Mouse",
|
|
1482
|
+
// "quantity": 2,
|
|
1483
|
+
// "unit_price": 29.99
|
|
1484
|
+
// }
|
|
1485
|
+
// ],
|
|
1486
|
+
// "total_amount": 1059.97,
|
|
1487
|
+
// "status": "PENDING",
|
|
1488
|
+
// "note": null
|
|
1489
|
+
// }
|
|
1490
|
+
|
|
1491
|
+
// Create domain object using Order.create(), automatically handling naming style conversion and large integers
|
|
1492
|
+
const order = Order.create(data);
|
|
1493
|
+
|
|
1494
|
+
console.log(order.id); // Output: 9223372036854775807n (BigInt type)
|
|
1495
|
+
console.log(order.orderNumber); // Output: "ORD-2023-001" (converted to camelCase)
|
|
1496
|
+
console.log(order.orderItems[0].productName); // Output: "Laptop"
|
|
1497
|
+
|
|
1498
|
+
// Validation and normalization
|
|
1499
|
+
order.normalize();
|
|
1500
|
+
const validationResult = order.validate();
|
|
1501
|
+
if (!validationResult.valid) {
|
|
1502
|
+
console.error('Order data validation failed:', validationResult.message);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
return order;
|
|
1506
|
+
} catch (error) {
|
|
1507
|
+
console.error('Failed to fetch order:', error);
|
|
1508
|
+
throw error;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
// Sending data back to the back-end
|
|
1513
|
+
async function updateOrder(order) {
|
|
1514
|
+
try {
|
|
1515
|
+
// Use toJSON to convert domain object to plain JavaScript object
|
|
1516
|
+
// Automatically handles: 1. Naming style conversion 2. Empty field removal 3. BigInt conversion
|
|
1517
|
+
const orderData = order.toJSON();
|
|
1518
|
+
|
|
1519
|
+
// Example of converted data format:
|
|
1520
|
+
// {
|
|
1521
|
+
// "id": "9223372036854775807", // BigInt converted to string, without 'n' suffix
|
|
1522
|
+
// "order_number": "ORD-2023-001",
|
|
1523
|
+
// "customer_id": "5678",
|
|
1524
|
+
// "customer_name": "John Doe",
|
|
1525
|
+
// "order_date": "2023-08-15T14:30:00.000Z",
|
|
1526
|
+
// "order_items": [
|
|
1527
|
+
// {
|
|
1528
|
+
// "id": "8345678912345678901",
|
|
1529
|
+
// "product_id": "101",
|
|
1530
|
+
// "product_name": "Laptop",
|
|
1531
|
+
// "quantity": 1,
|
|
1532
|
+
// "unit_price": 999.99
|
|
1533
|
+
// },
|
|
1534
|
+
// // ...other order items
|
|
1535
|
+
// ],
|
|
1536
|
+
// "total_amount": 1059.97,
|
|
1537
|
+
// "status": "PENDING"
|
|
1538
|
+
// // Note: 'note' field was null and has been automatically removed
|
|
1539
|
+
// }
|
|
1540
|
+
|
|
1541
|
+
const response = await fetch(`/api/orders/${order.id}`, {
|
|
1542
|
+
method: 'PUT',
|
|
1543
|
+
headers: {
|
|
1544
|
+
'Content-Type': 'application/json'
|
|
1545
|
+
},
|
|
1546
|
+
body: JSON.stringify(orderData) // No additional processing needed, already in the right format
|
|
1547
|
+
});
|
|
1548
|
+
|
|
1549
|
+
if (!response.ok) {
|
|
1550
|
+
throw new Error(`Failed to update order: ${response.status}`);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
return await response.json();
|
|
1554
|
+
} catch (error) {
|
|
1555
|
+
console.error('Failed to update order:', error);
|
|
1556
|
+
throw error;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
// Example usage
|
|
1561
|
+
async function example() {
|
|
1562
|
+
// Fetch order data and modify it
|
|
1563
|
+
const order = await fetchOrder('123');
|
|
1564
|
+
order.status = 'COMPLETED';
|
|
1565
|
+
order.note = ''; // Empty string, will be removed when sent to back-end
|
|
1566
|
+
|
|
1567
|
+
// Add a new item to the order
|
|
1568
|
+
const newItem = new OrderItem();
|
|
1569
|
+
newItem.productId = '303';
|
|
1570
|
+
newItem.productName = 'Headphones';
|
|
1571
|
+
newItem.quantity = 1;
|
|
1572
|
+
newItem.unitPrice = 79.99;
|
|
1573
|
+
order.orderItems.push(newItem);
|
|
1574
|
+
|
|
1575
|
+
// Recalculate total amount
|
|
1576
|
+
order.totalAmount = order.orderItems.reduce(
|
|
1577
|
+
(sum, item) => sum + item.getTotalPrice(), 0
|
|
1578
|
+
);
|
|
1579
|
+
|
|
1580
|
+
// Send the updated order back to the server
|
|
1581
|
+
await updateOrder(order);
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
</code></pre>
|
|
1585
|
+
<h3>Key Points</h3>
|
|
1586
|
+
<ol>
|
|
1587
|
+
<li>
|
|
1588
|
+
<p><strong>Automatic Naming Style Conversion</strong>:</p>
|
|
1589
|
+
<ul>
|
|
1590
|
+
<li>Data from the back-end uses snake_case format (e.g., <code>order_number</code>)</li>
|
|
1591
|
+
<li>Front-end domain objects use camelCase format (e.g., <code>orderNumber</code>)</li>
|
|
1592
|
+
<li>Through <code>DefaultOptions.set('assign', {...})</code> configuration, <code>Model.create()</code> and <code>model.assign()</code> automatically convert naming styles</li>
|
|
1593
|
+
<li>Through <code>DefaultOptions.set('toJSON', {...})</code> configuration, <code>model.toJSON()</code> automatically converts camelCase back to snake_case</li>
|
|
1594
|
+
</ul>
|
|
1595
|
+
</li>
|
|
1596
|
+
<li>
|
|
1597
|
+
<p><strong>Large Integer Handling</strong>:</p>
|
|
1598
|
+
<ul>
|
|
1599
|
+
<li>Back-end uses Java Long type IDs (e.g., <code>9223372036854775807</code>) that exceed JavaScript's safe integer range</li>
|
|
1600
|
+
<li><code>Model.create()</code> and <code>model.assign()</code> automatically convert these large integers to JavaScript's BigInt type</li>
|
|
1601
|
+
<li><code>model.toJSON()</code> automatically converts BigInt to the correct JSON format (without the 'n' suffix)</li>
|
|
1602
|
+
</ul>
|
|
1603
|
+
</li>
|
|
1604
|
+
<li>
|
|
1605
|
+
<p><strong>Empty Field Handling</strong>:</p>
|
|
1606
|
+
<ul>
|
|
1607
|
+
<li>With <code>removeEmptyFields: true</code> configuration, <code>model.toJSON()</code> automatically removes null, undefined, and empty string properties</li>
|
|
1608
|
+
<li>In the example, the 'note' field with null or empty string value won't be sent to the back-end</li>
|
|
1609
|
+
</ul>
|
|
1610
|
+
</li>
|
|
1611
|
+
<li>
|
|
1612
|
+
<p><strong>Type Conversion and Validation</strong>:</p>
|
|
1613
|
+
<ul>
|
|
1614
|
+
<li>Use <code>@Type</code> and <code>@ElementType</code> decorators to ensure type safety</li>
|
|
1615
|
+
<li>Use <code>model.normalize()</code> for data normalization</li>
|
|
1616
|
+
<li>Use <code>model.validate()</code> to validate data integrity</li>
|
|
1617
|
+
</ul>
|
|
1618
|
+
</li>
|
|
1619
|
+
</ol>
|
|
1620
|
+
<p>This complete example demonstrates how to use the features of this library to easily handle various challenges in front-end and back-end data exchange in real-world applications.</p>
|
|
1621
|
+
<h2>Advanced Usage</h2>
|
|
1622
|
+
<h3>Combining Multiple Decorators</h3>
|
|
1623
|
+
<p>You can combine multiple decorators to add rich functionality to your classes:</p>
|
|
1624
|
+
<pre class="prettyprint source lang-javascript"><code>import {
|
|
1625
|
+
Model,
|
|
1626
|
+
Type,
|
|
1627
|
+
ElementType,
|
|
1628
|
+
Normalizable,
|
|
1629
|
+
Validatable,
|
|
1630
|
+
NonEmpty
|
|
1631
|
+
} from '@qubit-ltd/common-decorator';
|
|
1632
|
+
|
|
1633
|
+
@Model
|
|
1634
|
+
class Product {
|
|
1635
|
+
constructor() {
|
|
1636
|
+
this.id = null;
|
|
1637
|
+
this.name = '';
|
|
1638
|
+
this.price = 0;
|
|
1639
|
+
this.tags = [];
|
|
1640
|
+
this.createdAt = null;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
@NonEmpty
|
|
1644
|
+
@Validatable
|
|
1645
|
+
@Normalizable
|
|
1646
|
+
@Type(String)
|
|
1647
|
+
get name() {
|
|
1648
|
+
return this._name;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
set name(value) {
|
|
1652
|
+
this._name = value;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
@Validatable
|
|
1656
|
+
@Normalizable
|
|
1657
|
+
@Type(Number)
|
|
1658
|
+
get price() {
|
|
1659
|
+
return this._price;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
set price(value) {
|
|
1663
|
+
this._price = value;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
@Normalizable
|
|
1667
|
+
@ElementType(String)
|
|
1668
|
+
get tags() {
|
|
1669
|
+
return this._tags;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
set tags(value) {
|
|
1673
|
+
this._tags = value;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
// Usage
|
|
1678
|
+
const product = new Product();
|
|
1679
|
+
product.assign({
|
|
1680
|
+
name: ' Product Name ',
|
|
1681
|
+
price: '99.99',
|
|
1682
|
+
tags: ['tag1', 2, 'tag3']
|
|
1683
|
+
});
|
|
1684
|
+
|
|
1685
|
+
// After normalization, product.name will be trimmed,
|
|
1686
|
+
// product.price will be a Number,
|
|
1687
|
+
// and all elements in product.tags will be strings
|
|
1688
|
+
product.normalize();
|
|
1689
|
+
|
|
1690
|
+
console.log(product.validate()); // Checks if name is not empty and all types match
|
|
1691
|
+
</code></pre>
|
|
1692
|
+
<h3>Custom Validation and Normalization</h3>
|
|
1693
|
+
<p>You can implement custom validation and normalization logic:</p>
|
|
1694
|
+
<pre class="prettyprint source lang-javascript"><code>import { Model, Normalizable, Validatable } from '@qubit-ltd/common-decorator';
|
|
1695
|
+
|
|
1696
|
+
@Model
|
|
1697
|
+
class EmailSubscription {
|
|
1698
|
+
constructor() {
|
|
1699
|
+
this.email = '';
|
|
1700
|
+
this.subscribed = false;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
@Normalizable((value) => {
|
|
1704
|
+
// Custom normalizer that converts email to lowercase and trims whitespace
|
|
1705
|
+
return typeof value === 'string' ? value.toLowerCase().trim() : value;
|
|
1706
|
+
})
|
|
1707
|
+
@Validatable((value) => {
|
|
1708
|
+
// Custom validator that checks if email is valid
|
|
1709
|
+
if (typeof value !== 'string' || !value.includes('@')) {
|
|
1710
|
+
return {
|
|
1711
|
+
valid: false,
|
|
1712
|
+
message: 'Invalid email address',
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
return { valid: true };
|
|
1716
|
+
})
|
|
1717
|
+
get email() {
|
|
1718
|
+
return this._email;
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
set email(value) {
|
|
1722
|
+
this._email = value;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
</code></pre>
|
|
1726
|
+
<h3>Working with DefaultOptions</h3>
|
|
1727
|
+
<p>You can configure default options for various operations:</p>
|
|
1728
|
+
<pre class="prettyprint source lang-javascript"><code>import { DefaultOptions, Model } from '@qubit-ltd/common-decorator';
|
|
1729
|
+
|
|
1730
|
+
// Configure default options for JSON serialization
|
|
1731
|
+
DefaultOptions.set('toJSON', {
|
|
1732
|
+
normalize: true,
|
|
1733
|
+
removeEmptyFields: true,
|
|
1734
|
+
convertNaming: true,
|
|
1735
|
+
sourceNamingStyle: 'LOWER_CAMEL',
|
|
1736
|
+
targetNamingStyle: 'LOWER_UNDERSCORE'
|
|
1737
|
+
});
|
|
1738
|
+
|
|
1739
|
+
@Model
|
|
1740
|
+
class Order {
|
|
1741
|
+
constructor() {
|
|
1742
|
+
this.orderId = null;
|
|
1743
|
+
this.customerName = '';
|
|
1744
|
+
this.orderItems = [];
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
const order = new Order();
|
|
1749
|
+
order.assign({
|
|
1750
|
+
orderId: '12345',
|
|
1751
|
+
customerName: 'John Doe',
|
|
1752
|
+
orderItems: [
|
|
1753
|
+
{ itemId: 1, name: 'Product 1', quantity: 2 }
|
|
1754
|
+
]
|
|
1755
|
+
});
|
|
1756
|
+
|
|
1757
|
+
// Will use the configured default options for serialization
|
|
1758
|
+
const json = order.toJsonString();
|
|
1759
|
+
console.log(json);
|
|
1760
|
+
// Output will use lower_underscore naming:
|
|
1761
|
+
// {"order_id":"12345","customer_name":"John Doe","order_items":[{"item_id":1,"name":"Product 1","quantity":2}]}
|
|
1762
|
+
</code></pre>
|
|
1763
|
+
<h2>Integration Examples</h2>
|
|
1764
|
+
<h3>Using with Vue.js</h3>
|
|
1765
|
+
<pre class="prettyprint source lang-javascript"><code>import { Model, Normalizable, Validatable } from '@qubit-ltd/common-decorator';
|
|
1766
|
+
import { defineComponent, ref } from 'vue';
|
|
1767
|
+
|
|
1768
|
+
@Model
|
|
1769
|
+
class UserProfile {
|
|
1770
|
+
constructor() {
|
|
1771
|
+
this.username = '';
|
|
1772
|
+
this.email = '';
|
|
1773
|
+
this.bio = '';
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
@Normalizable
|
|
1777
|
+
@Validatable
|
|
1778
|
+
get username() {
|
|
1779
|
+
return this._username;
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
set username(value) {
|
|
1783
|
+
this._username = value;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
// Other getters and setters...
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
export default defineComponent({
|
|
1790
|
+
setup() {
|
|
1791
|
+
const profile = ref(new UserProfile());
|
|
1792
|
+
|
|
1793
|
+
const updateProfile = (formData) => {
|
|
1794
|
+
profile.value.assign(formData);
|
|
1795
|
+
profile.value.normalize();
|
|
1796
|
+
const validation = profile.value.validate();
|
|
1797
|
+
|
|
1798
|
+
if (validation.valid) {
|
|
1799
|
+
// Save profile
|
|
1800
|
+
} else {
|
|
1801
|
+
// Handle validation errors
|
|
1802
|
+
console.error(validation.message);
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
|
|
1806
|
+
return {
|
|
1807
|
+
profile,
|
|
1808
|
+
updateProfile
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
</code></pre>
|
|
1813
|
+
<h3>Using with Express.js</h3>
|
|
1814
|
+
<pre class="prettyprint source lang-javascript"><code>import express from 'express';
|
|
1815
|
+
import { Model, Normalizable, Validatable, NonEmpty } from '@qubit-ltd/common-decorator';
|
|
1816
|
+
|
|
1817
|
+
const app = express();
|
|
1818
|
+
app.use(express.json());
|
|
1819
|
+
|
|
1820
|
+
@Model
|
|
1821
|
+
class NewUserRequest {
|
|
1822
|
+
constructor() {
|
|
1823
|
+
this.username = '';
|
|
1824
|
+
this.email = '';
|
|
1825
|
+
this.password = '';
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
@NonEmpty
|
|
1829
|
+
@Normalizable
|
|
1830
|
+
@Validatable
|
|
1831
|
+
get username() {
|
|
1832
|
+
return this._username;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
set username(value) {
|
|
1836
|
+
this._username = value;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// Other getters and setters...
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
app.post('/api/users', (req, res) => {
|
|
1843
|
+
try {
|
|
1844
|
+
const userRequest = NewUserRequest.create(req.body);
|
|
1845
|
+
userRequest.normalize();
|
|
1846
|
+
const validation = userRequest.validate();
|
|
1847
|
+
|
|
1848
|
+
if (!validation.valid) {
|
|
1849
|
+
return res.status(400).json({ error: validation.message });
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// Create user in database
|
|
1853
|
+
return res.status(201).json({ message: 'User created successfully' });
|
|
1854
|
+
} catch (error) {
|
|
1855
|
+
return res.status(500).json({ error: error.message });
|
|
1856
|
+
}
|
|
1857
|
+
});
|
|
1858
|
+
|
|
1859
|
+
app.listen(3000, () => {
|
|
1860
|
+
console.log('Server is running on port 3000');
|
|
1861
|
+
});
|
|
1862
|
+
</code></pre>
|
|
1863
|
+
<h2>Compatibility and Requirements</h2>
|
|
1864
|
+
<ul>
|
|
1865
|
+
<li><strong>Node.js</strong>: 14.x or higher</li>
|
|
1866
|
+
<li><strong>ECMAScript</strong>: ES2022 or higher</li>
|
|
1867
|
+
<li><strong>Decorator Support</strong>: Requires babel configuration for Stage 3 decorators</li>
|
|
1868
|
+
<li><strong>Browser Support</strong>: Modern browsers with ES6+ support</li>
|
|
1869
|
+
</ul>
|
|
1870
|
+
<h2>Best Practices</h2>
|
|
1871
|
+
<h3>Project Structure</h3>
|
|
1872
|
+
<p>When using this library, we recommend organizing your domain models in a structured way:</p>
|
|
1873
|
+
<pre class="prettyprint source"><code>src/
|
|
1874
|
+
├── models/
|
|
1875
|
+
│ ├── base/
|
|
1876
|
+
│ │ └── BaseModel.js
|
|
1877
|
+
│ ├── User.js
|
|
1878
|
+
│ ├── Product.js
|
|
1879
|
+
│ └── Order.js
|
|
1880
|
+
├── enums/
|
|
1881
|
+
│ ├── Status.js
|
|
1882
|
+
│ └── Role.js
|
|
1883
|
+
└── app.js
|
|
1884
|
+
</code></pre>
|
|
1885
|
+
<h3>Performance Considerations</h3>
|
|
1886
|
+
<ul>
|
|
1887
|
+
<li>Use <code>normalize()</code> only when necessary, not on every operation</li>
|
|
1888
|
+
<li>Consider caching validation results for frequently accessed objects</li>
|
|
1889
|
+
<li>For large collections, use <code>createArray()</code> method instead of mapping each item</li>
|
|
1890
|
+
</ul>
|
|
1891
|
+
<h3>Type Safety</h3>
|
|
1892
|
+
<p>While JavaScript is dynamically typed, this library provides several ways to ensure type safety:</p>
|
|
1893
|
+
<ol>
|
|
1894
|
+
<li>Use the <code>@Type</code> decorator to enforce type checking for properties</li>
|
|
1895
|
+
<li>Use the <code>@ElementType</code> decorator for arrays</li>
|
|
1896
|
+
<li>Enable normalization to automatically convert values to the correct type</li>
|
|
1897
|
+
</ol>
|
|
1898
|
+
<h3>Memory Management</h3>
|
|
1899
|
+
<p>When working with large object graphs:</p>
|
|
1900
|
+
<ol>
|
|
1901
|
+
<li>Avoid deep cloning unnecessarily</li>
|
|
1902
|
+
<li>Use the <code>removeEmptyFields</code> option in <code>toJSON</code> for large objects</li>
|
|
1903
|
+
<li>Be cautious with circular references when serializing objects</li>
|
|
1904
|
+
</ol></article>
|
|
1305
1905
|
</section>
|
|
1306
1906
|
|
|
1307
1907
|
|
|
@@ -1315,7 +1915,7 @@ See the <a href="LICENSE">LICENSE</a> file for more details.</p></article>
|
|
|
1315
1915
|
|
|
1316
1916
|
<footer>
|
|
1317
1917
|
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.4</a>
|
|
1318
|
-
on Mon
|
|
1918
|
+
on Mon Apr 21 2025 02:07:33 GMT+0800 (China Standard Time)
|
|
1319
1919
|
using the <a href="https://github.com/Haixing-Hu/jsdoc-minami">customized Minami theme</a>.
|
|
1320
1920
|
</footer>
|
|
1321
1921
|
|