j-templates 7.0.105 → 8.0.1

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.
@@ -17,7 +17,7 @@ export declare class Component<D = void, T = void, E = {}> {
17
17
  /**
18
18
  * Returns the component's virtual node injector.
19
19
  */
20
- get Injector(): import("../Utils/injector").Injector;
20
+ get Injector(): import("../Utils").Injector;
21
21
  /**
22
22
  * Indicates whether the component has been destroyed.
23
23
  */
package/Node/vNode.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.vNode = void 0;
4
- const array_1 = require("../_not_used/array");
5
4
  const Store_1 = require("../Store");
6
5
  const observableScope_1 = require("../Store/Tree/observableScope");
6
+ const array_1 = require("../Utils/array");
7
7
  const emitter_1 = require("../Utils/emitter");
8
8
  const functions_1 = require("../Utils/functions");
9
9
  const injector_1 = require("../Utils/injector");
@@ -17,9 +17,7 @@ var vNode;
17
17
  definition,
18
18
  type: definition.type,
19
19
  injector: definition.componentFactory
20
- ? injector_1.Injector.Scope(injector_1.Injector.Current(), function () {
21
- return new injector_1.Injector();
22
- })
20
+ ? new injector_1.Injector()
23
21
  : (injector_1.Injector.Current() ?? new injector_1.Injector()),
24
22
  parentNode: null,
25
23
  node: definition.node ?? null,
@@ -134,7 +132,7 @@ function InitNode(vnode, parentNode) {
134
132
  nodeConfig_1.NodeConfig.attributeAssignment(node, attrs);
135
133
  }
136
134
  if (componentFactory) {
137
- vnode.component = componentFactory(vnode);
135
+ vnode.component = injector_1.Injector.Scope(vnode.injector, componentFactory, vnode);
138
136
  vnode.component.Bound();
139
137
  Children(vnode, ComponentChildren.bind(vnode.component));
140
138
  }
@@ -153,8 +151,10 @@ function Children(vnode, children, data) {
153
151
  Store_1.ObservableScope.Watch(childrenScope, CreateScheduledCallback(function (scope) {
154
152
  if (vnode.destroyed)
155
153
  return;
154
+ const oldChildrenLength = vnode.children.length;
156
155
  vnode.children = Store_1.ObservableScope.Value(scope);
157
- UpdateChildren(vnode);
156
+ if (oldChildrenLength !== 0 || vnode.children.length !== 0)
157
+ UpdateChildren(vnode);
158
158
  }));
159
159
  vnode.children = Store_1.ObservableScope.Value(childrenScope);
160
160
  }
package/SYNTAX_PRIMER.md CHANGED
@@ -594,7 +594,7 @@ Template() {
594
594
 
595
595
  > ⚠️ **Falsy edge case:** the falsy-collapse rule applies broadly — **`0`, `""`, and `NaN` also collapse to `[]`**, not just `false`/`null`/`undefined`. Only *truthy* non-array values are wrapped as `[value]`.
596
596
 
597
- **Also accepts** `Promise<T>` and `Promise<T[]>` for async data. While a Promise is pending, the scope evaluates to `null` (falsy), so the element renders nothing until resolved — there is no built-in placeholder; implement one yourself if needed.
597
+ **Also accepts** `Promise<T>` and `Promise<T[]>` for async data. While a Promise is pending, the scope evaluates to `null` (falsy), so the element renders nothing until resolved — there is no built-in placeholder; implement one yourself if needed. While a newer promise is pending, the last resolved value is kept.
598
598
 
599
599
  The `false`/`true` behavior makes `data:` a clean conditional rendering mechanism. **The child function is invoked with the truthy value as its data argument** — e.g. `data: () => this.isLoading` calls the child with `true` when loading. It renders its child once when true and nothing when false, with its own isolated reactive scope.
600
600
 
@@ -979,6 +979,8 @@ get userData(): User | null { return getUserSync(this.Data.userId); }
979
979
 
980
980
  **Pattern 3 (@ComputedAsync):** Getter must be synchronous. Returns default value initially, then computed value with same reference via ApplyDiff.
981
981
 
982
+ Shared async-scope behavior — typing, pending/old-value semantics, batching, and `scope()` composition — is covered in [Async Scopes](#async-scopes).
983
+
982
984
  ### State Location
983
985
 
984
986
  | State Type | Location | API |
@@ -995,6 +997,46 @@ get userData(): User | null { return getUserSync(this.Data.userId); }
995
997
 
996
998
  ---
997
999
 
1000
+ ## Async Scopes
1001
+
1002
+ Any function that supplies a scope value can be `async` — a `@Scope()` getter, a `props` or `data` function, or a `scope()`/`gate()`/`peek()`/`mapped()` callback. Services use the same mechanism through `ObservableScope.Create(async)` (see [Async Patterns](#async-patterns)).
1003
+
1004
+ **Typing unwraps the resolved value.** The helper signatures declare `() => T | Promise<T>`, so TypeScript infers the resolved value, not the promise:
1005
+
1006
+ ```typescript
1007
+ scope(async () => (await fetch(url)).text()); // typed string, not Promise<string>
1008
+ ```
1009
+
1010
+ The same unwrap applies to config functions — `FunctionOr<T>` for `props`/`attrs`/`on`, and the `Promise<Array<T>> | Promise<T>` union for `data:`. **The `async` keyword is required:** `IsAsync` detects it via `Symbol.toStringTag`. A plain function that merely *returns* a promise (`() => fetch(url)`) is treated as a synchronous scope whose value is the promise itself — it is never resolved (see Traps #17).
1011
+
1012
+ **Pending behavior.** An async scope renders nothing until its first result arrives: the initial value is `null`, so async `data:` collapses to no children and an async `props:` function applies nothing (the assignment closures skip null inputs). After the first result, the scope **keeps the last result while a new one is pending** — the value is replaced only when the promise resolves, and a resolution that arrives after a newer re-run has started is discarded.
1013
+
1014
+ ```typescript
1015
+ // Valid: nothing is applied to the element until the promise resolves.
1016
+ div({ props: async () => ({ innerHTML: await getMarkup() }) });
1017
+ ```
1018
+
1019
+ **Batching.** Async scopes are greedy — a dependency change marks the scope dirty and queues the re-run on the microtask queue (batched), instead of re-evaluating and propagating synchronously. This is the `greedy: true` behavior noted in Async Patterns.
1020
+
1021
+ **Composition with `scope()`.** `scope()` can compose an async value inside a synchronous scope. The inner scope registers as a dependency of the enclosing watch context, so the **outer scope re-runs when the inner one resolves**:
1022
+
1023
+ ```typescript
1024
+ Template() {
1025
+ return div({
1026
+ props: () => ({
1027
+ innerText: scope(async () => (await fetch(`/api/summary?open=${this.openCount}`)).text()),
1028
+ className: "summary-container",
1029
+ }),
1030
+ });
1031
+ }
1032
+ ```
1033
+
1034
+ `scope()` must be called inside a watch context — a `@Scope()` getter, a children function, or a `props:`/`data:` function (see Traps #11).
1035
+
1036
+ **Dependency capture.** Only reactive reads before the first `await` are tracked — reads after it happen outside the watch context and don't re-run the scope (see Traps #2). Read every reactive value the async scope depends on before the first `await`.
1037
+
1038
+ ---
1039
+
998
1040
  ## Scope Selection Decision Tree
999
1041
 
1000
1042
  Need derived data?
@@ -374,7 +374,7 @@ var ObservableNode;
374
374
  // Replacing rootNode
375
375
  const rootPatch = diffResult[0].value;
376
376
  const rootType = (0, json_2.JsonType)(root);
377
- const rootPatchType = (0, json_2.JsonType)(root);
377
+ const rootPatchType = (0, json_2.JsonType)(rootPatch);
378
378
  if (rootType !== rootPatchType)
379
379
  throw new Error("Unable to change type of Root ObservableNode: " + rootType);
380
380
  switch (rootType) {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Removes all null values from an array starting from a specified index.
3
+ * This function modifies the array in-place by shifting non-null elements
4
+ * to fill the gaps left by removed null values, then truncating the array.
5
+ *
6
+ * @param array - The array from which to remove null values. Can contain mixed types including null.
7
+ * @param startIndex - The index to start removing null values from (default: 0).
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const arr = [1, null, 2, null, 3, null, 4];
12
+ * RemoveNulls(arr); // Removes all null values, result: [1, 2, 3, 4]
13
+ *
14
+ * const arr2 = [null, null, 1, null, 2];
15
+ * RemoveNulls(arr2, 2); // Starts from index 2, result: [null, null, 1, 2]
16
+ * ```
17
+ */
18
+ export declare function RemoveNulls(array: (unknown | null)[], startIndex?: number): void;
package/Utils/array.js ADDED
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RemoveNulls = RemoveNulls;
4
+ /**
5
+ * Removes all null values from an array starting from a specified index.
6
+ * This function modifies the array in-place by shifting non-null elements
7
+ * to fill the gaps left by removed null values, then truncating the array.
8
+ *
9
+ * @param array - The array from which to remove null values. Can contain mixed types including null.
10
+ * @param startIndex - The index to start removing null values from (default: 0).
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const arr = [1, null, 2, null, 3, null, 4];
15
+ * RemoveNulls(arr); // Removes all null values, result: [1, 2, 3, 4]
16
+ *
17
+ * const arr2 = [null, null, 1, null, 2];
18
+ * RemoveNulls(arr2, 2); // Starts from index 2, result: [null, null, 1, 2]
19
+ * ```
20
+ */
21
+ function RemoveNulls(array, startIndex = 0) {
22
+ let nullIndex = startIndex;
23
+ for (; nullIndex < array.length && array[nullIndex] !== null; nullIndex++) { }
24
+ let notNullIndex = nullIndex + 1;
25
+ for (; notNullIndex < array.length && array[notNullIndex] === null; notNullIndex++) { }
26
+ while (notNullIndex < array.length) {
27
+ array[nullIndex] = array[notNullIndex];
28
+ nullIndex++;
29
+ notNullIndex++;
30
+ for (; notNullIndex < array.length && array[notNullIndex] === null; notNullIndex++) { }
31
+ }
32
+ if (nullIndex < array.length)
33
+ array.splice(nullIndex);
34
+ }
@@ -88,7 +88,7 @@ import { Injector } from "./injector";
88
88
  * @Value()
89
89
  * lastName: string = "Doe";
90
90
  *
91
- * @Computed() // Overhead: creates StoreSync, watch cycle, diff computation
91
+ * @Computed() // Overhead: observable node, watch cycle, diff computation
92
92
  * get fullName(): string {
93
93
  * return this.firstName + " " + this.lastName; // Cheap string concat
94
94
  * }
@@ -99,15 +99,18 @@ import { Injector } from "./injector";
99
99
  * }
100
100
  * ```
101
101
  *
102
- * @param defaultValue The default value to be used if the computed property is not defined.
103
102
  * @returns A property decorator that can be applied to a getter method.
104
103
  * @throws Will throw an error if the property is not a getter or if it has a setter.
105
104
  * @remarks
106
- * The @Computed decorator uses a two-phase caching system with diff-based updates:
107
- * 1. Getter scope: Computes value and writes to StoreSync when dependencies change
108
- * 2. StoreSync: Computes diff between old and new values
109
- * 3. ObservableNode.ApplyDiff: Updates the EXISTING object with only changed properties
110
- * 4. Property scope: Reads the updated (but same reference) value from StoreSync
105
+ * The @Computed decorator uses a Gated getter scope driving a persistent observable node:
106
+ * 1. Getter scope (Gated): Re-evaluates the getter when dependencies change, batched via
107
+ * the microtask queue. If the result deep-equals the previous value, no update is emitted.
108
+ * 2. ObservableNode.Apply: Diffs the fresh value against the node's current root and applies
109
+ * only the changed paths in-place, preserving the node's object identity.
110
+ * 3. Downstream notification: Per-property scopes are fired for each changed path, so scopes
111
+ * reading sub-properties update directly. If the diff collapses to a full root replacement
112
+ * (type change or removed keys), the root value gets a new identity and the Gated scope
113
+ * emits, notifying top-level subscribers.
111
114
  *
112
115
  * **Initialization**: @Computed uses lazy initialization - the scopes are created on first access:
113
116
  * ```typescript
@@ -152,8 +155,9 @@ import { Injector } from "./injector";
152
155
  * - The diff computation overhead is justified when you need object reuse
153
156
  * @see {@link Scope} for simple getter-based reactive properties (caches but new reference)
154
157
  * @see {@link ComputedAsync} for async computed properties
155
- * @see {@link ObservableNode.ApplyDiff} for how diffs are applied to maintain object identity
156
- * @see {@link StoreSync} for sync store implementation
158
+ * @see {@link ObservableNode.Apply} for how diffs are applied in-place to maintain object identity
159
+ * @see {@link ObservableScope} for the Gated scope mechanism (batched, ===-gated updates)
160
+ * @see {@link StoreSync} for the store-backed variant used by @ComputedAsync
157
161
  */
158
162
  export declare function Computed<T extends WeakKey, K extends keyof T, D extends T[K]>(): (target: T, propertyKey: K, descriptor: PropertyDescriptor) => PropertyDescriptor;
159
163
  /**
@@ -133,7 +133,7 @@ function GetDestroyArrayForPrototype(prototype, create = true) {
133
133
  }
134
134
  return array;
135
135
  }
136
- function CreateComputedScope(getter, store, defaultValue) {
136
+ function CreateStoreScope(getter, store, defaultValue) {
137
137
  const getterScope = observableScope_1.ObservableScope.Gated(function () {
138
138
  const value = getter();
139
139
  return observableNode_1.ObservableNode.Clone(value);
@@ -154,6 +154,31 @@ function CreateComputedScope(getter, store, defaultValue) {
154
154
  });
155
155
  return propertyScope;
156
156
  }
157
+ /**
158
+ * Creates a Gated observable scope that exposes a getter's value through a persistent
159
+ * observable node, preserving the value's object identity across updates.
160
+ *
161
+ * On each re-evaluation the getter's value is cloned and merged into the node in-place
162
+ * via ObservableNode.Apply:
163
+ * - Content changes (same structure, changed properties) fire only the affected
164
+ * per-property scopes - the top-level scope does not emit.
165
+ * - Structural changes (type change or removed keys) replace the root value with a new
166
+ * identity, which the Gated scope detects and emits for.
167
+ * - Deep-equal results are suppressed entirely by the Gated ===-gating.
168
+ *
169
+ * @param getter Function computing the value. May read reactive dependencies.
170
+ * @returns The Gated scope whose value is the observable root node.
171
+ */
172
+ function CreateNodeScope(getter) {
173
+ const observableNode = observableNode_1.ObservableNode.Create({ root: null });
174
+ const getterScope = observableScope_1.ObservableScope.Gated(function () {
175
+ const value = getter();
176
+ const clonedValue = observableNode_1.ObservableNode.Clone(value);
177
+ observableNode_1.ObservableNode.Apply(observableNode, { root: clonedValue });
178
+ return observableNode.root;
179
+ });
180
+ return getterScope;
181
+ }
157
182
  /**
158
183
  * Computed decorator factory for creating synchronous computed properties with caching and object reuse.
159
184
  * A computed property is derived from other properties and automatically updates when its dependencies change.
@@ -184,7 +209,7 @@ function CreateComputedScope(getter, store, defaultValue) {
184
209
  * @Value()
185
210
  * lastName: string = "Doe";
186
211
  *
187
- * @Computed() // Overhead: creates StoreSync, watch cycle, diff computation
212
+ * @Computed() // Overhead: observable node, watch cycle, diff computation
188
213
  * get fullName(): string {
189
214
  * return this.firstName + " " + this.lastName; // Cheap string concat
190
215
  * }
@@ -195,15 +220,18 @@ function CreateComputedScope(getter, store, defaultValue) {
195
220
  * }
196
221
  * ```
197
222
  *
198
- * @param defaultValue The default value to be used if the computed property is not defined.
199
223
  * @returns A property decorator that can be applied to a getter method.
200
224
  * @throws Will throw an error if the property is not a getter or if it has a setter.
201
225
  * @remarks
202
- * The @Computed decorator uses a two-phase caching system with diff-based updates:
203
- * 1. Getter scope: Computes value and writes to StoreSync when dependencies change
204
- * 2. StoreSync: Computes diff between old and new values
205
- * 3. ObservableNode.ApplyDiff: Updates the EXISTING object with only changed properties
206
- * 4. Property scope: Reads the updated (but same reference) value from StoreSync
226
+ * The @Computed decorator uses a Gated getter scope driving a persistent observable node:
227
+ * 1. Getter scope (Gated): Re-evaluates the getter when dependencies change, batched via
228
+ * the microtask queue. If the result deep-equals the previous value, no update is emitted.
229
+ * 2. ObservableNode.Apply: Diffs the fresh value against the node's current root and applies
230
+ * only the changed paths in-place, preserving the node's object identity.
231
+ * 3. Downstream notification: Per-property scopes are fired for each changed path, so scopes
232
+ * reading sub-properties update directly. If the diff collapses to a full root replacement
233
+ * (type change or removed keys), the root value gets a new identity and the Gated scope
234
+ * emits, notifying top-level subscribers.
207
235
  *
208
236
  * **Initialization**: @Computed uses lazy initialization - the scopes are created on first access:
209
237
  * ```typescript
@@ -248,8 +276,9 @@ function CreateComputedScope(getter, store, defaultValue) {
248
276
  * - The diff computation overhead is justified when you need object reuse
249
277
  * @see {@link Scope} for simple getter-based reactive properties (caches but new reference)
250
278
  * @see {@link ComputedAsync} for async computed properties
251
- * @see {@link ObservableNode.ApplyDiff} for how diffs are applied to maintain object identity
252
- * @see {@link StoreSync} for sync store implementation
279
+ * @see {@link ObservableNode.Apply} for how diffs are applied in-place to maintain object identity
280
+ * @see {@link ObservableScope} for the Gated scope mechanism (batched, ===-gated updates)
281
+ * @see {@link StoreSync} for the store-backed variant used by @ComputedAsync
253
282
  */
254
283
  function Computed() {
255
284
  return function (target, propertyKey, descriptor) {
@@ -262,7 +291,6 @@ function Computed() {
262
291
  * @param target The target object.
263
292
  * @param prop The property key.
264
293
  * @param descriptor The property descriptor.
265
- * @param defaultValue The default value to be used if the computed property is not defined.
266
294
  * @returns A property descriptor that replaces the original descriptor with a computed implementation.
267
295
  * @throws Will throw an error if the property is not a getter or if it has a setter.
268
296
  */
@@ -279,7 +307,7 @@ function ComputedDecorator(target, prop, descriptor) {
279
307
  get: function () {
280
308
  const scopeMap = GetScopeMapForInstance(this);
281
309
  if (scopeMap[propertyKey] === undefined) {
282
- const propertyScope = CreateComputedScope(getter.bind(this), new Store_1.StoreSync());
310
+ const propertyScope = CreateNodeScope(getter.bind(this));
283
311
  scopeMap[propertyKey] = [propertyScope, undefined];
284
312
  }
285
313
  return observableScope_1.ObservableScope.Value(scopeMap[propertyKey][0]);
@@ -405,7 +433,7 @@ function ComputedAsyncDecorator(target, prop, descriptor, defaultValue) {
405
433
  get: function () {
406
434
  const scopeMap = GetScopeMapForInstance(this);
407
435
  if (scopeMap[propertyKey] === undefined) {
408
- const propertyScope = CreateComputedScope(getter.bind(this), new Store_1.StoreAsync(), defaultValue);
436
+ const propertyScope = CreateStoreScope(getter.bind(this), new Store_1.StoreAsync(), defaultValue);
409
437
  scopeMap[propertyKey] = [propertyScope, undefined];
410
438
  }
411
439
  return observableScope_1.ObservableScope.Value(scopeMap[propertyKey][0]);
package/Utils/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./decorators";
2
2
  export * from "./animation";
3
+ export { Injector } from "./injector";
3
4
  export { IDestroyable } from "./utils.types";
package/Utils/index.js CHANGED
@@ -14,5 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.Injector = void 0;
17
18
  __exportStar(require("./decorators"), exports);
18
19
  __exportStar(require("./animation"), exports);
20
+ var injector_1 = require("./injector");
21
+ Object.defineProperty(exports, "Injector", { enumerable: true, get: function () { return injector_1.Injector; } });
@@ -1,21 +1,3 @@
1
- /**
2
- * Removes all null values from an array starting from a specified index.
3
- * This function modifies the array in-place by shifting non-null elements
4
- * to fill the gaps left by removed null values, then truncating the array.
5
- *
6
- * @param array - The array from which to remove null values. Can contain mixed types including null.
7
- * @param startIndex - The index to start removing null values from (default: 0).
8
- *
9
- * @example
10
- * ```typescript
11
- * const arr = [1, null, 2, null, 3, null, 4];
12
- * RemoveNulls(arr); // Removes all null values, result: [1, 2, 3, 4]
13
- *
14
- * const arr2 = [null, null, 1, null, 2];
15
- * RemoveNulls(arr2, 2); // Starts from index 2, result: [null, null, 1, 2]
16
- * ```
17
- */
18
- export declare function RemoveNulls(array: (unknown | null)[], startIndex?: number): void;
19
1
  export declare function ArrayDiff(source: any[], target: any[]): boolean;
20
2
  /**
21
3
  * Reconciles two sorted arrays by applying add and remove operations to transition
@@ -1,41 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RemoveNulls = RemoveNulls;
4
3
  exports.ArrayDiff = ArrayDiff;
5
4
  exports.ReconcileSortedEmitters = ReconcileSortedEmitters;
6
5
  exports.InsertionSortTuples = InsertionSortTuples;
7
6
  exports.ReconcileSortedArrays = ReconcileSortedArrays;
8
- /**
9
- * Removes all null values from an array starting from a specified index.
10
- * This function modifies the array in-place by shifting non-null elements
11
- * to fill the gaps left by removed null values, then truncating the array.
12
- *
13
- * @param array - The array from which to remove null values. Can contain mixed types including null.
14
- * @param startIndex - The index to start removing null values from (default: 0).
15
- *
16
- * @example
17
- * ```typescript
18
- * const arr = [1, null, 2, null, 3, null, 4];
19
- * RemoveNulls(arr); // Removes all null values, result: [1, 2, 3, 4]
20
- *
21
- * const arr2 = [null, null, 1, null, 2];
22
- * RemoveNulls(arr2, 2); // Starts from index 2, result: [null, null, 1, 2]
23
- * ```
24
- */
25
- function RemoveNulls(array, startIndex = 0) {
26
- let nullIndex = startIndex;
27
- for (; nullIndex < array.length && array[nullIndex] !== null; nullIndex++) { }
28
- let notNullIndex = nullIndex + 1;
29
- for (; notNullIndex < array.length && array[notNullIndex] === null; notNullIndex++) { }
30
- while (notNullIndex < array.length) {
31
- array[nullIndex] = array[notNullIndex];
32
- nullIndex++;
33
- notNullIndex++;
34
- for (; notNullIndex < array.length && array[notNullIndex] === null; notNullIndex++) { }
35
- }
36
- if (nullIndex < array.length)
37
- array.splice(nullIndex);
38
- }
39
7
  function ArrayDiff(source, target) {
40
8
  if (source === target)
41
9
  return false;
package/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { Component } from './Node/component';
2
2
  export { InlineScope as scope, GateScope as gate, PeekScope as peek, MappedScope as mapped } from './Store/Tree/observableScope';
3
+ export { vNode } from './Node/vNode.types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "j-templates",
3
- "version": "7.0.105",
3
+ "version": "8.0.1",
4
4
  "description": "j-templates",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/TypesInCode/jTemplates",