@reidelsaltres/pureper 0.2.15 → 0.2.17
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/out/foundation/Fetcher.d.ts.map +1 -1
- package/out/foundation/Fetcher.js +8 -13
- package/out/foundation/Fetcher.js.map +1 -1
- package/out/foundation/Injection.d.ts +87 -0
- package/out/foundation/Injection.d.ts.map +1 -0
- package/out/foundation/Injection.js +149 -0
- package/out/foundation/Injection.js.map +1 -0
- package/out/foundation/Triplet.d.ts +30 -25
- package/out/foundation/Triplet.d.ts.map +1 -1
- package/out/foundation/Triplet.js +96 -115
- package/out/foundation/Triplet.js.map +1 -1
- package/out/foundation/TripletDecorator.d.ts +11 -0
- package/out/foundation/TripletDecorator.d.ts.map +1 -1
- package/out/foundation/TripletDecorator.js +25 -8
- package/out/foundation/TripletDecorator.js.map +1 -1
- package/out/foundation/component_api/UniHtml.d.ts +5 -1
- package/out/foundation/component_api/UniHtml.d.ts.map +1 -1
- package/out/foundation/component_api/UniHtml.js +23 -5
- package/out/foundation/component_api/UniHtml.js.map +1 -1
- package/out/foundation/worker/ServiceWorker.d.ts +48 -17
- package/out/foundation/worker/ServiceWorker.d.ts.map +1 -1
- package/out/foundation/worker/ServiceWorker.js +186 -119
- package/out/foundation/worker/ServiceWorker.js.map +1 -1
- package/out/index.d.ts +3 -2
- package/out/index.d.ts.map +1 -1
- package/out/index.js +2 -1
- package/out/index.js.map +1 -1
- package/package.json +1 -1
- package/src/foundation/Fetcher.ts +9 -14
- package/src/foundation/Injection.ts +183 -0
- package/src/foundation/Triplet.ts +114 -141
- package/src/foundation/TripletDecorator.ts +32 -8
- package/src/foundation/component_api/UniHtml.ts +26 -5
- package/src/foundation/worker/ServiceWorker.ts +203 -129
- package/src/foundation/worker/serviceworker.js +191 -0
- package/src/index.ts +7 -4
- package/out/foundation/worker/serviceworker.d.ts +0 -1
- package/out/foundation/worker/serviceworker.d.ts.map +0 -1
- package/out/foundation/worker/serviceworker.js +0 -2
- package/out/foundation/worker/serviceworker.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Fetcher.d.ts","sourceRoot":"","sources":["../../src/foundation/Fetcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Fetcher.d.ts","sourceRoot":"","sources":["../../src/foundation/Fetcher.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,OAAO,OAAO;WACX,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;WAgBvC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;WAgBnC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;mBAiBxB,aAAa;CAarC"}
|
|
@@ -1,40 +1,29 @@
|
|
|
1
1
|
import { HOSTING_ORIGIN } from "./Hosting.js";
|
|
2
|
-
// cache stores response bodies (text) by resolved URL so we can reuse them safely
|
|
3
|
-
const temporaryCache = new Map();
|
|
4
2
|
// keep in-flight promises to deduplicate concurrent identical requests
|
|
5
3
|
const inFlightText = new Map();
|
|
6
4
|
const inFlightJSON = new Map();
|
|
7
5
|
export default class Fetcher {
|
|
8
6
|
static async fetchText(url) {
|
|
9
7
|
const resolved = this.resolveUrl(url);
|
|
10
|
-
if (temporaryCache.has(resolved))
|
|
11
|
-
return temporaryCache.get(resolved);
|
|
12
8
|
// If a request for the same URL is already in-flight, reuse its promise
|
|
13
9
|
if (inFlightText.has(resolved))
|
|
14
10
|
return inFlightText.get(resolved);
|
|
15
11
|
const p = (async () => {
|
|
16
12
|
const response = await this.internalFetch(resolved);
|
|
17
|
-
|
|
18
|
-
temporaryCache.set(resolved, text);
|
|
19
|
-
return text;
|
|
13
|
+
return response.text();
|
|
20
14
|
})();
|
|
21
15
|
inFlightText.set(resolved, p);
|
|
22
|
-
// cleanup entry when finished
|
|
23
16
|
p.finally(() => inFlightText.delete(resolved));
|
|
24
17
|
return p;
|
|
25
18
|
}
|
|
26
19
|
static async fetchJSON(url) {
|
|
27
20
|
const resolved = this.resolveUrl(url);
|
|
28
|
-
if (temporaryCache.has(resolved))
|
|
29
|
-
return JSON.parse(temporaryCache.get(resolved));
|
|
30
21
|
// If a request for the same URL is already in-flight, reuse its promise
|
|
31
22
|
if (inFlightJSON.has(resolved))
|
|
32
23
|
return inFlightJSON.get(resolved);
|
|
33
24
|
const p = (async () => {
|
|
34
25
|
const response = await this.internalFetch(resolved);
|
|
35
|
-
|
|
36
|
-
temporaryCache.set(resolved, JSON.stringify(json));
|
|
37
|
-
return json;
|
|
26
|
+
return response.json();
|
|
38
27
|
})();
|
|
39
28
|
inFlightJSON.set(resolved, p);
|
|
40
29
|
p.finally(() => inFlightJSON.delete(resolved));
|
|
@@ -56,6 +45,12 @@ export default class Fetcher {
|
|
|
56
45
|
return new URL(trimmed, `${HOSTING_ORIGIN}/`).href;
|
|
57
46
|
}
|
|
58
47
|
static async internalFetch(resolvedUrl) {
|
|
48
|
+
// L2: check ServiceWorker CacheStorage before hitting the network
|
|
49
|
+
if ('caches' in window) {
|
|
50
|
+
const cached = await caches.match(resolvedUrl);
|
|
51
|
+
if (cached)
|
|
52
|
+
return cached;
|
|
53
|
+
}
|
|
59
54
|
const response = await fetch(resolvedUrl, { cache: 'default' });
|
|
60
55
|
if (!response.ok) {
|
|
61
56
|
throw new Error(`HTTP error! ${resolvedUrl} status: ${response.status}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Fetcher.js","sourceRoot":"","sources":["../../src/foundation/Fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Fetcher.js","sourceRoot":"","sources":["../../src/foundation/Fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import Observable from "./api/Observer.js";
|
|
2
|
+
import { AnyConstructor } from "./component_api/mixin/Proto.js";
|
|
3
|
+
import UniHtml from "./component_api/UniHtml.js";
|
|
4
|
+
export type ImplementationStruct = {
|
|
5
|
+
markupURL?: string;
|
|
6
|
+
markup?: string;
|
|
7
|
+
cssURL?: string;
|
|
8
|
+
css?: string;
|
|
9
|
+
ltCssURL?: string;
|
|
10
|
+
ltCss?: string;
|
|
11
|
+
class?: AnyConstructor<UniHtml>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Implementation — a swappable variant for a Triplet placeholder.
|
|
15
|
+
*
|
|
16
|
+
* Each placeholder (component tag or page route) can have multiple registered
|
|
17
|
+
* implementations. One is active at a time; switching triggers a reload on
|
|
18
|
+
* all live instances.
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* // Register the default implementation
|
|
22
|
+
* @ReComponent({ markupURL: './Button.hmle', cssURL: './Button.css' }, "re-button")
|
|
23
|
+
* class ReButton extends Component { ... }
|
|
24
|
+
*
|
|
25
|
+
* // Register an alternative implementation
|
|
26
|
+
* @ReImplementation({ markupURL: './FancyButton.hmle', cssURL: './FancyButton.css' }, "re-button")
|
|
27
|
+
* class FancyButton extends Component { ... }
|
|
28
|
+
*
|
|
29
|
+
* // Switch all re-button instances to FancyButton
|
|
30
|
+
* Placeholder.switchTo("re-button", "FancyButton");
|
|
31
|
+
*
|
|
32
|
+
* // Switch a single instance manually
|
|
33
|
+
* const btn = document.querySelector("re-button");
|
|
34
|
+
* Placeholder.switchInstance(btn, "FancyButton");
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class Implementation {
|
|
38
|
+
readonly name: string;
|
|
39
|
+
readonly markup?: Promise<string>;
|
|
40
|
+
readonly style?: Promise<string>;
|
|
41
|
+
readonly globalStyle?: Promise<string>;
|
|
42
|
+
readonly uniClass?: AnyConstructor<UniHtml>;
|
|
43
|
+
constructor(name: string, struct: ImplementationStruct);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Placeholder — manages a named slot (tag or route) with swappable implementations.
|
|
47
|
+
*
|
|
48
|
+
* - `Placeholder.get(name)` — get or create a placeholder
|
|
49
|
+
* - `placeholder.addImplementation(impl)` — register an implementation
|
|
50
|
+
* - `Placeholder.switchTo(name, implName)` — globally switch + reload all instances
|
|
51
|
+
* - `Placeholder.switchInstance(instance, implName)` — switch one instance
|
|
52
|
+
*/
|
|
53
|
+
export declare class Placeholder {
|
|
54
|
+
/** Все зарегистрированные placeholders по имени (tag / route). */
|
|
55
|
+
private static readonly _all;
|
|
56
|
+
readonly name: string;
|
|
57
|
+
readonly implementations: Map<string, Implementation>;
|
|
58
|
+
readonly activeImpl: Observable<Implementation | null>;
|
|
59
|
+
/** Все живые экземпляры этого placeholder для reload при смене implementation. */
|
|
60
|
+
private readonly _instances;
|
|
61
|
+
private constructor();
|
|
62
|
+
/** Get or create a placeholder by name. */
|
|
63
|
+
static get(name: string): Placeholder;
|
|
64
|
+
/** Check if a placeholder exists. */
|
|
65
|
+
static has(name: string): boolean;
|
|
66
|
+
/** Add an implementation. The first one added becomes active by default. */
|
|
67
|
+
addImplementation(impl: Implementation): void;
|
|
68
|
+
/** Get the currently active implementation. */
|
|
69
|
+
getActive(): Implementation | null;
|
|
70
|
+
/** Track a live instance for reload. */
|
|
71
|
+
trackInstance(instance: UniHtml): void;
|
|
72
|
+
/** Untrack a disposed instance. */
|
|
73
|
+
untrackInstance(instance: UniHtml): void;
|
|
74
|
+
/** Get all tracked live instances. */
|
|
75
|
+
getInstances(): Set<UniHtml>;
|
|
76
|
+
/**
|
|
77
|
+
* Switch the active implementation globally.
|
|
78
|
+
* All live instances of this placeholder will reload.
|
|
79
|
+
*/
|
|
80
|
+
static switchTo(placeholderName: string, implName: string): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Switch a single instance to a different implementation and reload it.
|
|
83
|
+
* Does NOT change the global active implementation.
|
|
84
|
+
*/
|
|
85
|
+
static switchInstance(placeholderName: string, instance: UniHtml, implName: string): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=Injection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Injection.d.ts","sourceRoot":"","sources":["../../src/foundation/Injection.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,OAAO,MAAM,4BAA4B,CAAC;AAEjD,MAAM,MAAM,oBAAoB,GAAG;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;CACnC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,cAAc;IACvB,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,SAAgB,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,SAAgB,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,SAAgB,QAAQ,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;gBAEhC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB;CAiBhE;AAED;;;;;;;GAOG;AACH,qBAAa,WAAW;IACpB,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAuC;IAEnE,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAa;IACzE,SAAgB,UAAU,EAAE,UAAU,CAAC,cAAc,GAAG,IAAI,CAAC,CAAwB;IAErF,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAEtD,OAAO;IAIP,2CAA2C;WAC7B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAS5C,qCAAqC;WACvB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIxC,4EAA4E;IACrE,iBAAiB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAcpD,+CAA+C;IACxC,SAAS,IAAI,cAAc,GAAG,IAAI;IAIzC,wCAAwC;IACjC,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAI7C,mCAAmC;IAC5B,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAI/C,sCAAsC;IAC/B,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC;IAInC;;;OAGG;WACiB,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBtF;;;OAGG;WACiB,cAAc,CAAC,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWlH"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import Observable from "./api/Observer.js";
|
|
2
|
+
import Fetcher from "./Fetcher.js";
|
|
3
|
+
/**
|
|
4
|
+
* Implementation — a swappable variant for a Triplet placeholder.
|
|
5
|
+
*
|
|
6
|
+
* Each placeholder (component tag or page route) can have multiple registered
|
|
7
|
+
* implementations. One is active at a time; switching triggers a reload on
|
|
8
|
+
* all live instances.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Register the default implementation
|
|
12
|
+
* @ReComponent({ markupURL: './Button.hmle', cssURL: './Button.css' }, "re-button")
|
|
13
|
+
* class ReButton extends Component { ... }
|
|
14
|
+
*
|
|
15
|
+
* // Register an alternative implementation
|
|
16
|
+
* @ReImplementation({ markupURL: './FancyButton.hmle', cssURL: './FancyButton.css' }, "re-button")
|
|
17
|
+
* class FancyButton extends Component { ... }
|
|
18
|
+
*
|
|
19
|
+
* // Switch all re-button instances to FancyButton
|
|
20
|
+
* Placeholder.switchTo("re-button", "FancyButton");
|
|
21
|
+
*
|
|
22
|
+
* // Switch a single instance manually
|
|
23
|
+
* const btn = document.querySelector("re-button");
|
|
24
|
+
* Placeholder.switchInstance(btn, "FancyButton");
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class Implementation {
|
|
28
|
+
name;
|
|
29
|
+
markup;
|
|
30
|
+
style;
|
|
31
|
+
globalStyle;
|
|
32
|
+
uniClass;
|
|
33
|
+
constructor(name, struct) {
|
|
34
|
+
this.name = name;
|
|
35
|
+
if (struct.markup && struct.markupURL)
|
|
36
|
+
throw new Error(`[Implementation:${name}]: Both markup and markupURL provided.`);
|
|
37
|
+
this.markup = struct.markupURL ? Fetcher.fetchText(struct.markupURL) : Promise.resolve(struct.markup);
|
|
38
|
+
if (struct.css && struct.cssURL)
|
|
39
|
+
throw new Error(`[Implementation:${name}]: Both css and cssURL provided.`);
|
|
40
|
+
this.style = struct.cssURL ? Fetcher.fetchText(struct.cssURL) : Promise.resolve(struct.css);
|
|
41
|
+
if (struct.ltCss && struct.ltCssURL)
|
|
42
|
+
throw new Error(`[Implementation:${name}]: Both ltCss and ltCssURL provided.`);
|
|
43
|
+
this.globalStyle = struct.ltCssURL ? Fetcher.fetchText(struct.ltCssURL) : Promise.resolve(struct.ltCss);
|
|
44
|
+
this.uniClass = struct.class;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Placeholder — manages a named slot (tag or route) with swappable implementations.
|
|
49
|
+
*
|
|
50
|
+
* - `Placeholder.get(name)` — get or create a placeholder
|
|
51
|
+
* - `placeholder.addImplementation(impl)` — register an implementation
|
|
52
|
+
* - `Placeholder.switchTo(name, implName)` — globally switch + reload all instances
|
|
53
|
+
* - `Placeholder.switchInstance(instance, implName)` — switch one instance
|
|
54
|
+
*/
|
|
55
|
+
export class Placeholder {
|
|
56
|
+
/** Все зарегистрированные placeholders по имени (tag / route). */
|
|
57
|
+
static _all = new Map();
|
|
58
|
+
name;
|
|
59
|
+
implementations = new Map();
|
|
60
|
+
activeImpl = new Observable(null);
|
|
61
|
+
/** Все живые экземпляры этого placeholder для reload при смене implementation. */
|
|
62
|
+
_instances = new Set();
|
|
63
|
+
constructor(name) {
|
|
64
|
+
this.name = name;
|
|
65
|
+
}
|
|
66
|
+
/** Get or create a placeholder by name. */
|
|
67
|
+
static get(name) {
|
|
68
|
+
let p = this._all.get(name);
|
|
69
|
+
if (!p) {
|
|
70
|
+
p = new Placeholder(name);
|
|
71
|
+
this._all.set(name, p);
|
|
72
|
+
}
|
|
73
|
+
return p;
|
|
74
|
+
}
|
|
75
|
+
/** Check if a placeholder exists. */
|
|
76
|
+
static has(name) {
|
|
77
|
+
return this._all.has(name);
|
|
78
|
+
}
|
|
79
|
+
/** Add an implementation. The first one added becomes active by default. */
|
|
80
|
+
addImplementation(impl) {
|
|
81
|
+
if (this.implementations.has(impl.name)) {
|
|
82
|
+
console.warn(`[Placeholder:${this.name}]: Implementation "${impl.name}" already registered, overwriting.`);
|
|
83
|
+
}
|
|
84
|
+
this.implementations.set(impl.name, impl);
|
|
85
|
+
if (!this.activeImpl.getObject()) {
|
|
86
|
+
this.activeImpl.setObject(impl);
|
|
87
|
+
console.info(`[Placeholder:${this.name}]: Default implementation set to "${impl.name}"`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.info(`[Placeholder:${this.name}]: Implementation "${impl.name}" registered`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Get the currently active implementation. */
|
|
94
|
+
getActive() {
|
|
95
|
+
return this.activeImpl.getObject();
|
|
96
|
+
}
|
|
97
|
+
/** Track a live instance for reload. */
|
|
98
|
+
trackInstance(instance) {
|
|
99
|
+
this._instances.add(instance);
|
|
100
|
+
}
|
|
101
|
+
/** Untrack a disposed instance. */
|
|
102
|
+
untrackInstance(instance) {
|
|
103
|
+
this._instances.delete(instance);
|
|
104
|
+
}
|
|
105
|
+
/** Get all tracked live instances. */
|
|
106
|
+
getInstances() {
|
|
107
|
+
return this._instances;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Switch the active implementation globally.
|
|
111
|
+
* All live instances of this placeholder will reload.
|
|
112
|
+
*/
|
|
113
|
+
static async switchTo(placeholderName, implName) {
|
|
114
|
+
const p = this._all.get(placeholderName);
|
|
115
|
+
if (!p)
|
|
116
|
+
throw new Error(`[Placeholder]: "${placeholderName}" not found.`);
|
|
117
|
+
const impl = p.implementations.get(implName);
|
|
118
|
+
if (!impl)
|
|
119
|
+
throw new Error(`[Placeholder:${placeholderName}]: Implementation "${implName}" not found.`);
|
|
120
|
+
const prev = p.activeImpl.getObject();
|
|
121
|
+
if (prev === impl)
|
|
122
|
+
return;
|
|
123
|
+
p.activeImpl.setObject(impl);
|
|
124
|
+
console.info(`[Placeholder:${placeholderName}]: Switched to "${implName}"`);
|
|
125
|
+
// Reload all live instances
|
|
126
|
+
const reloads = [];
|
|
127
|
+
for (const instance of p._instances) {
|
|
128
|
+
reloads.push(instance.reload());
|
|
129
|
+
}
|
|
130
|
+
await Promise.all(reloads);
|
|
131
|
+
console.info(`[Placeholder:${placeholderName}]: Reloaded ${reloads.length} instance(s)`);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Switch a single instance to a different implementation and reload it.
|
|
135
|
+
* Does NOT change the global active implementation.
|
|
136
|
+
*/
|
|
137
|
+
static async switchInstance(placeholderName, instance, implName) {
|
|
138
|
+
const p = this._all.get(placeholderName);
|
|
139
|
+
if (!p)
|
|
140
|
+
throw new Error(`[Placeholder]: "${placeholderName}" not found.`);
|
|
141
|
+
const impl = p.implementations.get(implName);
|
|
142
|
+
if (!impl)
|
|
143
|
+
throw new Error(`[Placeholder:${placeholderName}]: Implementation "${implName}" not found.`);
|
|
144
|
+
instance._activeImplementation = impl;
|
|
145
|
+
await instance.reload();
|
|
146
|
+
console.info(`[Placeholder:${placeholderName}]: Instance switched to "${implName}"`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=Injection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Injection.js","sourceRoot":"","sources":["../../src/foundation/Injection.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,37 +1,42 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { ImplementationStruct } from "./Injection.js";
|
|
2
|
+
export declare const REGISTRY: (() => void)[];
|
|
3
3
|
export declare enum AccessType {
|
|
4
4
|
NONE = 0,
|
|
5
5
|
OFFLINE = 1,
|
|
6
6
|
ONLINE = 2,
|
|
7
7
|
BOTH = 3
|
|
8
8
|
}
|
|
9
|
-
export type TripletStruct = {
|
|
10
|
-
markupURL?: string;
|
|
11
|
-
markup?: string;
|
|
12
|
-
cssURL?: string;
|
|
13
|
-
css?: string;
|
|
14
|
-
ltCssURL?: string;
|
|
15
|
-
ltCss?: string;
|
|
16
|
-
jsURL?: string;
|
|
9
|
+
export type TripletStruct = ImplementationStruct & {
|
|
17
10
|
access?: AccessType;
|
|
18
|
-
class?: AnyConstructor<UniHtml>;
|
|
19
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Triplet — registers a placeholder with a default implementation.
|
|
14
|
+
*
|
|
15
|
+
* The placeholder is what gets registered in `customElements.define()` or `Router`.
|
|
16
|
+
* At runtime, the placeholder resolves the currently active {@link Implementation}
|
|
17
|
+
* and uses its markup, style, and class for the lifecycle.
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* // Default implementation registered via @ReComponent
|
|
21
|
+
* @ReComponent({ markupURL: './Button.hmle', cssURL: './Button.css' }, "re-button")
|
|
22
|
+
* class ReButton extends Component { ... }
|
|
23
|
+
*
|
|
24
|
+
* // Alternative implementation registered via @ReImplementation
|
|
25
|
+
* @ReImplementation({ markupURL: './FancyButton.hmle', cssURL: './Fancy.css' }, "re-button")
|
|
26
|
+
* class FancyButton extends Component { ... }
|
|
27
|
+
*
|
|
28
|
+
* // Switch globally — all re-button instances reload
|
|
29
|
+
* Placeholder.switchTo("re-button", "FancyButton");
|
|
30
|
+
*
|
|
31
|
+
* // Switch one instance only
|
|
32
|
+
* Placeholder.switchInstance("re-button", myBtnInstance, "FancyButton");
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
20
35
|
export default class Triplet {
|
|
21
|
-
readonly markup?: Promise<string>;
|
|
22
|
-
readonly css?: Promise<string>;
|
|
23
|
-
readonly lightCss?: Promise<string>;
|
|
24
|
-
readonly js?: Promise<string>;
|
|
25
|
-
private readonly markupURL?;
|
|
26
|
-
private readonly cssURL?;
|
|
27
|
-
private readonly ltCssURL?;
|
|
28
|
-
private readonly jsURL?;
|
|
29
36
|
private readonly access;
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
register(type: "router" | "markup", name: string): Promise<boolean>;
|
|
35
|
-
private createInjectedClass;
|
|
37
|
+
private readonly placeholderName?;
|
|
38
|
+
private readonly implementation;
|
|
39
|
+
constructor(struct: TripletStruct, implName?: string);
|
|
40
|
+
register(type: "router" | "markup", name: string): Promise<void>;
|
|
36
41
|
}
|
|
37
42
|
//# sourceMappingURL=Triplet.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Triplet.d.ts","sourceRoot":"","sources":["../../src/foundation/Triplet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Triplet.d.ts","sourceRoot":"","sources":["../../src/foundation/Triplet.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,oBAAoB,EAAe,MAAM,gBAAgB,CAAC;AAEnF,eAAO,MAAM,QAAQ,EAAE,CAAC,MAAM,IAAI,CAAC,EAAO,CAAC;AAE3C,oBAAY,UAAU;IAClB,IAAI,IAAI;IACR,OAAO,IAAS;IAChB,MAAM,IAAS;IACf,IAAI,IAAmB;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG;IAC/C,MAAM,CAAC,EAAE,UAAU,CAAC;CACvB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,OAAO,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;gBAE7B,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,MAAM;IAO9C,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA4FhF"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import Fetcher from "./Fetcher.js";
|
|
2
1
|
import { Router } from "./worker/Router.js";
|
|
3
|
-
import ServiceWorker from "./worker/ServiceWorker.js";
|
|
4
2
|
import Page from "./component_api/Page.js";
|
|
5
3
|
import Component from "./component_api/Component.js";
|
|
6
4
|
import TemplateEngine from "./engine/TemplateEngine.js";
|
|
7
5
|
import Scope from "./engine/Scope.js";
|
|
6
|
+
import { Implementation, Placeholder } from "./Injection.js";
|
|
7
|
+
export const REGISTRY = [];
|
|
8
8
|
export var AccessType;
|
|
9
9
|
(function (AccessType) {
|
|
10
10
|
AccessType[AccessType["NONE"] = 0] = "NONE";
|
|
@@ -12,131 +12,112 @@ export var AccessType;
|
|
|
12
12
|
AccessType[AccessType["ONLINE"] = 2] = "ONLINE";
|
|
13
13
|
AccessType[AccessType["BOTH"] = 3] = "BOTH";
|
|
14
14
|
})(AccessType || (AccessType = {}));
|
|
15
|
+
/**
|
|
16
|
+
* Triplet — registers a placeholder with a default implementation.
|
|
17
|
+
*
|
|
18
|
+
* The placeholder is what gets registered in `customElements.define()` or `Router`.
|
|
19
|
+
* At runtime, the placeholder resolves the currently active {@link Implementation}
|
|
20
|
+
* and uses its markup, style, and class for the lifecycle.
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* // Default implementation registered via @ReComponent
|
|
24
|
+
* @ReComponent({ markupURL: './Button.hmle', cssURL: './Button.css' }, "re-button")
|
|
25
|
+
* class ReButton extends Component { ... }
|
|
26
|
+
*
|
|
27
|
+
* // Alternative implementation registered via @ReImplementation
|
|
28
|
+
* @ReImplementation({ markupURL: './FancyButton.hmle', cssURL: './Fancy.css' }, "re-button")
|
|
29
|
+
* class FancyButton extends Component { ... }
|
|
30
|
+
*
|
|
31
|
+
* // Switch globally — all re-button instances reload
|
|
32
|
+
* Placeholder.switchTo("re-button", "FancyButton");
|
|
33
|
+
*
|
|
34
|
+
* // Switch one instance only
|
|
35
|
+
* Placeholder.switchInstance("re-button", myBtnInstance, "FancyButton");
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
15
38
|
export default class Triplet {
|
|
16
|
-
markup;
|
|
17
|
-
css;
|
|
18
|
-
lightCss;
|
|
19
|
-
js;
|
|
20
|
-
markupURL;
|
|
21
|
-
cssURL;
|
|
22
|
-
ltCssURL;
|
|
23
|
-
jsURL;
|
|
24
39
|
access;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.cssURL = struct.cssURL;
|
|
29
|
-
this.ltCssURL = struct.ltCssURL;
|
|
30
|
-
this.jsURL = struct.jsURL;
|
|
31
|
-
let markup = Promise.resolve(struct.markup);
|
|
32
|
-
if (struct.markupURL)
|
|
33
|
-
markup = Fetcher.fetchText(struct.markupURL);
|
|
34
|
-
let css = Promise.resolve(struct.css);
|
|
35
|
-
if (struct.cssURL)
|
|
36
|
-
css = Fetcher.fetchText(struct.cssURL);
|
|
37
|
-
let ltCss = Promise.resolve(struct.ltCss);
|
|
38
|
-
if (struct.ltCssURL)
|
|
39
|
-
ltCss = Fetcher.fetchText(struct.ltCssURL);
|
|
40
|
-
/*let js = Promise.resolve(undefined);
|
|
41
|
-
if (struct.jsURL)
|
|
42
|
-
js = Fetcher.fetchText(struct.jsURL);*/
|
|
43
|
-
this.markup = markup;
|
|
44
|
-
this.css = css;
|
|
45
|
-
this.lightCss = ltCss;
|
|
46
|
-
//this.js = js;
|
|
40
|
+
placeholderName;
|
|
41
|
+
implementation;
|
|
42
|
+
constructor(struct, implName) {
|
|
47
43
|
this.access = struct.access ?? AccessType.BOTH;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
async init() {
|
|
51
|
-
const isOnline = await ServiceWorker.isOnline();
|
|
52
|
-
if (this.access === AccessType.NONE)
|
|
53
|
-
return false;
|
|
54
|
-
if (this.access === AccessType.BOTH) {
|
|
55
|
-
await this.cache();
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
;
|
|
59
|
-
if (this.access === AccessType.OFFLINE && isOnline)
|
|
60
|
-
return false;
|
|
61
|
-
if (this.access === AccessType.ONLINE && !isOnline)
|
|
62
|
-
return false;
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
async cache() {
|
|
66
|
-
//
|
|
44
|
+
const name = implName ?? struct.class?.name ?? "default";
|
|
45
|
+
this.implementation = new Implementation(name, struct);
|
|
67
46
|
}
|
|
68
47
|
async register(type, name) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.uni = Component;
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
48
|
+
const placeholder = Placeholder.get(name);
|
|
49
|
+
placeholder.addImplementation(this.implementation);
|
|
50
|
+
// If the placeholder already has a registered element/route, skip re-registration
|
|
51
|
+
if (placeholder.implementations.size > 1) {
|
|
52
|
+
console.info(`[Triplet]: Implementation "${this.implementation.name}" added to existing placeholder "${name}"`);
|
|
53
|
+
return;
|
|
78
54
|
}
|
|
79
|
-
|
|
80
|
-
var style = await new CSSStyleSheet().replace(await this.lightCss);
|
|
81
|
-
document.adoptedStyleSheets = [
|
|
82
|
-
...document.adoptedStyleSheets,
|
|
83
|
-
style
|
|
84
|
-
];
|
|
85
|
-
}
|
|
86
|
-
let ori = this.createInjectedClass(this.uni, type);
|
|
55
|
+
// First implementation — register the placeholder shell
|
|
87
56
|
if (type === "router") {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
57
|
+
REGISTRY.push(() => {
|
|
58
|
+
const routePath = name;
|
|
59
|
+
Router.registerRoute("", routePath, (search) => {
|
|
60
|
+
const impl = placeholder.getActive();
|
|
61
|
+
const cls = impl.uniClass ?? Page;
|
|
62
|
+
const paramNames = (() => {
|
|
63
|
+
const ctor = cls.prototype.constructor;
|
|
64
|
+
const fnStr = ctor.toString();
|
|
65
|
+
const argsMatch = fnStr.match(/constructor\s*\(([^)]*)\)/);
|
|
66
|
+
if (!argsMatch)
|
|
67
|
+
return [];
|
|
68
|
+
return argsMatch[1].split(',').map(s => s.trim()).filter(Boolean);
|
|
69
|
+
})();
|
|
70
|
+
const args = paramNames.map(n => search?.get(n));
|
|
71
|
+
const instance = new cls(...args);
|
|
72
|
+
// Attach placeholder context to instance for _init resolution
|
|
73
|
+
instance._placeholderName = name;
|
|
74
|
+
instance._activeImplementation = impl;
|
|
75
|
+
placeholder.trackInstance(instance);
|
|
76
|
+
return instance;
|
|
100
77
|
});
|
|
101
|
-
|
|
78
|
+
console.info(`[Triplet]: Router route "${name}" registered as placeholder`);
|
|
102
79
|
});
|
|
103
|
-
console.info(`[Triplet]` + `: Router route '${name}' registered for path '${routePath}' by class ${ori}.`);
|
|
104
|
-
return reg.then(() => true).catch(() => false);
|
|
105
80
|
}
|
|
106
81
|
else if (type === "markup") {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
82
|
+
REGISTRY.push(() => {
|
|
83
|
+
if (customElements.get(name))
|
|
84
|
+
throw new Error(`Custom element '${name}' is already defined.`);
|
|
85
|
+
const cls = this.implementation.uniClass ?? Component;
|
|
86
|
+
const placeholderRef = placeholder;
|
|
87
|
+
const placeholderName = name;
|
|
88
|
+
// Create the placeholder class that delegates to the active implementation
|
|
89
|
+
let proto = cls.prototype;
|
|
90
|
+
proto._init = async function () {
|
|
91
|
+
// Resolve which implementation to use (per-instance override or global)
|
|
92
|
+
const impl = this._activeImplementation
|
|
93
|
+
?? placeholderRef.getActive();
|
|
94
|
+
if (!impl)
|
|
95
|
+
throw new Error(`[Placeholder:${placeholderName}]: No active implementation.`);
|
|
96
|
+
// Store for reload
|
|
97
|
+
this._placeholderName = placeholderName;
|
|
98
|
+
if (!this._activeImplementation)
|
|
99
|
+
this._activeImplementation = impl;
|
|
100
|
+
placeholderRef.trackInstance(this);
|
|
101
|
+
// Load markup
|
|
102
|
+
const markupText = await impl.markup;
|
|
103
|
+
const holder = TemplateEngine.createHolder(markupText, Scope.from(this));
|
|
104
|
+
// Apply scoped CSS
|
|
105
|
+
const dmc = this.shadowRoot ?? document;
|
|
106
|
+
const cssText = await impl.style;
|
|
107
|
+
if (cssText) {
|
|
108
|
+
dmc.adoptedStyleSheets.push(await new CSSStyleSheet().replace(cssText));
|
|
109
|
+
}
|
|
110
|
+
// Apply global CSS
|
|
111
|
+
const globalCss = await impl.globalStyle;
|
|
112
|
+
if (globalCss) {
|
|
113
|
+
document.adoptedStyleSheets.push(await new CSSStyleSheet().replace(globalCss));
|
|
114
|
+
}
|
|
115
|
+
return holder;
|
|
116
|
+
};
|
|
117
|
+
customElements.define(name, cls.prototype.constructor);
|
|
118
|
+
console.info(`[Triplet]: Custom element "${name}" registered as placeholder`);
|
|
119
|
+
});
|
|
112
120
|
}
|
|
113
|
-
return Promise.resolve(false);
|
|
114
|
-
}
|
|
115
|
-
createInjectedClass(c, type) {
|
|
116
|
-
let that = this;
|
|
117
|
-
let ori = class extends c {
|
|
118
|
-
constructor(...args) {
|
|
119
|
-
super(...args);
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
let proto = ori.prototype;
|
|
123
|
-
const parser = new TemplateEngine();
|
|
124
|
-
proto._init = async function () {
|
|
125
|
-
const markupText = await that.markup;
|
|
126
|
-
return TemplateEngine.createHolder(markupText, Scope.from(this));
|
|
127
|
-
};
|
|
128
|
-
proto._postInit = async function (preHtml) {
|
|
129
|
-
const dmc = this.shadowRoot ?? document;
|
|
130
|
-
const css = await that.css;
|
|
131
|
-
var style = await new CSSStyleSheet().replace(css);
|
|
132
|
-
dmc.adoptedStyleSheets = [
|
|
133
|
-
...dmc.adoptedStyleSheets,
|
|
134
|
-
style
|
|
135
|
-
];
|
|
136
|
-
//parser.hydrate(preHtml, this);
|
|
137
|
-
return preHtml;
|
|
138
|
-
};
|
|
139
|
-
return ori;
|
|
140
121
|
}
|
|
141
122
|
}
|
|
142
123
|
//# sourceMappingURL=Triplet.js.map
|