@cdk8s/awscdk-resolver 0.0.597 → 0.0.598
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/.jsii +3 -3
- package/lib/resolve.js +1 -1
- package/node_modules/@aws-sdk/client-cloudformation/package.json +1 -1
- package/node_modules/@nodable/entities/package.json +4 -1
- package/node_modules/@nodable/entities/src/EntityDecoder.js +104 -3
- package/node_modules/@nodable/entities/src/index.d.ts +77 -0
- package/node_modules/@nodable/entities/src/index.js +1 -1
- package/package.json +3 -3
package/.jsii
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"url": "https://aws.amazon.com"
|
|
8
8
|
},
|
|
9
9
|
"bundled": {
|
|
10
|
-
"@aws-sdk/client-cloudformation": "^3.
|
|
10
|
+
"@aws-sdk/client-cloudformation": "^3.1067.0"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"aws-cdk-lib": "^2.195.0",
|
|
@@ -4082,6 +4082,6 @@
|
|
|
4082
4082
|
"symbolId": "src/resolve:AwsCdkResolver"
|
|
4083
4083
|
}
|
|
4084
4084
|
},
|
|
4085
|
-
"version": "0.0.
|
|
4086
|
-
"fingerprint": "
|
|
4085
|
+
"version": "0.0.598",
|
|
4086
|
+
"fingerprint": "2gz2MUcZyEmURQQ8/PoLqVnf088E+kvVVQmKzfFLIFs="
|
|
4087
4087
|
}
|
package/lib/resolve.js
CHANGED
|
@@ -61,5 +61,5 @@ class AwsCdkResolver {
|
|
|
61
61
|
}
|
|
62
62
|
exports.AwsCdkResolver = AwsCdkResolver;
|
|
63
63
|
_a = JSII_RTTI_SYMBOL_1;
|
|
64
|
-
AwsCdkResolver[_a] = { fqn: "@cdk8s/awscdk-resolver.AwsCdkResolver", version: "0.0.
|
|
64
|
+
AwsCdkResolver[_a] = { fqn: "@cdk8s/awscdk-resolver.AwsCdkResolver", version: "0.0.598" };
|
|
65
65
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9yZXNvbHZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsaURBQTZDO0FBQzdDLDZCQUE2QjtBQUM3Qiw2Q0FBK0U7QUFJL0UsTUFBYSxjQUFjO0lBRWxCLE9BQU8sQ0FBQyxPQUEwQjtRQUV2QyxJQUFJLENBQUMsbUJBQUssQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDdkMsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLE9BQU8sT0FBTyxDQUFDLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN0QywrREFBK0Q7WUFDL0QsbUJBQW1CO1lBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLE9BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7UUFDdEYsQ0FBQztRQUVELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlDLElBQUksQ0FBQztZQUNILE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNsRCxPQUFPLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsMkVBQTJFO1lBQzNFLGtFQUFrRTtZQUNsRSwyRUFBMkU7WUFDM0UsK0VBQStFO1lBQy9FLCtDQUErQztZQUMvQyxPQUFPLENBQUMsWUFBWSxDQUFDLG9DQUFvQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZGLENBQUM7SUFFSCxDQUFDO0lBRU8sVUFBVSxDQUFDLEtBQWE7UUFFOUIsTUFBTSxlQUFlLEdBQVksRUFBRSxDQUFDO1FBRXBDLEtBQUssTUFBTSxLQUFLLElBQUksMEJBQVksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDN0QsSUFBSSx1QkFBUyxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUNqQyxNQUFNLEtBQUssR0FBRyxtQkFBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ3JDLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzVCLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxZQUFZLHVCQUFTLElBQUksQ0FBQyxDQUFDLEtBQUssS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQWMsQ0FBQztnQkFDN0csa0ZBQWtGO2dCQUNsRix3REFBd0Q7Z0JBQ3hELElBQUksTUFBTTtvQkFBRSxPQUFPLE1BQU0sQ0FBQztZQUM1QixDQUFDO1FBQ0gsQ0FBQztRQUVELDZCQUE2QjtRQUM3Qiw2QkFBNkI7UUFDN0Isb0NBQW9DO1FBQ3BDLG9GQUFvRjtRQUNwRiwrREFBK0Q7UUFDL0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsS0FBSyx1QkFBdUIsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRXZJLENBQUM7SUFFTyxnQkFBZ0IsQ0FBQyxNQUFpQjtRQUV4QyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLHVCQUF1QixDQUFDLENBQUM7UUFDMUUsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUEsNEJBQVksRUFBQyxPQUFPLENBQUMsUUFBUSxFQUFFO1lBQy9DLE1BQU07WUFDTixtQkFBSyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxTQUFTO1lBQzFCLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRTtTQUNmLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBRWhFLENBQUM7O0FBOURILHdDQWdFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4ZWNGaWxlU3luYyB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IFRva2VuLCBTdGFjaywgVG9rZW5pemF0aW9uLCBSZWZlcmVuY2UsIENmbk91dHB1dCB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IElSZXNvbHZlciwgUmVzb2x1dGlvbkNvbnRleHQgfSBmcm9tICdjZGs4cyc7XG5cblxuZXhwb3J0IGNsYXNzIEF3c0Nka1Jlc29sdmVyIGltcGxlbWVudHMgSVJlc29sdmVyIHtcblxuICBwdWJsaWMgcmVzb2x2ZShjb250ZXh0OiBSZXNvbHV0aW9uQ29udGV4dCkge1xuXG4gICAgaWYgKCFUb2tlbi5pc1VucmVzb2x2ZWQoY29udGV4dC52YWx1ZSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGNvbnRleHQudmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBzaG91bGQgYmUgb2sgYmVjYXVzZSB3ZSBvbmx5IHJlc29sdmUgQ2ZuT3V0cHV0IHZhbHVlcywgd2hpY2hcbiAgICAgIC8vIG11c3QgYmUgc3RyaW5ncy5cbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB2YWx1ZSB0eXBlOiAke3R5cGVvZihjb250ZXh0LnZhbHVlKX0gKEV4cGVjdGVkICdzdHJpbmcnKWApO1xuICAgIH1cblxuICAgIGNvbnN0IG91dHB1dCA9IHRoaXMuZmluZE91dHB1dChjb250ZXh0LnZhbHVlKTtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgb3V0cHV0VmFsdWUgPSB0aGlzLmZldGNoT3V0cHV0VmFsdWUob3V0cHV0KTtcbiAgICAgIGNvbnRleHQucmVwbGFjZVZhbHVlKG91dHB1dFZhbHVlKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIGlmIGJvdGggY2RrOHMgYW5kIEFXUyBDREsgYXBwbGljYXRpb25zIGFyZSBkZWZpbmVkIHdpdGhpbiB0aGUgc2FtZSBmaWxlLFxuICAgICAgLy8gYSBjZGs4cyBzeW50aCBpcyBnb2luZyB0byBoYXBwZW4gYmVmb3JlIHRoZSBBV1MgQ0RLIGRlcGxveW1lbnQuXG4gICAgICAvLyBpbiB0aGlzIGNhc2Ugd2UgbXVzdCBzd2FsbG93IHRoZSBlcnJvciwgb3RoZXJ3aXNlIHRoZSBBV1MgQ0RLIGRlcGxveW1lbnRcbiAgICAgIC8vIHdvbid0IGJlIGFibGUgdG8gZ28gdGhyb3VnaC4gd2UgcmVwbGFjZSB0aGUgdmFsdWUgd2l0aCBzb21ldGhpbmcgdG8gaW5kaWNhdGVcbiAgICAgIC8vIHRoYXQgYSBmZXRjaGluZyBhdHRlbXB0IHdhcyBtYWRlIGFuZCBmYWlsZWQuXG4gICAgICBjb250ZXh0LnJlcGxhY2VWYWx1ZShgRmFpbGVkIGZldGNoaW5nIHZhbHVlIGZvciBvdXRwdXQgJHtvdXRwdXQubm9kZS5wYXRofTogJHtlcnJ9YCk7XG4gICAgfVxuXG4gIH1cblxuICBwcml2YXRlIGZpbmRPdXRwdXQodmFsdWU6IHN0cmluZykge1xuXG4gICAgY29uc3QgaW5zcGVjdGVkU3RhY2tzOiBTdGFja1tdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IHRva2VuIG9mIFRva2VuaXphdGlvbi5yZXZlcnNlU3RyaW5nKHZhbHVlKS50b2tlbnMpIHtcbiAgICAgIGlmIChSZWZlcmVuY2UuaXNSZWZlcmVuY2UodG9rZW4pKSB7XG4gICAgICAgIGNvbnN0IHN0YWNrID0gU3RhY2sub2YodG9rZW4udGFyZ2V0KTtcbiAgICAgICAgaW5zcGVjdGVkU3RhY2tzLnB1c2goc3RhY2spO1xuICAgICAgICBjb25zdCBvdXRwdXQgPSBzdGFjay5ub2RlLmZpbmRBbGwoKS5maWx0ZXIoYyA9PiBjIGluc3RhbmNlb2YgQ2ZuT3V0cHV0ICYmIGMudmFsdWUgPT09IHZhbHVlKVswXSBhcyBDZm5PdXRwdXQ7XG4gICAgICAgIC8vIHdlIGRvbid0IHJlYWxseSBjYXJlIGlmIHRoZXJlIGFyZSBtb3JlIG91dHB1dHMgKHBvc3NpYmx5IGZyb20gZGlmZmVyZW50IHN0YWNrcylcbiAgICAgICAgLy8gdGhhdCBwb2ludCB0byB0aGUgc2FtZSB2YWx1ZS4gdGhlIGZpcnN0IHdpbGwgc3VmZmljZS5cbiAgICAgICAgaWYgKG91dHB1dCkgcmV0dXJuIG91dHB1dDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUaGlzIGNhbiBoYXBwZW4gaWYgZWl0aGVyOlxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gIDEuIFVzZXIgZGlkbid0IGRlZmluZSBhbiBvdXRwdXQuXG4gICAgLy8gIDIuIE91dHB1dCB3YXMgZGVmaW5lZCBpbiBhIGRpZmZlcmVudCBzdGFjayB0aGFuIHRoZSB0b2tlbnMgY29tcHJpc2luZyBpdHMgdmFsdWUuXG4gICAgLy8gIDMuIE5vbmUgb2YgdGhlIHRva2VucyBjb21wcmlzaW5nIHRoZSB2YWx1ZSBhcmUgYSBSZWZlcmVuY2UuXG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gZmluZCBvdXRwdXQgZGVmaW5lZCBmb3IgJHt2YWx1ZX0gKEluc3BlY3RlZCBzdGFja3M6ICR7aW5zcGVjdGVkU3RhY2tzLm1hcChzID0+IHMuc3RhY2tOYW1lKS5qb2luKCcsJyl9KWApO1xuXG4gIH1cblxuICBwcml2YXRlIGZldGNoT3V0cHV0VmFsdWUob3V0cHV0OiBDZm5PdXRwdXQpIHtcblxuICAgIGNvbnN0IHNjcmlwdCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICdsaWInLCAnZmV0Y2gtb3V0cHV0LXZhbHVlLmpzJyk7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UoZXhlY0ZpbGVTeW5jKHByb2Nlc3MuZXhlY1BhdGgsIFtcbiAgICAgIHNjcmlwdCxcbiAgICAgIFN0YWNrLm9mKG91dHB1dCkuc3RhY2tOYW1lLFxuICAgICAgb3V0cHV0Lm5vZGUuaWQsXG4gICAgXSwgeyBlbmNvZGluZzogJ3V0Zi04Jywgc3RkaW86IFsncGlwZSddIH0pLnRvU3RyaW5nKCkudHJpbSgpKTtcblxuICB9XG5cbn1cbiJdfQ==
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-sdk/client-cloudformation",
|
|
3
3
|
"description": "AWS SDK for JavaScript Cloudformation Client for Node.js, Browser and React Native",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.1067.0",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "concurrently 'yarn:build:types' 'yarn:build:es' && yarn build:cjs",
|
|
7
7
|
"build:cjs": "node ../../scripts/compilation/inline",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodable/entities",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Entity parser for XML, HTML, External entites with security and NCR control",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -25,10 +25,13 @@
|
|
|
25
25
|
"xml",
|
|
26
26
|
"html",
|
|
27
27
|
"entity",
|
|
28
|
+
"entities",
|
|
29
|
+
"stringify",
|
|
28
30
|
"encode",
|
|
29
31
|
"decode",
|
|
30
32
|
"ncr",
|
|
31
33
|
"security",
|
|
34
|
+
"safe",
|
|
32
35
|
"performance"
|
|
33
36
|
],
|
|
34
37
|
"author": "Amit Gupta (https://solothought.com)",
|
|
@@ -5,6 +5,30 @@
|
|
|
5
5
|
|
|
6
6
|
import { XML as DEFAULT_XML_ENTITIES } from "./entities.js"
|
|
7
7
|
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Entity hook action constants
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Action constants for `onExternalEntity` and `onInputEntity` hooks.
|
|
14
|
+
*
|
|
15
|
+
* Use these instead of raw strings to avoid typos:
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* import EntityDecoder, { ENTITY_ACTION } from './EntityDecoder.js';
|
|
19
|
+
* const dec = new EntityDecoder({
|
|
20
|
+
* onInputEntity: (name, value) => ENTITY_ACTION.BLOCK,
|
|
21
|
+
* });
|
|
22
|
+
*/
|
|
23
|
+
export const ENTITY_ACTION = Object.freeze({
|
|
24
|
+
/** Resolve and expand the entity normally. */
|
|
25
|
+
ALLOW: 'allow',
|
|
26
|
+
/** Silently skip this entity — it will not be registered. */
|
|
27
|
+
BLOCK: 'block',
|
|
28
|
+
/** Throw an error, aborting entity registration entirely. */
|
|
29
|
+
THROW: 'throw',
|
|
30
|
+
});
|
|
31
|
+
|
|
8
32
|
// ---------------------------------------------------------------------------
|
|
9
33
|
// Helpers
|
|
10
34
|
// ---------------------------------------------------------------------------
|
|
@@ -169,6 +193,14 @@ export default class EntityDecoder {
|
|
|
169
193
|
* the effective action is max(onNCR, rangeMinimum).
|
|
170
194
|
* @param {'remove'|'throw'} [options.ncr.nullNCR='remove']
|
|
171
195
|
* Action for U+0000 (null). 'allow' and 'leave' are clamped to 'remove' since null is never safe.
|
|
196
|
+
* @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} [options.onExternalEntity=null]
|
|
197
|
+
* Hook called when an external entity is registered via `setExternalEntities()` or
|
|
198
|
+
* `addExternalEntity()`. Return `ENTITY_ACTION.ALLOW` to accept the entity,
|
|
199
|
+
* `ENTITY_ACTION.BLOCK` to silently skip it, or `ENTITY_ACTION.THROW` to abort with an error.
|
|
200
|
+
* @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} [options.onInputEntity=null]
|
|
201
|
+
* Hook called when an input entity is registered via `addInputEntities()`. Return
|
|
202
|
+
* `ENTITY_ACTION.ALLOW` to accept, `ENTITY_ACTION.BLOCK` to silently skip, or
|
|
203
|
+
* `ENTITY_ACTION.THROW` to abort with an error.
|
|
172
204
|
*/
|
|
173
205
|
constructor(options = {}) {
|
|
174
206
|
this._limit = options.limit || {};
|
|
@@ -204,6 +236,43 @@ export default class EntityDecoder {
|
|
|
204
236
|
this._ncrXmlVersion = ncrCfg.xmlVersion;
|
|
205
237
|
this._ncrOnLevel = ncrCfg.onLevel;
|
|
206
238
|
this._ncrNullLevel = ncrCfg.nullLevel;
|
|
239
|
+
|
|
240
|
+
// --- Registration hooks ---
|
|
241
|
+
/** @type {((name: string, value: string) => 'allow'|'block'|'throw')|null} */
|
|
242
|
+
this._onExternalEntity = typeof options.onExternalEntity === 'function'
|
|
243
|
+
? options.onExternalEntity
|
|
244
|
+
: null;
|
|
245
|
+
/** @type {((name: string, value: string) => 'allow'|'block'|'throw')|null} */
|
|
246
|
+
this._onInputEntity = typeof options.onInputEntity === 'function'
|
|
247
|
+
? options.onInputEntity
|
|
248
|
+
: null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// -------------------------------------------------------------------------
|
|
252
|
+
// Private: registration hook dispatch
|
|
253
|
+
// -------------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Invoke a registration hook for a single entity name/value pair.
|
|
257
|
+
* Returns true when the entity should be accepted, false when it should be
|
|
258
|
+
* silently skipped (BLOCK), and throws when the hook returns THROW.
|
|
259
|
+
*
|
|
260
|
+
* @param {((name: string, value: string) => 'allow'|'block'|'throw')|null} hook
|
|
261
|
+
* @param {string} name
|
|
262
|
+
* @param {string} value
|
|
263
|
+
* @param {string} context — used in error messages ('external' | 'input')
|
|
264
|
+
* @returns {boolean} true = accept, false = skip
|
|
265
|
+
*/
|
|
266
|
+
_applyRegistrationHook(hook, name, value, context) {
|
|
267
|
+
if (!hook) return true; // no hook → always accept
|
|
268
|
+
const action = hook(name, value);
|
|
269
|
+
if (action === ENTITY_ACTION.BLOCK) return false;
|
|
270
|
+
if (action === ENTITY_ACTION.THROW) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
`[EntityDecoder] Registration of ${context} entity "&${name};" was rejected by hook`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
return true; // ALLOW or any unknown return value → accept
|
|
207
276
|
}
|
|
208
277
|
|
|
209
278
|
// -------------------------------------------------------------------------
|
|
@@ -213,6 +282,9 @@ export default class EntityDecoder {
|
|
|
213
282
|
/**
|
|
214
283
|
* Replace the full set of persistent external entities.
|
|
215
284
|
* All keys are validated — throws on invalid characters.
|
|
285
|
+
* If `onExternalEntity` is set, it is called once per entry; entries that
|
|
286
|
+
* return `ENTITY_ACTION.BLOCK` are silently omitted, `ENTITY_ACTION.THROW`
|
|
287
|
+
* aborts the whole call.
|
|
216
288
|
* @param {Record<string, string | { regex?: RegExp, val: string }>} map
|
|
217
289
|
*/
|
|
218
290
|
setExternalEntities(map) {
|
|
@@ -221,18 +293,34 @@ export default class EntityDecoder {
|
|
|
221
293
|
validateEntityName(key);
|
|
222
294
|
}
|
|
223
295
|
}
|
|
224
|
-
this.
|
|
296
|
+
if (!this._onExternalEntity) {
|
|
297
|
+
this._externalMap = mergeEntityMaps(map);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
// Hook present — resolve values first, then filter
|
|
301
|
+
const flat = mergeEntityMaps(map);
|
|
302
|
+
const filtered = Object.create(null);
|
|
303
|
+
for (const [name, value] of Object.entries(flat)) {
|
|
304
|
+
if (this._applyRegistrationHook(this._onExternalEntity, name, value, 'external')) {
|
|
305
|
+
filtered[name] = value;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
this._externalMap = filtered;
|
|
225
309
|
}
|
|
226
310
|
|
|
227
311
|
/**
|
|
228
312
|
* Add a single persistent external entity.
|
|
313
|
+
* If `onExternalEntity` is set it is called before the entity is stored;
|
|
314
|
+
* `ENTITY_ACTION.BLOCK` silently skips storage, `ENTITY_ACTION.THROW` raises.
|
|
229
315
|
* @param {string} key
|
|
230
316
|
* @param {string} value
|
|
231
317
|
*/
|
|
232
318
|
addExternalEntity(key, value) {
|
|
233
319
|
validateEntityName(key);
|
|
234
320
|
if (typeof value === 'string' && value.indexOf('&') === -1) {
|
|
235
|
-
this.
|
|
321
|
+
if (this._applyRegistrationHook(this._onExternalEntity, key, value, 'external')) {
|
|
322
|
+
this._externalMap[key] = value;
|
|
323
|
+
}
|
|
236
324
|
}
|
|
237
325
|
}
|
|
238
326
|
|
|
@@ -243,12 +331,25 @@ export default class EntityDecoder {
|
|
|
243
331
|
/**
|
|
244
332
|
* Inject DOCTYPE entities for the current document.
|
|
245
333
|
* Also resets per-document expansion counters.
|
|
334
|
+
* If `onInputEntity` is set it is called once per entry; entries returning
|
|
335
|
+
* `ENTITY_ACTION.BLOCK` are silently omitted, `ENTITY_ACTION.THROW` aborts.
|
|
246
336
|
* @param {Record<string, string | { regx?: RegExp, regex?: RegExp, val: string }>} map
|
|
247
337
|
*/
|
|
248
338
|
addInputEntities(map) {
|
|
249
339
|
this._totalExpansions = 0;
|
|
250
340
|
this._expandedLength = 0;
|
|
251
|
-
this.
|
|
341
|
+
if (!this._onInputEntity) {
|
|
342
|
+
this._inputMap = mergeEntityMaps(map);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const flat = mergeEntityMaps(map);
|
|
346
|
+
const filtered = Object.create(null);
|
|
347
|
+
for (const [name, value] of Object.entries(flat)) {
|
|
348
|
+
if (this._applyRegistrationHook(this._onInputEntity, name, value, 'input')) {
|
|
349
|
+
filtered[name] = value;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
this._inputMap = filtered;
|
|
252
353
|
}
|
|
253
354
|
|
|
254
355
|
// -------------------------------------------------------------------------
|
|
@@ -5,6 +5,50 @@
|
|
|
5
5
|
/** A function-based entity replacement value (used for numeric refs). */
|
|
6
6
|
export type EntityValFn = (match: string, captured: string, ...rest: unknown[]) => string;
|
|
7
7
|
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Entity registration hook
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Actions returned by `onExternalEntity` / `onInputEntity` hooks.
|
|
14
|
+
* Use the `ENTITY_ACTION` constant object instead of raw strings to avoid typos.
|
|
15
|
+
*
|
|
16
|
+
* - `'allow'` — register and expand the entity normally
|
|
17
|
+
* - `'block'` — silently skip the entity (not registered, treated as unknown)
|
|
18
|
+
* - `'throw'` — abort registration with an error
|
|
19
|
+
*/
|
|
20
|
+
export type EntityHookAction = 'allow' | 'block' | 'throw';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Immutable constant bag for entity registration hook return values.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* import { ENTITY_ACTION } from '@nodable/entities';
|
|
27
|
+
* const dec = new EntityDecoder({
|
|
28
|
+
* onInputEntity: (_name, _value) => ENTITY_ACTION.BLOCK,
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
export const ENTITY_ACTION: Readonly<{
|
|
32
|
+
/** Register and expand the entity normally. */
|
|
33
|
+
ALLOW: 'allow';
|
|
34
|
+
/** Silently skip this entity — it will not be registered. */
|
|
35
|
+
BLOCK: 'block';
|
|
36
|
+
/** Throw an error, aborting entity registration. */
|
|
37
|
+
THROW: 'throw';
|
|
38
|
+
}>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Callback signature for `onExternalEntity` and `onInputEntity` hooks.
|
|
42
|
+
*
|
|
43
|
+
* Called once per entity **at registration time** (not at decode time).
|
|
44
|
+
* Return `ENTITY_ACTION.ALLOW` (or `'allow'`) to accept, `ENTITY_ACTION.BLOCK`
|
|
45
|
+
* to silently skip, or `ENTITY_ACTION.THROW` to raise an error.
|
|
46
|
+
*
|
|
47
|
+
* @param name — the entity name without `&` / `;`, e.g. `"brand"`
|
|
48
|
+
* @param value — the resolved string value after any `{regex,val}` unwrapping
|
|
49
|
+
*/
|
|
50
|
+
export type EntityRegistrationHook = (name: string, value: string) => EntityHookAction;
|
|
51
|
+
|
|
8
52
|
// ---------------------------------------------------------------------------
|
|
9
53
|
// Encoder options
|
|
10
54
|
// ---------------------------------------------------------------------------
|
|
@@ -191,6 +235,39 @@ export interface EntityDecoderOptions {
|
|
|
191
235
|
* Numeric Character Reference (NCR) policy.
|
|
192
236
|
*/
|
|
193
237
|
ncr?: EntityDecoderNCROptions;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Hook called once **at registration time** for each entity passed to
|
|
241
|
+
* `setExternalEntities()` or `addExternalEntity()`.
|
|
242
|
+
*
|
|
243
|
+
* - `'allow'` (or `ENTITY_ACTION.ALLOW`) — register the entity normally (default)
|
|
244
|
+
* - `'block'` (or `ENTITY_ACTION.BLOCK`) — silently skip; the entity is not stored
|
|
245
|
+
* - `'throw'` (or `ENTITY_ACTION.THROW`) — abort registration with an `Error`
|
|
246
|
+
*
|
|
247
|
+
* The hook receives the entity name (without `&`/`;`) and the resolved string
|
|
248
|
+
* value. It is **not** called during `decode()` — only when entities are added.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* const dec = new EntityDecoder({
|
|
252
|
+
* onExternalEntity: (name, value) =>
|
|
253
|
+
* DANGEROUS_NAMES.has(name) ? ENTITY_ACTION.BLOCK : ENTITY_ACTION.ALLOW,
|
|
254
|
+
* });
|
|
255
|
+
*/
|
|
256
|
+
onExternalEntity?: EntityRegistrationHook | null;
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Hook called once **at registration time** for each entity passed to
|
|
260
|
+
* `addInputEntities()`.
|
|
261
|
+
*
|
|
262
|
+
* Follows the same `'allow' | 'block' | 'throw'` contract as `onExternalEntity`.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* const dec = new EntityDecoder({
|
|
266
|
+
* // Block all input / DOCTYPE entities unconditionally
|
|
267
|
+
* onInputEntity: () => ENTITY_ACTION.BLOCK,
|
|
268
|
+
* });
|
|
269
|
+
*/
|
|
270
|
+
onInputEntity?: EntityRegistrationHook | null;
|
|
194
271
|
}
|
|
195
272
|
|
|
196
273
|
// ---------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"jsii-docgen": "^10.5.0",
|
|
67
67
|
"jsii-pacmak": "^1.134.0",
|
|
68
68
|
"jsii-rosetta": "^5",
|
|
69
|
-
"projen": "^0.99.
|
|
69
|
+
"projen": "^0.99.72",
|
|
70
70
|
"ts-jest": "^27",
|
|
71
71
|
"ts-node": "^10.9.2",
|
|
72
72
|
"typescript": "^5.9.3"
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"constructs": "^10.3.0"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@aws-sdk/client-cloudformation": "^3.
|
|
80
|
+
"@aws-sdk/client-cloudformation": "^3.1067.0"
|
|
81
81
|
},
|
|
82
82
|
"bundledDependencies": [
|
|
83
83
|
"@aws-sdk/client-cloudformation"
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"publishConfig": {
|
|
94
94
|
"access": "public"
|
|
95
95
|
},
|
|
96
|
-
"version": "0.0.
|
|
96
|
+
"version": "0.0.598",
|
|
97
97
|
"jest": {
|
|
98
98
|
"coverageProvider": "v8",
|
|
99
99
|
"testMatch": [
|