projen-pipelines 0.3.21 → 0.3.23
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 +7 -4
- package/API.md +420 -0
- package/lib/assign-approver/base.js +3 -4
- package/lib/assign-approver/github.js +4 -4
- package/lib/awscdk/base.js +48 -6
- package/lib/awscdk/bash.js +2 -4
- package/lib/awscdk/github.js +13 -6
- package/lib/awscdk/gitlab.js +11 -6
- package/lib/drift/base.js +8 -4
- package/lib/drift/bash.js +3 -4
- package/lib/drift/detect-drift.js +3 -2
- package/lib/drift/github.js +5 -4
- package/lib/drift/gitlab.js +5 -4
- package/lib/drift/step.js +2 -4
- package/lib/release.js +5 -2
- package/lib/steps/amplify-deploy.step.js +5 -4
- package/lib/steps/artifact-steps.js +5 -6
- package/lib/steps/aws-assume-role.step.js +3 -4
- package/lib/steps/github-summary.step.js +3 -4
- package/lib/steps/package-manager-setup.step.js +4 -6
- package/lib/steps/registries.js +7 -8
- package/lib/steps/set-env.step.js +2 -1
- package/lib/steps/step.js +9 -10
- package/lib/versioning/computation.js +6 -8
- package/lib/versioning/config.js +3 -6
- package/lib/versioning/outputs.js +13 -16
- package/lib/versioning/setup.js +9 -9
- package/lib/versioning/strategy.js +4 -4
- package/lib/versioning/version-info.js +18 -9
- package/node_modules/@babel/code-frame/package.json +2 -2
- package/node_modules/@babel/helper-validator-identifier/package.json +1 -1
- package/node_modules/@nodable/entities/README.md +52 -1
- package/node_modules/@nodable/entities/package.json +4 -1
- package/node_modules/@nodable/entities/src/EntityDecoder.js +105 -4
- package/node_modules/@nodable/entities/src/EntityEncoder.js +79 -34
- package/node_modules/@nodable/entities/src/all-entities.js +53 -0
- package/node_modules/@nodable/entities/src/entities.js +0 -38
- package/node_modules/@nodable/entities/src/entityTries.js +48 -37
- package/node_modules/@nodable/entities/src/index.d.ts +93 -2
- package/node_modules/@nodable/entities/src/index.js +2 -2
- package/node_modules/anynum/LICENSE +21 -0
- package/node_modules/anynum/README.md +142 -0
- package/node_modules/anynum/anynum.js +135 -0
- package/node_modules/anynum/digitTable.js +116 -0
- package/node_modules/anynum/package.json +42 -0
- package/node_modules/dotgitignore/node_modules/brace-expansion/README.md +23 -1
- package/node_modules/dotgitignore/node_modules/brace-expansion/index.js +265 -86
- package/node_modules/dotgitignore/node_modules/brace-expansion/package.json +1 -1
- package/node_modules/fast-xml-builder/CHANGELOG.md +12 -0
- package/node_modules/fast-xml-builder/README.md +4 -1
- package/node_modules/fast-xml-builder/lib/fxb.cjs +1 -1
- package/node_modules/fast-xml-builder/lib/fxb.min.js +1 -1
- package/node_modules/fast-xml-builder/lib/fxb.min.js.map +1 -1
- package/node_modules/fast-xml-builder/package.json +6 -10
- package/node_modules/fast-xml-builder/src/fxb.js +34 -24
- package/node_modules/fast-xml-builder/src/orderedJs2Xml.js +18 -17
- package/node_modules/fast-xml-builder/src/util.js +10 -3
- package/node_modules/fast-xml-parser/CHANGELOG.md +34 -0
- package/node_modules/fast-xml-parser/README.md +10 -6
- package/node_modules/fast-xml-parser/lib/fxbuilder.min.js +1 -1
- package/node_modules/fast-xml-parser/lib/fxbuilder.min.js.map +1 -1
- package/node_modules/fast-xml-parser/lib/fxp.cjs +1 -1
- package/node_modules/fast-xml-parser/lib/fxp.d.cts +3 -1
- package/node_modules/fast-xml-parser/lib/fxp.min.js +1 -1
- package/node_modules/fast-xml-parser/lib/fxp.min.js.map +1 -1
- package/node_modules/fast-xml-parser/lib/fxparser.min.js +1 -1
- package/node_modules/fast-xml-parser/lib/fxparser.min.js.map +1 -1
- package/node_modules/fast-xml-parser/package.json +8 -10
- package/node_modules/fast-xml-parser/src/fxp.d.ts +5 -1
- package/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js +16 -1
- package/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js +2 -1
- package/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js +36 -3
- package/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js +14 -0
- package/node_modules/get-pkg-repo/node_modules/yargs/package.json +27 -26
- package/node_modules/get-pkg-repo/node_modules/yargs/yargs +5 -9
- package/node_modules/get-pkg-repo/node_modules/yargs/yargs.cjs +15 -0
- package/node_modules/hasown/CHANGELOG.md +7 -0
- package/node_modules/hasown/index.d.ts +0 -1
- package/node_modules/hasown/package.json +4 -5
- package/node_modules/is-unsafe/LICENSE +21 -0
- package/node_modules/is-unsafe/README.md +599 -0
- package/node_modules/is-unsafe/package.json +56 -0
- package/node_modules/is-unsafe/src/contexts/html.js +102 -0
- package/node_modules/is-unsafe/src/contexts/log.js +98 -0
- package/node_modules/is-unsafe/src/contexts/nosql.js +114 -0
- package/node_modules/is-unsafe/src/contexts/redos.js +60 -0
- package/node_modules/is-unsafe/src/contexts/shell.js +105 -0
- package/node_modules/is-unsafe/src/contexts/sql-strict.js +47 -0
- package/node_modules/is-unsafe/src/contexts/sql.js +95 -0
- package/node_modules/is-unsafe/src/contexts/svg.js +81 -0
- package/node_modules/is-unsafe/src/contexts/xml.js +79 -0
- package/node_modules/is-unsafe/src/index.cjs +27 -0
- package/node_modules/is-unsafe/src/index.d.ts +95 -0
- package/node_modules/is-unsafe/src/index.js +265 -0
- package/node_modules/path-expression-matcher/README.md +82 -7
- package/node_modules/path-expression-matcher/lib/pem.cjs +1 -1
- package/node_modules/path-expression-matcher/lib/pem.d.cts +94 -3
- package/node_modules/path-expression-matcher/lib/pem.min.js +1 -1
- package/node_modules/path-expression-matcher/lib/pem.min.js.map +1 -1
- package/node_modules/path-expression-matcher/package.json +2 -1
- package/node_modules/path-expression-matcher/src/ExpressionSet.js +18 -2
- package/node_modules/path-expression-matcher/src/Matcher.js +109 -16
- package/node_modules/path-expression-matcher/src/index.d.ts +67 -1
- package/node_modules/path-expression-matcher/src/index.js +3 -2
- package/node_modules/semver/classes/range.js +24 -4
- package/node_modules/semver/classes/semver.js +19 -2
- package/node_modules/semver/package.json +2 -2
- package/node_modules/semver/ranges/subset.js +2 -2
- package/node_modules/strnum/CHANGELOG.md +14 -0
- package/node_modules/strnum/README.md +9 -0
- package/node_modules/strnum/package.json +7 -3
- package/node_modules/strnum/strnum.js +14 -2
- package/node_modules/xml-naming/LICENSE +21 -0
- package/node_modules/xml-naming/README.md +99 -1
- package/node_modules/xml-naming/package.json +4 -2
- package/node_modules/xml-naming/src/index.d.ts +34 -0
- package/node_modules/xml-naming/src/index.js +134 -22
- package/node_modules/yargs/build/index.cjs +1 -1
- package/node_modules/yargs/package.json +6 -4
- package/node_modules/yargs/yargs +5 -9
- package/node_modules/yargs/yargs.cjs +15 -0
- package/package.json +8 -9
- package/node_modules/yargs/browser.d.ts +0 -5
|
@@ -98,6 +98,9 @@ class Range {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
parseRange (range) {
|
|
101
|
+
// strip build metadata so it can't bleed into the version
|
|
102
|
+
range = range.replace(BUILDSTRIPRE, '')
|
|
103
|
+
|
|
101
104
|
// memoize range parsing for performance.
|
|
102
105
|
// this is a very hot path, and fully deterministic.
|
|
103
106
|
const memoOpts =
|
|
@@ -223,6 +226,7 @@ const debug = require('../internal/debug')
|
|
|
223
226
|
const SemVer = require('./semver')
|
|
224
227
|
const {
|
|
225
228
|
safeRe: re,
|
|
229
|
+
src,
|
|
226
230
|
t,
|
|
227
231
|
comparatorTrimReplace,
|
|
228
232
|
tildeTrimReplace,
|
|
@@ -230,6 +234,9 @@ const {
|
|
|
230
234
|
} = require('../internal/re')
|
|
231
235
|
const { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require('../internal/constants')
|
|
232
236
|
|
|
237
|
+
// unbounded global build-metadata stripper used by parseRange
|
|
238
|
+
const BUILDSTRIPRE = new RegExp(src[t.BUILD], 'g')
|
|
239
|
+
|
|
233
240
|
const isNullSet = c => c.value === '<0.0.0-0'
|
|
234
241
|
const isAny = c => c.value === ''
|
|
235
242
|
|
|
@@ -270,6 +277,11 @@ const parseComparator = (comp, options) => {
|
|
|
270
277
|
|
|
271
278
|
const isX = id => !id || id.toLowerCase() === 'x' || id === '*'
|
|
272
279
|
|
|
280
|
+
const invalidXRangeOrder = (M, m, p) => (
|
|
281
|
+
(isX(M) && !isX(m)) ||
|
|
282
|
+
(isX(m) && p && !isX(p))
|
|
283
|
+
)
|
|
284
|
+
|
|
273
285
|
// ~, ~> --> * (any, kinda silly)
|
|
274
286
|
// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0
|
|
275
287
|
// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0
|
|
@@ -287,6 +299,10 @@ const replaceTildes = (comp, options) => {
|
|
|
287
299
|
|
|
288
300
|
const replaceTilde = (comp, options) => {
|
|
289
301
|
const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]
|
|
302
|
+
// if we're including prereleases in the match, then the lower bound is
|
|
303
|
+
// -0, the lowest possible prerelease value, just like x-ranges and carets.
|
|
304
|
+
// this keeps `~1.2` equivalent to the `1.2.x` x-range it's documented as.
|
|
305
|
+
const z = options.includePrerelease ? '-0' : ''
|
|
290
306
|
return comp.replace(r, (_, M, m, p, pr) => {
|
|
291
307
|
debug('tilde', comp, _, M, m, p, pr)
|
|
292
308
|
let ret
|
|
@@ -294,10 +310,10 @@ const replaceTilde = (comp, options) => {
|
|
|
294
310
|
if (isX(M)) {
|
|
295
311
|
ret = ''
|
|
296
312
|
} else if (isX(m)) {
|
|
297
|
-
ret = `>=${M}.0.0 <${+M + 1}.0.0-0`
|
|
313
|
+
ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`
|
|
298
314
|
} else if (isX(p)) {
|
|
299
315
|
// ~1.2 == >=1.2.0 <1.3.0-0
|
|
300
|
-
ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`
|
|
316
|
+
ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`
|
|
301
317
|
} else if (pr) {
|
|
302
318
|
debug('replaceTilde pr', pr)
|
|
303
319
|
ret = `>=${M}.${m}.${p}-${pr
|
|
@@ -366,10 +382,10 @@ const replaceCaret = (comp, options) => {
|
|
|
366
382
|
if (M === '0') {
|
|
367
383
|
if (m === '0') {
|
|
368
384
|
ret = `>=${M}.${m}.${p
|
|
369
|
-
}
|
|
385
|
+
} <${M}.${m}.${+p + 1}-0`
|
|
370
386
|
} else {
|
|
371
387
|
ret = `>=${M}.${m}.${p
|
|
372
|
-
}
|
|
388
|
+
} <${M}.${+m + 1}.0-0`
|
|
373
389
|
}
|
|
374
390
|
} else {
|
|
375
391
|
ret = `>=${M}.${m}.${p
|
|
@@ -395,6 +411,10 @@ const replaceXRange = (comp, options) => {
|
|
|
395
411
|
const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]
|
|
396
412
|
return comp.replace(r, (ret, gtlt, M, m, p, pr) => {
|
|
397
413
|
debug('xRange', comp, ret, gtlt, M, m, p, pr)
|
|
414
|
+
if (invalidXRangeOrder(M, m, p)) {
|
|
415
|
+
return comp
|
|
416
|
+
}
|
|
417
|
+
|
|
398
418
|
const xM = isX(M)
|
|
399
419
|
const xm = xM || isX(m)
|
|
400
420
|
const xp = xm || isX(p)
|
|
@@ -6,6 +6,22 @@ const { safeRe: re, t } = require('../internal/re')
|
|
|
6
6
|
|
|
7
7
|
const parseOptions = require('../internal/parse-options')
|
|
8
8
|
const { compareIdentifiers } = require('../internal/identifiers')
|
|
9
|
+
|
|
10
|
+
const isPrereleaseIdentifier = (prerelease, identifier) => {
|
|
11
|
+
const identifiers = identifier.split('.')
|
|
12
|
+
if (identifiers.length > prerelease.length) {
|
|
13
|
+
return false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < identifiers.length; i++) {
|
|
17
|
+
if (compareIdentifiers(prerelease[i], identifiers[i]) !== 0) {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return true
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
class SemVer {
|
|
10
26
|
constructor (version, options) {
|
|
11
27
|
options = parseOptions(options)
|
|
@@ -309,8 +325,9 @@ class SemVer {
|
|
|
309
325
|
if (identifierBase === false) {
|
|
310
326
|
prerelease = [identifier]
|
|
311
327
|
}
|
|
312
|
-
if (
|
|
313
|
-
|
|
328
|
+
if (isPrereleaseIdentifier(this.prerelease, identifier)) {
|
|
329
|
+
const prereleaseBase = this.prerelease[identifier.split('.').length]
|
|
330
|
+
if (isNaN(prereleaseBase)) {
|
|
314
331
|
this.prerelease = prerelease
|
|
315
332
|
}
|
|
316
333
|
} else {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "semver",
|
|
3
|
-
"version": "7.8.
|
|
3
|
+
"version": "7.8.5",
|
|
4
4
|
"description": "The semantic version parser used by npm.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\""
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@npmcli/eslint-config": "^
|
|
17
|
+
"@npmcli/eslint-config": "^7.0.0",
|
|
18
18
|
"@npmcli/template-oss": "5.0.0",
|
|
19
19
|
"benchmark": "^2.1.4",
|
|
20
20
|
"tap": "^16.0.0"
|
|
@@ -174,7 +174,7 @@ const simpleSubset = (sub, dom, options) => {
|
|
|
174
174
|
if (higher === c && higher !== gt) {
|
|
175
175
|
return false
|
|
176
176
|
}
|
|
177
|
-
} else if (gt.operator === '>=' && !
|
|
177
|
+
} else if (gt.operator === '>=' && !c.test(gt.semver)) {
|
|
178
178
|
return false
|
|
179
179
|
}
|
|
180
180
|
}
|
|
@@ -192,7 +192,7 @@ const simpleSubset = (sub, dom, options) => {
|
|
|
192
192
|
if (lower === c && lower !== lt) {
|
|
193
193
|
return false
|
|
194
194
|
}
|
|
195
|
-
} else if (lt.operator === '<=' && !
|
|
195
|
+
} else if (lt.operator === '<=' && !c.test(lt.semver)) {
|
|
196
196
|
return false
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
|
|
2
|
+
**2.4.2 / 2026-08-14**
|
|
3
|
+
- fix: trimZeros to avoid quadratic complexity
|
|
4
|
+
|
|
5
|
+
**2.4.1 / 2026-06-18**
|
|
6
|
+
- deps: update anynum to 1.0.1
|
|
7
|
+
|
|
8
|
+
**2.4.0 / 2026-06-09**
|
|
9
|
+
- support unicode numerals using 'anynum'
|
|
10
|
+
|
|
11
|
+
**2.3.0 / 2026-05-07**
|
|
12
|
+
- support octal and binary, test with @byspec/numbers
|
|
13
|
+
- test with @byspec/numbers
|
|
14
|
+
|
|
15
|
+
|
|
2
16
|
**2.2.3 / 2026-04-07**
|
|
3
17
|
- remove unnecessary files from npm package
|
|
4
18
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# strnum
|
|
2
2
|
Parse string into Number based on configuration
|
|
3
3
|
|
|
4
|
+
[](https://npm-compare.com/strnum)
|
|
5
|
+
[](https://www.npmjs.com/package/strnum)
|
|
6
|
+
[](https://github.com/NaturalIntelligence/strnum)
|
|
7
|
+
|
|
4
8
|
## Users
|
|
5
9
|
|
|
6
10
|
<a href="https://github.com/aws-amplify" target="_blank"><img src="https://avatars.githubusercontent.com/u/41077760?s=100&v=4"></a>
|
|
@@ -86,6 +90,10 @@ toNumber("1.0e-2"); //0.01)
|
|
|
86
90
|
|
|
87
91
|
toNumber("+1212121212"); // 1212121212
|
|
88
92
|
toNumber("+1212121212", { skipLike: /\+[0-9]{10}/} )); //"+1212121212"
|
|
93
|
+
|
|
94
|
+
toNumber("1e1000", { unicode: true, infinity: "original" }); //"1e1000"
|
|
95
|
+
toNumber("1000", { unicode: true }); //1000
|
|
96
|
+
toNumber("1000", { unicode: false }); //"1000"
|
|
89
97
|
```
|
|
90
98
|
|
|
91
99
|
Supported Options
|
|
@@ -95,6 +103,7 @@ leadingZeros: true, //when number with leading zeros like 08 should be parsed. 0
|
|
|
95
103
|
eNotation: true, //when number with eNotation or number parsed in eNotation should be considered
|
|
96
104
|
skipLike: /regex/ //when string should not be parsed when it matches the specified regular expression
|
|
97
105
|
infinity: "original", // "null", "infinity" (Infinity type), "string" ("Infinity" (the string literal))
|
|
106
|
+
unicode: false, //when number with unicode numerals should be parsed
|
|
98
107
|
```
|
|
99
108
|
|
|
100
109
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strnum",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Parse String to Number based on configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "strnum.js",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"string",
|
|
12
12
|
"number",
|
|
13
13
|
"parse",
|
|
14
|
-
"convert"
|
|
14
|
+
"convert",
|
|
15
|
+
"unicode"
|
|
15
16
|
],
|
|
16
17
|
"repository": {
|
|
17
18
|
"type": "git",
|
|
@@ -28,5 +29,8 @@
|
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@byspec/numbers": "^0.1.1",
|
|
30
31
|
"jasmine": "^5.6.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"anynum": "^1.0.1"
|
|
31
35
|
}
|
|
32
|
-
}
|
|
36
|
+
}
|
|
@@ -3,6 +3,8 @@ const binRegex = /^0b[01]+$/;
|
|
|
3
3
|
const octRegex = /^0o[0-7]+$/;
|
|
4
4
|
const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/;
|
|
5
5
|
|
|
6
|
+
import anynum from "anynum";
|
|
7
|
+
|
|
6
8
|
const consider = {
|
|
7
9
|
hex: true,
|
|
8
10
|
binary: false,
|
|
@@ -12,6 +14,7 @@ const consider = {
|
|
|
12
14
|
eNotation: true,
|
|
13
15
|
//skipLike: /regex/,
|
|
14
16
|
infinity: "original", // "null", "infinity" (Infinity type), "string" ("Infinity" (the string literal))
|
|
17
|
+
unicode: false,
|
|
15
18
|
};
|
|
16
19
|
|
|
17
20
|
export default function toNumber(str, options = {}) {
|
|
@@ -23,7 +26,12 @@ export default function toNumber(str, options = {}) {
|
|
|
23
26
|
if (trimmedStr.length === 0) return str;
|
|
24
27
|
else if (options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str;
|
|
25
28
|
else if (trimmedStr === "0") return 0;
|
|
26
|
-
|
|
29
|
+
|
|
30
|
+
if (options.unicode) {
|
|
31
|
+
trimmedStr = anynum(trimmedStr);
|
|
32
|
+
if (trimmedStr === "0") return 0; // re-check after normalization
|
|
33
|
+
}
|
|
34
|
+
if (options.hex && hexRegex.test(trimmedStr)) {
|
|
27
35
|
return parse_int(trimmedStr, 16);
|
|
28
36
|
} else if (options.binary && binRegex.test(trimmedStr)) {
|
|
29
37
|
return parse_int(trimmedStr, 2);
|
|
@@ -120,7 +128,11 @@ function resolveEnotation(str, trimmedStr, options) {
|
|
|
120
128
|
*/
|
|
121
129
|
function trimZeros(numStr) {
|
|
122
130
|
if (numStr && numStr.indexOf(".") !== -1) {//float
|
|
123
|
-
|
|
131
|
+
//remove ending zeros without the O(n^2) backtracking that /0+$/ hits
|
|
132
|
+
//when the string doesn't end in 0 but has a long internal zero-run
|
|
133
|
+
let end = numStr.length;
|
|
134
|
+
while (end > 0 && numStr.charCodeAt(end - 1) === 48 /* '0' */) end--;
|
|
135
|
+
numStr = numStr.slice(0, end);
|
|
124
136
|
if (numStr === ".") numStr = "0";
|
|
125
137
|
else if (numStr[0] === ".") numStr = "0" + numStr;
|
|
126
138
|
else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Natural Intelligence
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
# xml-naming
|
|
2
|
+
[](https://npm-compare.com/xml-naming)
|
|
3
|
+
[](https://www.npmjs.com/package/xml-naming)
|
|
4
|
+
[](https://github.com/NaturalIntelligence/xml-naming)
|
|
2
5
|
|
|
3
6
|
Validates XML name productions as defined in the [XML 1.0](https://www.w3.org/TR/xml/) and [XML 1.1](https://www.w3.org/TR/xml11/) specifications.
|
|
4
7
|
|
|
@@ -71,6 +74,88 @@ name('\uD800\uDC00', { xmlVersion: '1.1' }) // true
|
|
|
71
74
|
|
|
72
75
|
---
|
|
73
76
|
|
|
77
|
+
### ASCII-only fast path
|
|
78
|
+
|
|
79
|
+
All validators, `validate`, `validateAll`, and `sanitize` also accept `{ asciiOnly: true }`.
|
|
80
|
+
When set, matching is restricted to the ASCII subset of the NameStartChar/NameChar
|
|
81
|
+
productions and skips unicode-aware regex matching entirely — no `\u00C0-\uFFFD`-style
|
|
82
|
+
ranges, and (for XML 1.1) no `/u` regex flag. Unicode-aware regexes are measurably slower
|
|
83
|
+
than plain ASCII matching in JS engines, so this is a real performance win when you know
|
|
84
|
+
your input is ASCII-only, which is the common case for HTML/SVG ids and most XML tags.
|
|
85
|
+
|
|
86
|
+
**This is opt-in and defaults to `false`** for backward compatibility: turning it on
|
|
87
|
+
changes behavior, since it rejects legitimate non-ASCII XML names that would otherwise be
|
|
88
|
+
valid. Only enable it when you control the input and know it's ASCII (e.g. internal
|
|
89
|
+
identifiers, machine-generated names), not for validating arbitrary user- or
|
|
90
|
+
externally-supplied XML/SVG content.
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
import { name, sanitize } from 'xml-naming';
|
|
94
|
+
|
|
95
|
+
name('café', { asciiOnly: true }) // false — 'é' is not ASCII, even though it's
|
|
96
|
+
name('café') // true a valid XML 1.0/1.1 NameChar
|
|
97
|
+
|
|
98
|
+
sanitize('café', 'name', { asciiOnly: true }) // 'caf_' — non-ASCII replaced too
|
|
99
|
+
sanitize('café', 'name') // 'café' — left untouched by default
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### Memoized validator (`createValidator`)
|
|
105
|
+
|
|
106
|
+
Real documents tend to reuse a small vocabulary of tag/attribute names across many
|
|
107
|
+
siblings (`id`, `class`, `href`, ... repeated across hundreds of elements). Calling the
|
|
108
|
+
plain boolean validators re-runs the regex on every call, even for names seen before.
|
|
109
|
+
|
|
110
|
+
`createValidator(production, opts)` returns a memoized validator function: `xmlVersion`
|
|
111
|
+
and `asciiOnly` are fixed at creation time (so the regex is resolved once, not per call),
|
|
112
|
+
and repeated inputs after the first are served from an internal cache instead of
|
|
113
|
+
re-matching the regex.
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
import { createValidator } from 'xml-naming';
|
|
117
|
+
|
|
118
|
+
const isQName = createValidator('qName', { xmlVersion: '1.0' });
|
|
119
|
+
|
|
120
|
+
isQName('sku'); // false → regex test (cache miss), result cached
|
|
121
|
+
isQName('sku'); // false → cache hit, no regex run
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Use one instance per document/parse (or reuse across a session — your choice), rather
|
|
125
|
+
than creating one per call:
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
// e.g. inside a parser, once per parse call:
|
|
129
|
+
const isValidTag = createValidator('qName', { asciiOnly: true });
|
|
130
|
+
|
|
131
|
+
for (const tagName of tagNames) {
|
|
132
|
+
if (!isValidTag(tagName)) throw new Error(`Invalid tag name: ${tagName}`);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Because the validator is a plain function, this loop already gets short-circuit
|
|
137
|
+
behaviour (via `break`/`throw` on first failure) and zero extra allocation on the happy
|
|
138
|
+
path — no separate "bulk" API is needed for that.
|
|
139
|
+
|
|
140
|
+
**Cache bound:** the internal cache is capped by `maxCacheSize` (default `2048`). Once
|
|
141
|
+
the cap is reached, new distinct strings are still validated correctly, they're just no
|
|
142
|
+
longer cached — existing cached entries keep being served. This keeps memory bounded
|
|
143
|
+
even against high-cardinality or adversarial input (e.g. externally-supplied names that
|
|
144
|
+
never repeat), without the cost of a full LRU or the perf cliff of reset-and-refill.
|
|
145
|
+
|
|
146
|
+
Call `.reset()` on the returned function to clear the cache manually, e.g. between
|
|
147
|
+
unrelated parse calls if you're reusing one validator instance across a long-running
|
|
148
|
+
process:
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
isQName.reset();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The cache is private to each `createValidator()` instance — there's no shared/global
|
|
155
|
+
cache, so unrelated callers never interfere with each other.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
74
159
|
### Diagnostic validation
|
|
75
160
|
|
|
76
161
|
```js
|
|
@@ -169,21 +254,34 @@ sanitize('my element', 'name', { replacement: '-' }) // 'my-element'
|
|
|
169
254
|
|
|
170
255
|
`opts`:
|
|
171
256
|
- `xmlVersion`: `'1.0'` (default) | `'1.1'`
|
|
257
|
+
- `asciiOnly`: boolean (default `false`) — ASCII-only fast path, see above
|
|
258
|
+
|
|
259
|
+
### `createValidator(production, opts?)` → memoized `(str) => boolean`, with `.reset()`
|
|
260
|
+
|
|
261
|
+
`opts`:
|
|
262
|
+
- `xmlVersion`: `'1.0'` (default) | `'1.1'`
|
|
263
|
+
- `asciiOnly`: boolean (default `false`)
|
|
264
|
+
- `maxCacheSize`: number (default `2048`) — cache stops accepting new entries once reached; existing entries keep serving hits
|
|
172
265
|
|
|
173
266
|
### `validate(str, production, opts?)` → `ValidationResult`
|
|
174
267
|
|
|
175
268
|
`production`: `'name'` | `'ncName'` | `'qName'` | `'nmToken'` | `'nmTokens'`
|
|
176
269
|
|
|
270
|
+
`opts`: same as boolean validators (`xmlVersion`, `asciiOnly`)
|
|
271
|
+
|
|
177
272
|
### `validateAll(strings[], production, opts?)` → `ValidationResult[]`
|
|
178
273
|
|
|
274
|
+
`opts`: same as `validate`
|
|
275
|
+
|
|
179
276
|
### `sanitize(str, production?, opts?)` → `string`
|
|
180
277
|
|
|
181
278
|
`opts`:
|
|
182
279
|
- `xmlVersion`: `'1.0'` | `'1.1'`
|
|
183
280
|
- `replacement`: string (default `'_'`)
|
|
281
|
+
- `asciiOnly`: boolean (default `false`) — also replaces non-ASCII characters, not just XML-illegal ones
|
|
184
282
|
|
|
185
283
|
---
|
|
186
284
|
|
|
187
285
|
## License
|
|
188
286
|
|
|
189
|
-
MIT
|
|
287
|
+
MIT
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xml-naming",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Validates XML name productions — Name, NCName, QName, NMToken, NMTokens — for XML 1.0 and 1.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
"README.md"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"test": "jasmine specs/*spec.js"
|
|
19
|
+
"test": "jasmine specs/*spec.js",
|
|
20
|
+
"perf": "node specs/perf.js"
|
|
20
21
|
},
|
|
21
22
|
"keywords": [
|
|
23
|
+
"fast",
|
|
22
24
|
"xml",
|
|
23
25
|
"xml-name",
|
|
24
26
|
"ncname",
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export interface ValidationOptions {
|
|
2
2
|
/** XML specification version to validate against. Defaults to '1.0'. */
|
|
3
3
|
xmlVersion?: '1.0' | '1.1';
|
|
4
|
+
/**
|
|
5
|
+
* Restrict matching to the ASCII subset of the NameStartChar/NameChar
|
|
6
|
+
* productions and skip unicode-aware regex matching entirely. Faster,
|
|
7
|
+
* especially for XML 1.1 (which otherwise requires the `/u` regex flag),
|
|
8
|
+
* but rejects legitimate non-ASCII XML names. Off by default for
|
|
9
|
+
* backward compatibility — opt in only when inputs are known to be ASCII.
|
|
10
|
+
* Defaults to false.
|
|
11
|
+
*/
|
|
12
|
+
asciiOnly?: boolean;
|
|
4
13
|
}
|
|
5
14
|
|
|
6
15
|
export interface SanitizeOptions extends ValidationOptions {
|
|
@@ -55,6 +64,31 @@ export function nmToken(str: string, opts?: ValidationOptions): boolean;
|
|
|
55
64
|
*/
|
|
56
65
|
export function nmTokens(str: string, opts?: ValidationOptions): boolean;
|
|
57
66
|
|
|
67
|
+
export interface CreateValidatorOptions extends ValidationOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Max number of distinct strings to cache. Once reached, new strings are
|
|
70
|
+
* still validated correctly but are no longer cached; existing cached
|
|
71
|
+
* entries keep being served. Defaults to 2048.
|
|
72
|
+
*/
|
|
73
|
+
maxCacheSize?: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface MemoizedValidator {
|
|
77
|
+
(str: string): boolean;
|
|
78
|
+
/** Clears the internal cache. */
|
|
79
|
+
reset(): void;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Returns a memoized boolean validator function for a single production.
|
|
84
|
+
* `opts` (xmlVersion, asciiOnly) are fixed at creation time. Repeated calls
|
|
85
|
+
* with the same string after the first are served from an internal cache
|
|
86
|
+
* instead of re-running the regex — useful when validating a small, reused
|
|
87
|
+
* vocabulary of names (e.g. tag/attribute names across many siblings in a
|
|
88
|
+
* document) many times.
|
|
89
|
+
*/
|
|
90
|
+
export function createValidator(production: Production, opts?: CreateValidatorOptions): MemoizedValidator;
|
|
91
|
+
|
|
58
92
|
/**
|
|
59
93
|
* Validates a string against a named XML production and returns a detailed result.
|
|
60
94
|
*/
|