@teqfw/di 2.2.0 → 2.3.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/CHANGELOG.md +5 -0
- package/README.md +13 -2
- package/ai/dependency-id.md +13 -4
- package/ai/usage.md +9 -2
- package/dist/esm.js +1 -1
- package/dist/umd.js +1 -1
- package/package.json +2 -1
- package/src/Def/Parser.mjs +30 -36
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.3.0 - 2026-03-25 - Release preparation update
|
|
4
|
+
|
|
5
|
+
- Updated package version metadata to `2.3.0`.
|
|
6
|
+
- Included the current working tree changes in the release preparation commit.
|
|
7
|
+
|
|
3
8
|
## 2.2.0 - 2026-03-16 - Agent interface alignment release
|
|
4
9
|
|
|
5
10
|
- Clarified lifecycle marker semantics in the agent interface documentation to match parser behavior (`$`, `$$`, and `$$$`).
|
package/README.md
CHANGED
|
@@ -233,12 +233,16 @@ App_Service
|
|
|
233
233
|
App_Service$
|
|
234
234
|
App_Service__build$$
|
|
235
235
|
App_Service$$_wrapLog_wrapTrace
|
|
236
|
-
|
|
237
|
-
|
|
236
|
+
node:fs
|
|
237
|
+
npm:@humanfs/core
|
|
238
|
+
node:worker_threads
|
|
239
|
+
npm:lodash
|
|
238
240
|
```
|
|
239
241
|
|
|
240
242
|
Where:
|
|
241
243
|
|
|
244
|
+
- `node:` platform prefix for Node.js built-in modules
|
|
245
|
+
- `npm:` platform prefix for npm packages
|
|
242
246
|
- `$` singleton lifecycle
|
|
243
247
|
- `$$` new instance lifecycle
|
|
244
248
|
- wrappers modify runtime behavior
|
|
@@ -292,6 +296,13 @@ Wrappers can implement:
|
|
|
292
296
|
|
|
293
297
|
This acts as a lightweight **DI-level AOP mechanism.**
|
|
294
298
|
|
|
299
|
+
Platform-specific examples:
|
|
300
|
+
|
|
301
|
+
```txt
|
|
302
|
+
node:worker_threads
|
|
303
|
+
npm:@humanfs/core
|
|
304
|
+
```
|
|
305
|
+
|
|
295
306
|
## Test Mode
|
|
296
307
|
|
|
297
308
|
```javascript
|
package/ai/dependency-id.md
CHANGED
|
@@ -32,14 +32,16 @@ A CDC may reference modules provided by the runtime platform or external package
|
|
|
32
32
|
|
|
33
33
|
The following prefixes are supported:
|
|
34
34
|
|
|
35
|
-
- **`
|
|
36
|
-
- **`
|
|
35
|
+
- **`node:`** — reference a built-in Node.js module.
|
|
36
|
+
- **`npm:`** — reference a module from the npm ecosystem.
|
|
37
37
|
|
|
38
38
|
Examples:
|
|
39
39
|
|
|
40
40
|
```txt
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
node:fs$
|
|
42
|
+
npm:@humanfs/core$
|
|
43
|
+
node:worker_threads$
|
|
44
|
+
npm:lodash$
|
|
43
45
|
```
|
|
44
46
|
|
|
45
47
|
If no platform prefix is present, the identifier refers to an application module resolved through namespace mapping.
|
|
@@ -103,6 +105,13 @@ In this example the container creates a new instance and applies the wrappers `w
|
|
|
103
105
|
|
|
104
106
|
Wrapper behavior is described in **extensions.md**.
|
|
105
107
|
|
|
108
|
+
Platform-specific examples:
|
|
109
|
+
|
|
110
|
+
```txt
|
|
111
|
+
node:worker_threads$
|
|
112
|
+
npm:@humanfs/core$
|
|
113
|
+
```
|
|
114
|
+
|
|
106
115
|
## Resolution Semantics
|
|
107
116
|
|
|
108
117
|
When the container receives a CDC it performs the following interpretation steps:
|
package/ai/usage.md
CHANGED
|
@@ -200,12 +200,19 @@ Typical usage:
|
|
|
200
200
|
CDC may reference runtime platform modules.
|
|
201
201
|
|
|
202
202
|
```text
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
node:fs
|
|
204
|
+
npm:@humanfs/core
|
|
205
|
+
node:worker_threads
|
|
206
|
+
npm:lodash
|
|
205
207
|
```
|
|
206
208
|
|
|
207
209
|
These identifiers provide access to Node.js built-ins and npm packages.
|
|
208
210
|
|
|
211
|
+
Typical usage:
|
|
212
|
+
|
|
213
|
+
- `node:worker_threads` for Node.js worker-thread primitives
|
|
214
|
+
- `npm:@humanfs/core` for a scoped npm package dependency
|
|
215
|
+
|
|
209
216
|
### Root Graph Resolution
|
|
210
217
|
|
|
211
218
|
Applications typically resolve a single root dependency.
|
package/dist/esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const r=o.TEQ,n=e.AS_IS,i=new Set(Object.values(o)),s=new Set(Object.values(e)),a=new Set(Object.values(t));let l=class{moduleName;platform;exportName;composition;life;wrappers;origin},c=class{create(e){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};class p{constructor(){const r=new c;let n=null;this.parse=function(i){if(n&&n.log(`Parser.parse: input='${i}'.`),"string"!=typeof i)throw new Error("CDC must be a string.");if(0===i.length)throw new Error("CDC must be non-empty.");if(!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(i))throw new Error("CDC must satisfy AsciiCdcIdentifier.");const s=i;let a=i,l=o.TEQ;if(a.startsWith("node_"))l=o.NODE,a=a.slice(5);else if(a.startsWith("npm_"))l=o.NPM,a=a.slice(4);else if(a.startsWith("teq_"))throw new Error("Explicit teq_ prefix is forbidden.");if(0===a.length)throw new Error("moduleName must be non-empty.");const c=a.match(/(\${1,3})(?:_([A-Za-z0-9]+(?:_[A-Za-z0-9]+)*))?$/);let p=null,f=[],u=a;if(c){const e=c[1],o=c[2];if("$"===e)p=t.SINGLETON;else{if("$$"!==e&&"$$$"!==e)throw new Error("Lifecycle marker overflow.");p=t.TRANSIENT}if(u=a.slice(0,c.index),o){f=o.split("_");for(const e of f){if(!e)throw new Error("Wrapper must be non-empty.");if(e.includes("$"))throw new Error("Wrapper must not contain $.");if(e.includes("_"))throw new Error("Wrapper must not contain _.")}}}else{if(a.includes("$"))throw new Error("Invalid lifecycle marker.");if(a.match(/(?:^|[^_])_([a-z][A-Za-z0-9]*)$/))throw new Error("Wrapper without lifecycle is forbidden.")}if(u.includes("$$$$"))throw new Error("Lifecycle marker overflow.");const d=u.indexOf("__"),m=u.lastIndexOf("__");if(-1!==d&&d!==m)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let g=u,w=null;if(-1!==d){if(g=u.slice(0,d),w=u.slice(d+2),!w)throw new Error("Export must be non-empty.");if(w.includes("_"))throw new Error("Export must not contain _.");if(w.includes("$"))throw new Error("Export must not contain $.")}if(!g)throw new Error("moduleName must be non-empty.");if(g.startsWith("_")||g.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(g.includes("__"))throw new Error("moduleName must not contain __.");if(g.includes("$"))throw new Error("moduleName must not contain $.");let h=e.AS_IS;null!==w?h=e.FACTORY:p===t.SINGLETON?(w="default",h=e.FACTORY):p===t.TRANSIENT&&(h=e.FACTORY,null===w&&(w="default"));const $=r.create({moduleName:g,platform:l,exportName:w,composition:h,life:p,wrappers:f,origin:s});return n&&n.log(`Parser.parse: produced='${$.platform}::${$.moduleName}'.`),$},this.setLogger=function(e){n=e}}}let f=class{prefix;target;defaultExt},u=class{create(e){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class d{namespaces;nodeModulesRoot}class m{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new d,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}class g{constructor({config:e,importFn:t=e=>import(e),logger:o=null}){const r=new Map,n=e;let i;const s=t,a=o,l=function(e,t){if("node"===e){const e=`node:${t}`;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("npm"===e){const e=t;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("teq"!==e)throw new Error(`Unsupported platform: ${e}`);const o=function(e){let t=null,o=-1;const r=i.namespaces;for(const n of r){const r=e.startsWith(n.prefix);a&&a.log(`Resolver.namespace: prefix='${n.prefix}' match=${String(r)} module='${e}'.`),r&&n.prefix.length>o&&(t=n,o=n.prefix.length)}if(!t)throw new Error(`Namespace rule is not found for '${e}'.`);return t}(t),r=t.slice(o.prefix.length).split("_").join("/"),n=(s=r,(l=o.defaultExt)?s.endsWith(l)?s:`${s}${l}`:s);var s,l;const c=function(e,t){return e?e.endsWith("/")?`${e}${t}`:`${e}/${t}`:t}(o.target,n);return a&&a.log(`Resolver.specifier: module='${t}' -> '${c}'.`),c};this.resolve=async function(e){var t;await Promise.resolve(),i||(i={nodeModulesRoot:(t=n).nodeModulesRoot,namespaces:t.namespaces.map(e=>({prefix:e.prefix,target:e.target,defaultExt:e.defaultExt}))});const o=e.platform,c=e.moduleName,p=`${o}::${c}`;if(r.has(p))return a&&a.log(`Resolver.cache: hit key='${p}'.`),r.get(p);a&&a.log(`Resolver.cache: miss key='${p}'.`);const f=(async()=>{const e=l(o,c);return a&&a.log(`Resolver.import: '${e}'.`),s(e)})();r.set(p,f);try{return await f}catch(e){throw r.delete(p),a&&a.error(`Resolver.cache: evict key='${p}' after failure.`,e),e}}}}class w{constructor({parser:e,resolver:t,logger:o=null}){const r=o,n=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;const f=c;for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(e,t,o,[]),t}}}class h{constructor(){this.instantiate=function(t,o,r){const n=function(e,t){if(null===e.exportName)return t;if(!(e.exportName in t))throw new Error(`Export '${e.exportName}' is not found in module namespace.`);return t[e.exportName]}(t,o);if(t.composition===e.AS_IS)return n;if(t.composition===e.FACTORY){if("function"!=typeof n)throw new Error("Factory composition requires a callable export.");const e=n;let t;if(function(e){try{return Reflect.construct(String,[],e),!0}catch{return!1}}(e)){t=new e(r)}else{t=e(r)}if(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");return t}throw new Error(`Unsupported composition mode: ${String(t.composition)}.`)}}}class ${constructor(o=null){const r=new Map,n=o;this.apply=function(o,i){if(o.composition!==e.FACTORY)return n&&n.log(`Lifecycle.apply: composition='${o.composition}' cache=skip.`),i();if(o.life===t.TRANSIENT)return n&&n.log("Lifecycle.apply: transient cache=skip."),i();if(o.life===t.SINGLETON){const e=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")}(o);if(r.has(e))return n&&n.log(`Lifecycle.cache: hit key='${e}'.`),r.get(e);n&&n.log(`Lifecycle.cache: miss key='${e}', create.`);const t=i();return r.set(e,t),n&&n.log(`Lifecycle.cache: stored key='${e}'.`),t}return n&&n.log("Lifecycle.apply: no lifecycle marker cache=skip."),i()}}}class y{constructor(){const e=function(e){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}class N{constructor(e="teqfw/di"){const t=`[${e}]`;this.log=function(e){console.debug(`${t} ${e}`)},this.error=function(e,o){console.error(`${t} ${e}`),o instanceof Error?console.error(o.stack??o.message):void 0!==o&&console.error(o)}}}const E=Object.freeze({log(){},error(){}});class x{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new m;let f,u,d,x=E;const C=new h,v=new y,b=function(e){const t=null===e.exportName?"":e.exportName,o=null===e.life?"":e.life,r=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,t,e.composition,o,r].join("::")},_=function(e){return b(e)},I=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){x.log(`Container.freeze: skipped (${String(e)}).`)}return e},R=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},j=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},A=function(e){a&&x.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){j(),A("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){j(),A("addPostprocess()."),o.push(e)},this.setParser=function(e){j(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?x:null),A("setParser().")},this.addNamespaceRoot=function(e,t,o){j(),A(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){j(),A("enableTestMode()."),s=!0},this.enableLogging=function(){j(),a||(a=!0,x=new N,"function"==typeof l.setLogger&&l.setLogger(x),x.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(j(),A(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(_(o),t)},this.get=async function(i){if("failed"===e)throw x.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{x.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;x.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(x),f=new g({config:t,logger:x}),u=new w({parser:l,resolver:f,logger:x}),d=new $(x)}(),x.log(`Container.state: '${e}'.`),a="parse",x.log("Container.pipeline: parse:entry.");const p=l.parse(i);x.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",x.log("Container.pipeline: preprocess:entry.");const m=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(x.log(`Container.pipeline: preprocess:exit '${m.platform}::${m.moduleName}'.`),!0===s){a="mock",x.log("Container.pipeline: mock-lookup:entry.");const e=_(m);if(n.has(e)){x.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",x.log("Container.pipeline: freeze:entry.");const t=I(n.get(e));return x.log("Container.pipeline: freeze:exit."),x.log("Container.pipeline: return:success."),R(t)}x.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else x.log("Container.pipeline: mock-lookup:disabled.");a="resolve",x.log("Container.pipeline: resolve:entry.");const h=await u.resolve(m);x.log(`Container.pipeline: resolve:exit nodes=${h.size}.`);const y=new Map,N=function(e){if(y.has(e))return y.get(e);if(!h.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=h.get(e);a="lifecycle",x.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=d.apply(t.depId,function(){a="instantiate",x.log(`Container.pipeline: instantiate:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const e={},r=function(e){const t=Reflect.get(e,"__deps__");return void 0===t?{}:t}(t.namespace);for(const[t,o]of Object.entries(r)){const r=o,n=l.parse(r);e[t]=N(b(n))}const n=C.instantiate(t.depId,t.namespace,e);x.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",x.log(`Container.pipeline: postprocess:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const i=function(e){let t=e;for(const e of o)t=e(t);return t}(n);x.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=v.execute(t.depId,i,t.namespace);a="freeze",x.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=I(s);return x.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return x.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),y.set(e,r),r},E=N(b(m));return x.log("Container.pipeline: return:success."),R(E)}catch(t){throw x.error(`Container.pipeline: failed at stage='${a}'.`,t),x.log("Container.transition: operational -> failed."),e="failed",t}}}}export{x as default};
|
|
1
|
+
var e=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const r=o.TEQ,n=e.AS_IS,i=new Set(Object.values(o)),s=new Set(Object.values(e)),a=new Set(Object.values(t));let l=class{moduleName;platform;exportName;composition;life;wrappers;origin},c=class{create(e){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};class p{constructor(){const r=new c;let n=null;this.parse=function(i){if(n&&n.log(`Parser.parse: input='${i}'.`),"string"!=typeof i)throw new Error("CDC must be a string.");if(0===i.length)throw new Error("CDC must be non-empty.");if(!/^[\x00-\x7F]+$/.test(i))throw new Error("CDC must be ASCII.");const s=i;let a=i,l=o.TEQ;if(a.startsWith("node:"))l=o.NODE,a=a.slice(5);else if(a.startsWith("npm:"))l=o.NPM,a=a.slice(4);else if(a.startsWith("teq:"))throw new Error("Explicit teq: prefix is forbidden.");if(0===a.length)throw new Error("moduleName must be non-empty.");let c=null,p=!1,f=[],u=a;const d=u.match(/(\${1,3})(?:_[a-z][0-9A-Za-z]*)*$/);if(d){const e=d[1],o=d[0].slice(e.length);if(p=!0,"$"===e)c=t.SINGLETON;else if("$$"===e)c=t.TRANSIENT;else{if("$$$"!==e)throw new Error("Lifecycle marker is invalid.");c=null}u=u.slice(0,d.index),o.length>0&&(f=o.slice(1).split("_"))}else{if(a.includes("$"))throw new Error("Invalid lifecycle encoding.");if(/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(a))throw new Error("Wrapper without lifecycle is forbidden.")}const m=u.indexOf("__"),g=u.lastIndexOf("__");if(-1!==m&&m!==g)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let w=u,h=null;if(-1!==m){if(w=u.slice(0,m),h=u.slice(m+2),!h)throw new Error("Export must be non-empty.");if(h.includes("_"))throw new Error("Export must not contain _.");if(h.includes("$"))throw new Error("Export must not contain $.")}if(!w)throw new Error("moduleName must be non-empty.");if(w.startsWith("_")||w.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(w.includes("__"))throw new Error("moduleName must not contain __.");if(w.includes("$"))throw new Error("moduleName must not contain $.");if(l!==o.NPM){if(!/^[A-Za-z_][$0-9A-Za-z_]*$/.test(w))throw new Error("moduleName must satisfy the canonical identifier form.")}else if(!/^[@A-Za-z_][$0-9A-Za-z_./-]*$/.test(w))throw new Error("npm moduleName must satisfy the package specifier form.");let $=e.AS_IS;null!==h?$=e.FACTORY:p&&($=e.FACTORY,h="default");const y=r.create({moduleName:w,platform:l,exportName:h,composition:$,life:c,wrappers:f,origin:s});return n&&n.log(`Parser.parse: produced='${y.platform}::${y.moduleName}'.`),y},this.setLogger=function(e){n=e}}}let f=class{prefix;target;defaultExt},u=class{create(e){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class d{namespaces;nodeModulesRoot}class m{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new d,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}class g{constructor({config:e,importFn:t=e=>import(e),logger:o=null}){const r=new Map,n=e;let i;const s=t,a=o,l=function(e,t){if("node"===e){const e=`node:${t}`;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("npm"===e){const e=t;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("teq"!==e)throw new Error(`Unsupported platform: ${e}`);const o=function(e){let t=null,o=-1;const r=i.namespaces;for(const n of r){const r=e.startsWith(n.prefix);a&&a.log(`Resolver.namespace: prefix='${n.prefix}' match=${String(r)} module='${e}'.`),r&&n.prefix.length>o&&(t=n,o=n.prefix.length)}if(!t)throw new Error(`Namespace rule is not found for '${e}'.`);return t}(t),r=t.slice(o.prefix.length).split("_").join("/"),n=(s=r,(l=o.defaultExt)?s.endsWith(l)?s:`${s}${l}`:s);var s,l;const c=function(e,t){return e?e.endsWith("/")?`${e}${t}`:`${e}/${t}`:t}(o.target,n);return a&&a.log(`Resolver.specifier: module='${t}' -> '${c}'.`),c};this.resolve=async function(e){var t;await Promise.resolve(),i||(i={nodeModulesRoot:(t=n).nodeModulesRoot,namespaces:t.namespaces.map(e=>({prefix:e.prefix,target:e.target,defaultExt:e.defaultExt}))});const o=e.platform,c=e.moduleName,p=`${o}::${c}`;if(r.has(p))return a&&a.log(`Resolver.cache: hit key='${p}'.`),r.get(p);a&&a.log(`Resolver.cache: miss key='${p}'.`);const f=(async()=>{const e=l(o,c);return a&&a.log(`Resolver.import: '${e}'.`),s(e)})();r.set(p,f);try{return await f}catch(e){throw r.delete(p),a&&a.error(`Resolver.cache: evict key='${p}' after failure.`,e),e}}}}class w{constructor({parser:e,resolver:t,logger:o=null}){const r=o,n=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;const f=c;for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(e,t,o,[]),t}}}class h{constructor(){this.instantiate=function(t,o,r){const n=function(e,t){if(null===e.exportName)return t;if(!(e.exportName in t))throw new Error(`Export '${e.exportName}' is not found in module namespace.`);return t[e.exportName]}(t,o);if(t.composition===e.AS_IS)return n;if(t.composition===e.FACTORY){if("function"!=typeof n)throw new Error("Factory composition requires a callable export.");const e=n;let t;if(function(e){try{return Reflect.construct(String,[],e),!0}catch{return!1}}(e)){t=new e(r)}else{t=e(r)}if(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");return t}throw new Error(`Unsupported composition mode: ${String(t.composition)}.`)}}}class ${constructor(o=null){const r=new Map,n=o;this.apply=function(o,i){if(o.composition!==e.FACTORY)return n&&n.log(`Lifecycle.apply: composition='${o.composition}' cache=skip.`),i();if(o.life===t.TRANSIENT)return n&&n.log("Lifecycle.apply: transient cache=skip."),i();if(o.life===t.SINGLETON){const e=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")}(o);if(r.has(e))return n&&n.log(`Lifecycle.cache: hit key='${e}'.`),r.get(e);n&&n.log(`Lifecycle.cache: miss key='${e}', create.`);const t=i();return r.set(e,t),n&&n.log(`Lifecycle.cache: stored key='${e}'.`),t}return n&&n.log("Lifecycle.apply: no lifecycle marker cache=skip."),i()}}}class y{constructor(){const e=function(e){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}class N{constructor(e="teqfw/di"){const t=`[${e}]`;this.log=function(e){console.debug(`${t} ${e}`)},this.error=function(e,o){console.error(`${t} ${e}`),o instanceof Error?console.error(o.stack??o.message):void 0!==o&&console.error(o)}}}const x=Object.freeze({log(){},error(){}});class E{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new m;let f,u,d,E=x;const C=new h,b=new y,v=function(e){const t=null===e.exportName?"":e.exportName,o=null===e.life?"":e.life,r=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,t,e.composition,o,r].join("::")},_=function(e){return v(e)},I=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){E.log(`Container.freeze: skipped (${String(e)}).`)}return e},j=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},R=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},A=function(e){a&&E.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){R(),A("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){R(),A("addPostprocess()."),o.push(e)},this.setParser=function(e){R(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?E:null),A("setParser().")},this.addNamespaceRoot=function(e,t,o){R(),A(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){R(),A("enableTestMode()."),s=!0},this.enableLogging=function(){R(),a||(a=!0,E=new N,"function"==typeof l.setLogger&&l.setLogger(E),E.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(R(),A(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(_(o),t)},this.get=async function(i){if("failed"===e)throw E.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{E.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;E.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(E),f=new g({config:t,logger:E}),u=new w({parser:l,resolver:f,logger:E}),d=new $(E)}(),E.log(`Container.state: '${e}'.`),a="parse",E.log("Container.pipeline: parse:entry.");const p=l.parse(i);E.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",E.log("Container.pipeline: preprocess:entry.");const m=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(E.log(`Container.pipeline: preprocess:exit '${m.platform}::${m.moduleName}'.`),!0===s){a="mock",E.log("Container.pipeline: mock-lookup:entry.");const e=_(m);if(n.has(e)){E.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",E.log("Container.pipeline: freeze:entry.");const t=I(n.get(e));return E.log("Container.pipeline: freeze:exit."),E.log("Container.pipeline: return:success."),j(t)}E.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else E.log("Container.pipeline: mock-lookup:disabled.");a="resolve",E.log("Container.pipeline: resolve:entry.");const h=await u.resolve(m);E.log(`Container.pipeline: resolve:exit nodes=${h.size}.`);const y=new Map,N=function(e){if(y.has(e))return y.get(e);if(!h.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=h.get(e);a="lifecycle",E.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=d.apply(t.depId,function(){a="instantiate",E.log(`Container.pipeline: instantiate:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const e={},r=function(e){const t=Reflect.get(e,"__deps__");return void 0===t?{}:t}(t.namespace);for(const[t,o]of Object.entries(r)){const r=o,n=l.parse(r);e[t]=N(v(n))}const n=C.instantiate(t.depId,t.namespace,e);E.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",E.log(`Container.pipeline: postprocess:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const i=function(e){let t=e;for(const e of o)t=e(t);return t}(n);E.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=b.execute(t.depId,i,t.namespace);a="freeze",E.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=I(s);return E.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return E.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),y.set(e,r),r},x=N(v(m));return E.log("Container.pipeline: return:success."),j(x)}catch(t){throw E.error(`Container.pipeline: failed at stage='${a}'.`,t),E.log("Container.transition: operational -> failed."),e="failed",t}}}}export{E as default};
|
package/dist/umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).TeqFw_Di_Container=t()}(this,function(){"use strict";var e=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const r=o.TEQ,n=e.AS_IS,i=new Set(Object.values(o)),s=new Set(Object.values(e)),a=new Set(Object.values(t));let l=class{moduleName;platform;exportName;composition;life;wrappers;origin},c=class{create(e){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};class p{constructor(){const r=new c;let n=null;this.parse=function(i){if(n&&n.log(`Parser.parse: input='${i}'.`),"string"!=typeof i)throw new Error("CDC must be a string.");if(0===i.length)throw new Error("CDC must be non-empty.");if(!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(i))throw new Error("CDC must satisfy AsciiCdcIdentifier.");const s=i;let a=i,l=o.TEQ;if(a.startsWith("node_"))l=o.NODE,a=a.slice(5);else if(a.startsWith("npm_"))l=o.NPM,a=a.slice(4);else if(a.startsWith("teq_"))throw new Error("Explicit teq_ prefix is forbidden.");if(0===a.length)throw new Error("moduleName must be non-empty.");const c=a.match(/(\${1,3})(?:_([A-Za-z0-9]+(?:_[A-Za-z0-9]+)*))?$/);let p=null,f=[],u=a;if(c){const e=c[1],o=c[2];if("$"===e)p=t.SINGLETON;else{if("$$"!==e&&"$$$"!==e)throw new Error("Lifecycle marker overflow.");p=t.TRANSIENT}if(u=a.slice(0,c.index),o){f=o.split("_");for(const e of f){if(!e)throw new Error("Wrapper must be non-empty.");if(e.includes("$"))throw new Error("Wrapper must not contain $.");if(e.includes("_"))throw new Error("Wrapper must not contain _.")}}}else{if(a.includes("$"))throw new Error("Invalid lifecycle marker.");if(a.match(/(?:^|[^_])_([a-z][A-Za-z0-9]*)$/))throw new Error("Wrapper without lifecycle is forbidden.")}if(u.includes("$$$$"))throw new Error("Lifecycle marker overflow.");const d=u.indexOf("__"),m=u.lastIndexOf("__");if(-1!==d&&d!==m)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let g=u,w=null;if(-1!==d){if(g=u.slice(0,d),w=u.slice(d+2),!w)throw new Error("Export must be non-empty.");if(w.includes("_"))throw new Error("Export must not contain _.");if(w.includes("$"))throw new Error("Export must not contain $.")}if(!g)throw new Error("moduleName must be non-empty.");if(g.startsWith("_")||g.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(g.includes("__"))throw new Error("moduleName must not contain __.");if(g.includes("$"))throw new Error("moduleName must not contain $.");let h=e.AS_IS;null!==w?h=e.FACTORY:p===t.SINGLETON?(w="default",h=e.FACTORY):p===t.TRANSIENT&&(h=e.FACTORY,null===w&&(w="default"));const $=r.create({moduleName:g,platform:l,exportName:w,composition:h,life:p,wrappers:f,origin:s});return n&&n.log(`Parser.parse: produced='${$.platform}::${$.moduleName}'.`),$},this.setLogger=function(e){n=e}}}let f=class{prefix;target;defaultExt},u=class{create(e){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class d{namespaces;nodeModulesRoot}class m{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new d,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}class g{constructor({config:e,importFn:t=e=>import(e),logger:o=null}){const r=new Map,n=e;let i;const s=t,a=o,l=function(e,t){if("node"===e){const e=`node:${t}`;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("npm"===e){const e=t;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("teq"!==e)throw new Error(`Unsupported platform: ${e}`);const o=function(e){let t=null,o=-1;const r=i.namespaces;for(const n of r){const r=e.startsWith(n.prefix);a&&a.log(`Resolver.namespace: prefix='${n.prefix}' match=${String(r)} module='${e}'.`),r&&n.prefix.length>o&&(t=n,o=n.prefix.length)}if(!t)throw new Error(`Namespace rule is not found for '${e}'.`);return t}(t),r=t.slice(o.prefix.length).split("_").join("/"),n=(s=r,(l=o.defaultExt)?s.endsWith(l)?s:`${s}${l}`:s);var s,l;const c=function(e,t){return e?e.endsWith("/")?`${e}${t}`:`${e}/${t}`:t}(o.target,n);return a&&a.log(`Resolver.specifier: module='${t}' -> '${c}'.`),c};this.resolve=async function(e){var t;await Promise.resolve(),i||(i={nodeModulesRoot:(t=n).nodeModulesRoot,namespaces:t.namespaces.map(e=>({prefix:e.prefix,target:e.target,defaultExt:e.defaultExt}))});const o=e.platform,c=e.moduleName,p=`${o}::${c}`;if(r.has(p))return a&&a.log(`Resolver.cache: hit key='${p}'.`),r.get(p);a&&a.log(`Resolver.cache: miss key='${p}'.`);const f=(async()=>{const e=l(o,c);return a&&a.log(`Resolver.import: '${e}'.`),s(e)})();r.set(p,f);try{return await f}catch(e){throw r.delete(p),a&&a.error(`Resolver.cache: evict key='${p}' after failure.`,e),e}}}}class w{constructor({parser:e,resolver:t,logger:o=null}){const r=o,n=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;const f=c;for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(e,t,o,[]),t}}}class h{constructor(){this.instantiate=function(t,o,r){const n=function(e,t){if(null===e.exportName)return t;if(!(e.exportName in t))throw new Error(`Export '${e.exportName}' is not found in module namespace.`);return t[e.exportName]}(t,o);if(t.composition===e.AS_IS)return n;if(t.composition===e.FACTORY){if("function"!=typeof n)throw new Error("Factory composition requires a callable export.");const e=n;let t;if(function(e){try{return Reflect.construct(String,[],e),!0}catch{return!1}}(e)){t=new e(r)}else{t=e(r)}if(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");return t}throw new Error(`Unsupported composition mode: ${String(t.composition)}.`)}}}class ${constructor(o=null){const r=new Map,n=o;this.apply=function(o,i){if(o.composition!==e.FACTORY)return n&&n.log(`Lifecycle.apply: composition='${o.composition}' cache=skip.`),i();if(o.life===t.TRANSIENT)return n&&n.log("Lifecycle.apply: transient cache=skip."),i();if(o.life===t.SINGLETON){const e=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")}(o);if(r.has(e))return n&&n.log(`Lifecycle.cache: hit key='${e}'.`),r.get(e);n&&n.log(`Lifecycle.cache: miss key='${e}', create.`);const t=i();return r.set(e,t),n&&n.log(`Lifecycle.cache: stored key='${e}'.`),t}return n&&n.log("Lifecycle.apply: no lifecycle marker cache=skip."),i()}}}class y{constructor(){const e=function(e){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}class N{constructor(e="teqfw/di"){const t=`[${e}]`;this.log=function(e){console.debug(`${t} ${e}`)},this.error=function(e,o){console.error(`${t} ${e}`),o instanceof Error?console.error(o.stack??o.message):void 0!==o&&console.error(o)}}}const E=Object.freeze({log(){},error(){}});return class{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new m;let f,u,d,x=E;const C=new h,b=new y,v=function(e){const t=null===e.exportName?"":e.exportName,o=null===e.life?"":e.life,r=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,t,e.composition,o,r].join("::")},_=function(e){return v(e)},I=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){x.log(`Container.freeze: skipped (${String(e)}).`)}return e},R=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},j=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},A=function(e){a&&x.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){j(),A("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){j(),A("addPostprocess()."),o.push(e)},this.setParser=function(e){j(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?x:null),A("setParser().")},this.addNamespaceRoot=function(e,t,o){j(),A(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){j(),A("enableTestMode()."),s=!0},this.enableLogging=function(){j(),a||(a=!0,x=new N,"function"==typeof l.setLogger&&l.setLogger(x),x.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(j(),A(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(_(o),t)},this.get=async function(i){if("failed"===e)throw x.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{x.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;x.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(x),f=new g({config:t,logger:x}),u=new w({parser:l,resolver:f,logger:x}),d=new $(x)}(),x.log(`Container.state: '${e}'.`),a="parse",x.log("Container.pipeline: parse:entry.");const p=l.parse(i);x.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",x.log("Container.pipeline: preprocess:entry.");const m=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(x.log(`Container.pipeline: preprocess:exit '${m.platform}::${m.moduleName}'.`),!0===s){a="mock",x.log("Container.pipeline: mock-lookup:entry.");const e=_(m);if(n.has(e)){x.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",x.log("Container.pipeline: freeze:entry.");const t=I(n.get(e));return x.log("Container.pipeline: freeze:exit."),x.log("Container.pipeline: return:success."),R(t)}x.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else x.log("Container.pipeline: mock-lookup:disabled.");a="resolve",x.log("Container.pipeline: resolve:entry.");const h=await u.resolve(m);x.log(`Container.pipeline: resolve:exit nodes=${h.size}.`);const y=new Map,N=function(e){if(y.has(e))return y.get(e);if(!h.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=h.get(e);a="lifecycle",x.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=d.apply(t.depId,function(){a="instantiate",x.log(`Container.pipeline: instantiate:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const e={},r=function(e){const t=Reflect.get(e,"__deps__");return void 0===t?{}:t}(t.namespace);for(const[t,o]of Object.entries(r)){const r=o,n=l.parse(r);e[t]=N(v(n))}const n=C.instantiate(t.depId,t.namespace,e);x.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",x.log(`Container.pipeline: postprocess:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const i=function(e){let t=e;for(const e of o)t=e(t);return t}(n);x.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=b.execute(t.depId,i,t.namespace);a="freeze",x.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=I(s);return x.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return x.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),y.set(e,r),r},E=N(v(m));return x.log("Container.pipeline: return:success."),R(E)}catch(t){throw x.error(`Container.pipeline: failed at stage='${a}'.`,t),x.log("Container.transition: operational -> failed."),e="failed",t}}}}});
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).TeqFw_Di_Container=t()}(this,function(){"use strict";var e=Object.freeze({AS_IS:"A",FACTORY:"F"});var t=Object.freeze({SINGLETON:"S",TRANSIENT:"T"});var o=Object.freeze({TEQ:"teq",NODE:"node",NPM:"npm"});const r=o.TEQ,n=e.AS_IS,i=new Set(Object.values(o)),s=new Set(Object.values(e)),a=new Set(Object.values(t));let l=class{moduleName;platform;exportName;composition;life;wrappers;origin},c=class{create(e){const t=e&&"object"==typeof e?e:{},o=new l;o.moduleName="string"==typeof t.moduleName?t.moduleName:"";const c="string"==typeof t.platform?t.platform:void 0;o.platform=c&&i.has(c)?c:r;let p=null;null===t.exportName?p=null:"string"==typeof t.exportName&&(p=t.exportName),o.exportName=p;const f="string"==typeof t.composition?t.composition:void 0;o.composition=f&&s.has(f)?f:n;const u="string"==typeof t.life?t.life:void 0;return o.life=u&&a.has(u)?u:null,o.wrappers=Array.isArray(t.wrappers)?t.wrappers.filter(e=>"string"==typeof e):[],o.origin="string"==typeof t.origin?t.origin:"",Object.freeze(o.wrappers),Object.freeze(o)}};class p{constructor(){const r=new c;let n=null;this.parse=function(i){if(n&&n.log(`Parser.parse: input='${i}'.`),"string"!=typeof i)throw new Error("CDC must be a string.");if(0===i.length)throw new Error("CDC must be non-empty.");if(!/^[\x00-\x7F]+$/.test(i))throw new Error("CDC must be ASCII.");const s=i;let a=i,l=o.TEQ;if(a.startsWith("node:"))l=o.NODE,a=a.slice(5);else if(a.startsWith("npm:"))l=o.NPM,a=a.slice(4);else if(a.startsWith("teq:"))throw new Error("Explicit teq: prefix is forbidden.");if(0===a.length)throw new Error("moduleName must be non-empty.");let c=null,p=!1,f=[],u=a;const d=u.match(/(\${1,3})(?:_[a-z][0-9A-Za-z]*)*$/);if(d){const e=d[1],o=d[0].slice(e.length);if(p=!0,"$"===e)c=t.SINGLETON;else if("$$"===e)c=t.TRANSIENT;else{if("$$$"!==e)throw new Error("Lifecycle marker is invalid.");c=null}u=u.slice(0,d.index),o.length>0&&(f=o.slice(1).split("_"))}else{if(a.includes("$"))throw new Error("Invalid lifecycle encoding.");if(/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(a))throw new Error("Wrapper without lifecycle is forbidden.")}const m=u.indexOf("__"),g=u.lastIndexOf("__");if(-1!==m&&m!==g)throw new Error("Export delimiter must appear at most once.");if(u.startsWith("__")||u.endsWith("__"))throw new Error("Malformed export segment.");let h=u,w=null;if(-1!==m){if(h=u.slice(0,m),w=u.slice(m+2),!w)throw new Error("Export must be non-empty.");if(w.includes("_"))throw new Error("Export must not contain _.");if(w.includes("$"))throw new Error("Export must not contain $.")}if(!h)throw new Error("moduleName must be non-empty.");if(h.startsWith("_")||h.startsWith("$"))throw new Error("moduleName must not start with _ or $.");if(h.includes("__"))throw new Error("moduleName must not contain __.");if(h.includes("$"))throw new Error("moduleName must not contain $.");if(l!==o.NPM){if(!/^[A-Za-z_][$0-9A-Za-z_]*$/.test(h))throw new Error("moduleName must satisfy the canonical identifier form.")}else if(!/^[@A-Za-z_][$0-9A-Za-z_./-]*$/.test(h))throw new Error("npm moduleName must satisfy the package specifier form.");let $=e.AS_IS;null!==w?$=e.FACTORY:p&&($=e.FACTORY,w="default");const y=r.create({moduleName:h,platform:l,exportName:w,composition:$,life:c,wrappers:f,origin:s});return n&&n.log(`Parser.parse: produced='${y.platform}::${y.moduleName}'.`),y},this.setLogger=function(e){n=e}}}let f=class{prefix;target;defaultExt},u=class{create(e){const t=e&&"object"==typeof e?e:{},o=new f;return o.prefix="string"==typeof t.prefix?t.prefix:void 0,o.target="string"==typeof t.target?t.target:void 0,o.defaultExt="string"==typeof t.defaultExt?t.defaultExt:void 0,Object.freeze(o)}};class d{namespaces;nodeModulesRoot}class m{constructor(){const e=new u;this.create=function(t){const o=t&&"object"==typeof t?t:{},r=new d,n=Array.isArray(o.namespaces)?o.namespaces:[];return r.namespaces=n.map(t=>e.create(t)),r.nodeModulesRoot="string"==typeof o.nodeModulesRoot?o.nodeModulesRoot:void 0,Object.freeze(r.namespaces),Object.freeze(r)}}}class g{constructor({config:e,importFn:t=e=>import(e),logger:o=null}){const r=new Map,n=e;let i;const s=t,a=o,l=function(e,t){if("node"===e){const e=`node:${t}`;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("npm"===e){const e=t;return a&&a.log(`Resolver.specifier: module='${t}' -> '${e}'.`),e}if("teq"!==e)throw new Error(`Unsupported platform: ${e}`);const o=function(e){let t=null,o=-1;const r=i.namespaces;for(const n of r){const r=e.startsWith(n.prefix);a&&a.log(`Resolver.namespace: prefix='${n.prefix}' match=${String(r)} module='${e}'.`),r&&n.prefix.length>o&&(t=n,o=n.prefix.length)}if(!t)throw new Error(`Namespace rule is not found for '${e}'.`);return t}(t),r=t.slice(o.prefix.length).split("_").join("/"),n=(s=r,(l=o.defaultExt)?s.endsWith(l)?s:`${s}${l}`:s);var s,l;const c=function(e,t){return e?e.endsWith("/")?`${e}${t}`:`${e}/${t}`:t}(o.target,n);return a&&a.log(`Resolver.specifier: module='${t}' -> '${c}'.`),c};this.resolve=async function(e){var t;await Promise.resolve(),i||(i={nodeModulesRoot:(t=n).nodeModulesRoot,namespaces:t.namespaces.map(e=>({prefix:e.prefix,target:e.target,defaultExt:e.defaultExt}))});const o=e.platform,c=e.moduleName,p=`${o}::${c}`;if(r.has(p))return a&&a.log(`Resolver.cache: hit key='${p}'.`),r.get(p);a&&a.log(`Resolver.cache: miss key='${p}'.`);const f=(async()=>{const e=l(o,c);return a&&a.log(`Resolver.import: '${e}'.`),s(e)})();r.set(p,f);try{return await f}catch(e){throw r.delete(p),a&&a.error(`Resolver.cache: evict key='${p}' after failure.`,e),e}}}}class h{constructor({parser:e,resolver:t,logger:o=null}){const r=o,n=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")},i=async function(o,s,a,l){const c=n(o);if(a.has(c)){const e=[...l,c].join(" -> ");throw new Error(`Cyclic dependency detected: ${e}`)}const p=n(o);if(!s.has(p)){a.add(c),l.push(c);try{const n=await t.resolve(o);r&&r.log(`GraphResolver.walk: resolved '${p}'.`),s.set(p,{depId:o,namespace:n});const c=Reflect.get(n,"__deps__");if(void 0===c)return;const f=c;for(const[,t]of Object.entries(f)){const o=t,n=e.parse(o);r&&r.log(`GraphResolver.walk: edge '${p}' -> '${n.platform}::${n.moduleName}'.`),await i(n,s,a,l)}}finally{l.pop(),a.delete(c)}}};this.resolve=async function(e){const t=new Map,o=new Set;return await i(e,t,o,[]),t}}}class w{constructor(){this.instantiate=function(t,o,r){const n=function(e,t){if(null===e.exportName)return t;if(!(e.exportName in t))throw new Error(`Export '${e.exportName}' is not found in module namespace.`);return t[e.exportName]}(t,o);if(t.composition===e.AS_IS)return n;if(t.composition===e.FACTORY){if("function"!=typeof n)throw new Error("Factory composition requires a callable export.");const e=n;let t;if(function(e){try{return Reflect.construct(String,[],e),!0}catch{return!1}}(e)){t=new e(r)}else{t=e(r)}if(t instanceof Promise)throw new Error("Factory composition must return synchronously (non-Promise).");return t}throw new Error(`Unsupported composition mode: ${String(t.composition)}.`)}}}class ${constructor(o=null){const r=new Map,n=o;this.apply=function(o,i){if(o.composition!==e.FACTORY)return n&&n.log(`Lifecycle.apply: composition='${o.composition}' cache=skip.`),i();if(o.life===t.TRANSIENT)return n&&n.log("Lifecycle.apply: transient cache=skip."),i();if(o.life===t.SINGLETON){const e=function(e){const t=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,null===e.exportName?"":e.exportName,e.composition,null===e.life?"":e.life,t].join("::")}(o);if(r.has(e))return n&&n.log(`Lifecycle.cache: hit key='${e}'.`),r.get(e);n&&n.log(`Lifecycle.cache: miss key='${e}', create.`);const t=i();return r.set(e,t),n&&n.log(`Lifecycle.cache: stored key='${e}'.`),t}return n&&n.log("Lifecycle.apply: no lifecycle marker cache=skip."),i()}}}class y{constructor(){const e=function(e){return"function"==typeof e};this.execute=function(t,o,r){let n=o;const i=t.wrappers;for(const t of i){if(!(t in r))throw new Error(`Wrapper '${t}' is not found in module namespace.`);const o=r[t];if(!e(o))throw new Error(`Wrapper '${t}' must be callable.`);if(n=o(n),n instanceof Promise)throw new Error(`Wrapper '${t}' must return synchronously (non-Promise).`)}return n}}}class x{constructor(e="teqfw/di"){const t=`[${e}]`;this.log=function(e){console.debug(`${t} ${e}`)},this.error=function(e,o){console.error(`${t} ${e}`),o instanceof Error?console.error(o.stack??o.message):void 0!==o&&console.error(o)}}}const N=Object.freeze({log(){},error(){}});return class{constructor(){let e="notConfigured";const t=[],o=[],r=[],n=new Map,i=new WeakMap;let s=!1,a=!1,l=new p;const c=new m;let f,u,d,E=N;const C=new w,b=new y,v=function(e){const t=null===e.exportName?"":e.exportName,o=null===e.life?"":e.life,r=Array.isArray(e.wrappers)?e.wrappers.join("|"):"";return[e.platform,e.moduleName,t,e.composition,o,r].join("::")},_=function(e){return v(e)},I=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;if("[object Module]"===Object.prototype.toString.call(e))return e;if(Object.isFrozen(e))return e;try{Object.freeze(e)}catch(e){E.log(`Container.freeze: skipped (${String(e)}).`)}return e},j=function(e){if(null==e)return e;const t=typeof e;if("object"!==t&&"function"!==t)return e;const o=e;if(i.has(o))return i.get(o);try{return Reflect.get(o,"then"),e}catch{const e=new Proxy(o,{get(e,t,o){if("then"!==t)return Reflect.get(e,t,o)}});return i.set(o,e),e}},R=function(){if("notConfigured"!==e)throw new Error("Container configuration is locked.")},A=function(e){a&&E.log(`Container.builder: ${e}`)};this.addPreprocess=function(e){R(),A("addPreprocess()."),t.push(e)},this.addPostprocess=function(e){R(),A("addPostprocess()."),o.push(e)},this.setParser=function(e){R(),l=e,"function"==typeof l.setLogger&&l.setLogger(a?E:null),A("setParser().")},this.addNamespaceRoot=function(e,t,o){R(),A(`addNamespaceRoot('${e}').`),r.push({prefix:e,target:t,defaultExt:o})},this.enableTestMode=function(){R(),A("enableTestMode()."),s=!0},this.enableLogging=function(){R(),a||(a=!0,E=new x,"function"==typeof l.setLogger&&l.setLogger(E),E.log("Container.builder: enableLogging()."))},this.register=function(e,t){if(R(),A(`register('${e}').`),!0!==s)throw new Error("Container test mode is disabled.");const o=l.parse(e);n.set(_(o),t)},this.get=async function(i){if("failed"===e)throw E.error(`Container.get: rejected in failed state cdc='${i}'.`),new Error("Container is in failed state.");let a="start";try{E.log(`Container.get: cdc='${i}'.`),function(){if("notConfigured"!==e)return;E.log("Container.transition: notConfigured -> operational."),e="operational";const t=c.create({namespaces:r});"function"==typeof l.setLogger&&l.setLogger(E),f=new g({config:t,logger:E}),u=new h({parser:l,resolver:f,logger:E}),d=new $(E)}(),E.log(`Container.state: '${e}'.`),a="parse",E.log("Container.pipeline: parse:entry.");const p=l.parse(i);E.log(`Container.pipeline: parse:exit '${p.platform}::${p.moduleName}'.`),a="preprocess",E.log("Container.pipeline: preprocess:entry.");const m=function(e){let o=e;for(const e of t)o=e(o);return o}(p);if(E.log(`Container.pipeline: preprocess:exit '${m.platform}::${m.moduleName}'.`),!0===s){a="mock",E.log("Container.pipeline: mock-lookup:entry.");const e=_(m);if(n.has(e)){E.log(`Container.pipeline: mock-lookup:hit '${e}'.`),a="freeze",E.log("Container.pipeline: freeze:entry.");const t=I(n.get(e));return E.log("Container.pipeline: freeze:exit."),E.log("Container.pipeline: return:success."),j(t)}E.log(`Container.pipeline: mock-lookup:miss '${e}'.`)}else E.log("Container.pipeline: mock-lookup:disabled.");a="resolve",E.log("Container.pipeline: resolve:entry.");const w=await u.resolve(m);E.log(`Container.pipeline: resolve:exit nodes=${w.size}.`);const y=new Map,x=function(e){if(y.has(e))return y.get(e);if(!w.has(e))throw new Error(`Resolved graph node is missing for '${e}'.`);const t=w.get(e);a="lifecycle",E.log(`Container.pipeline: lifecycle:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const r=d.apply(t.depId,function(){a="instantiate",E.log(`Container.pipeline: instantiate:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const e={},r=function(e){const t=Reflect.get(e,"__deps__");return void 0===t?{}:t}(t.namespace);for(const[t,o]of Object.entries(r)){const r=o,n=l.parse(r);e[t]=x(v(n))}const n=C.instantiate(t.depId,t.namespace,e);E.log(`Container.pipeline: instantiate:exit '${t.depId.platform}::${t.depId.moduleName}'.`),a="postprocess",E.log(`Container.pipeline: postprocess:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const i=function(e){let t=e;for(const e of o)t=e(t);return t}(n);E.log(`Container.pipeline: postprocess:exit '${t.depId.platform}::${t.depId.moduleName}'.`);const s=b.execute(t.depId,i,t.namespace);a="freeze",E.log(`Container.pipeline: freeze:entry '${t.depId.platform}::${t.depId.moduleName}'.`);const c=I(s);return E.log(`Container.pipeline: freeze:exit '${t.depId.platform}::${t.depId.moduleName}'.`),c});return E.log(`Container.pipeline: lifecycle:exit '${t.depId.platform}::${t.depId.moduleName}'.`),y.set(e,r),r},N=x(v(m));return E.log("Container.pipeline: return:success."),j(N)}catch(t){throw E.error(`Container.pipeline: failed at stage='${a}'.`,t),E.log("Container.transition: operational -> failed."),e="failed",t}}}}});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teqfw/di",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Dependency Injection container for ES6 modules that works in both browser and Node.js apps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dependency injection",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"scripts": {
|
|
53
53
|
"rollup": "rollup -c",
|
|
54
54
|
"eslint": "npx eslint './src/**/*.mjs'",
|
|
55
|
+
"test": "npm run test:unit && npm run test:integration",
|
|
55
56
|
"test:unit": "find test/unit -name '*.test.mjs' -print0 | xargs -0 node --test",
|
|
56
57
|
"test:integration": "find test/integration -name '*.test.mjs' -print0 | xargs -0 node --test"
|
|
57
58
|
},
|
package/src/Def/Parser.mjs
CHANGED
|
@@ -28,7 +28,7 @@ export default class TeqFw_Di_Def_Parser {
|
|
|
28
28
|
if (logger) logger.log(`Parser.parse: input='${cdc}'.`);
|
|
29
29
|
if (typeof cdc !== 'string') throw new Error('CDC must be a string.');
|
|
30
30
|
if (cdc.length === 0) throw new Error('CDC must be non-empty.');
|
|
31
|
-
if (!/^[
|
|
31
|
+
if (!/^[\x00-\x7F]+$/.test(cdc)) throw new Error('CDC must be ASCII.');
|
|
32
32
|
|
|
33
33
|
/** @type {string} */
|
|
34
34
|
const origin = cdc;
|
|
@@ -36,56 +36,46 @@ export default class TeqFw_Di_Def_Parser {
|
|
|
36
36
|
/** @type {typeof TeqFw_Di_Enum_Platform[keyof typeof TeqFw_Di_Enum_Platform]} */
|
|
37
37
|
let platform = TeqFw_Di_Enum_Platform.TEQ;
|
|
38
38
|
|
|
39
|
-
if (source.startsWith('
|
|
39
|
+
if (source.startsWith('node:')) {
|
|
40
40
|
platform = TeqFw_Di_Enum_Platform.NODE;
|
|
41
41
|
source = source.slice(5);
|
|
42
|
-
} else if (source.startsWith('
|
|
42
|
+
} else if (source.startsWith('npm:')) {
|
|
43
43
|
platform = TeqFw_Di_Enum_Platform.NPM;
|
|
44
44
|
source = source.slice(4);
|
|
45
|
-
} else if (source.startsWith('
|
|
46
|
-
throw new Error('Explicit
|
|
45
|
+
} else if (source.startsWith('teq:')) {
|
|
46
|
+
throw new Error('Explicit teq: prefix is forbidden.');
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (source.length === 0) throw new Error('moduleName must be non-empty.');
|
|
50
50
|
|
|
51
|
-
/** @type {
|
|
52
|
-
const lifecyclePattern = /(\${1,3})(?:_([A-Za-z0-9]+(?:_[A-Za-z0-9]+)*))?$/;
|
|
53
|
-
/** @type {RegExpMatchArray|null} */
|
|
54
|
-
const lifecycleMatch = source.match(lifecyclePattern);
|
|
55
|
-
|
|
56
|
-
/** @type {typeof TeqFw_Di_Enum_Life[keyof typeof TeqFw_Di_Enum_Life]} */
|
|
51
|
+
/** @type {typeof TeqFw_Di_Enum_Life[keyof typeof TeqFw_Di_Enum_Life] | null} */
|
|
57
52
|
let life = null;
|
|
53
|
+
let lifecycleDeclared = false;
|
|
58
54
|
/** @type {string[]} */
|
|
59
55
|
let wrappers = [];
|
|
60
56
|
let core = source;
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
58
|
+
const markerMatch = core.match(/(\${1,3})(?:_[a-z][0-9A-Za-z]*)*$/);
|
|
59
|
+
if (markerMatch) {
|
|
60
|
+
const marker = markerMatch[1];
|
|
61
|
+
const suffix = markerMatch[0].slice(marker.length);
|
|
62
|
+
lifecycleDeclared = true;
|
|
65
63
|
if (marker === '$') life = TeqFw_Di_Enum_Life.SINGLETON;
|
|
66
|
-
else if (
|
|
67
|
-
else
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (!one) throw new Error('Wrapper must be non-empty.');
|
|
74
|
-
if (one.includes('$')) throw new Error('Wrapper must not contain $.');
|
|
75
|
-
if (one.includes('_')) throw new Error('Wrapper must not contain _.');
|
|
76
|
-
}
|
|
64
|
+
else if (marker === '$$') life = TeqFw_Di_Enum_Life.TRANSIENT;
|
|
65
|
+
else if (marker === '$$$') life = null;
|
|
66
|
+
else throw new Error('Lifecycle marker is invalid.');
|
|
67
|
+
|
|
68
|
+
core = core.slice(0, markerMatch.index);
|
|
69
|
+
if (suffix.length > 0) {
|
|
70
|
+
wrappers = suffix.slice(1).split('_');
|
|
77
71
|
}
|
|
78
72
|
} else {
|
|
79
|
-
if (source.includes('$')) throw new Error('Invalid lifecycle
|
|
80
|
-
|
|
81
|
-
const trailing = source.match(/(?:^|[^_])_([a-z][A-Za-z0-9]*)$/);
|
|
82
|
-
if (trailing) {
|
|
73
|
+
if (source.includes('$')) throw new Error('Invalid lifecycle encoding.');
|
|
74
|
+
if (/(?:^|[^_])_[a-z][0-9A-Za-z]*$/.test(source)) {
|
|
83
75
|
throw new Error('Wrapper without lifecycle is forbidden.');
|
|
84
76
|
}
|
|
85
77
|
}
|
|
86
78
|
|
|
87
|
-
if (core.includes('$$$$')) throw new Error('Lifecycle marker overflow.');
|
|
88
|
-
|
|
89
79
|
const firstDelim = core.indexOf('__');
|
|
90
80
|
const lastDelim = core.lastIndexOf('__');
|
|
91
81
|
if ((firstDelim !== -1) && (firstDelim !== lastDelim)) throw new Error('Export delimiter must appear at most once.');
|
|
@@ -107,17 +97,21 @@ export default class TeqFw_Di_Def_Parser {
|
|
|
107
97
|
if (moduleName.startsWith('_') || moduleName.startsWith('$')) throw new Error('moduleName must not start with _ or $.');
|
|
108
98
|
if (moduleName.includes('__')) throw new Error('moduleName must not contain __.');
|
|
109
99
|
if (moduleName.includes('$')) throw new Error('moduleName must not contain $.');
|
|
100
|
+
if (platform !== TeqFw_Di_Enum_Platform.NPM) {
|
|
101
|
+
if (!/^[A-Za-z_][$0-9A-Za-z_]*$/.test(moduleName)) {
|
|
102
|
+
throw new Error('moduleName must satisfy the canonical identifier form.');
|
|
103
|
+
}
|
|
104
|
+
} else if (!/^[@A-Za-z_][$0-9A-Za-z_./-]*$/.test(moduleName)) {
|
|
105
|
+
throw new Error('npm moduleName must satisfy the package specifier form.');
|
|
106
|
+
}
|
|
110
107
|
|
|
111
108
|
/** @type {typeof TeqFw_Di_Enum_Composition[keyof typeof TeqFw_Di_Enum_Composition]} */
|
|
112
109
|
let composition = TeqFw_Di_Enum_Composition.AS_IS;
|
|
113
110
|
if (exportName !== null) {
|
|
114
111
|
composition = TeqFw_Di_Enum_Composition.FACTORY;
|
|
115
|
-
} else if (
|
|
116
|
-
exportName = 'default';
|
|
117
|
-
composition = TeqFw_Di_Enum_Composition.FACTORY;
|
|
118
|
-
} else if (life === TeqFw_Di_Enum_Life.TRANSIENT) {
|
|
112
|
+
} else if (lifecycleDeclared) {
|
|
119
113
|
composition = TeqFw_Di_Enum_Composition.FACTORY;
|
|
120
|
-
|
|
114
|
+
exportName = 'default';
|
|
121
115
|
}
|
|
122
116
|
|
|
123
117
|
const depId = depIdFactory.create({
|