schema-dsl 1.2.5 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +130 -238
- package/LICENSE +21 -21
- package/README.md +628 -2486
- package/dist/DslBuilder-BIgQOAXp.d.ts +343 -0
- package/dist/DslBuilder-CjHTucNQ.d.cts +343 -0
- package/dist/Validator-CllRdrY0.d.ts +192 -0
- package/dist/Validator-D6okG9tr.d.cts +192 -0
- package/dist/index.cjs +6640 -0
- package/dist/index.d.cts +1151 -0
- package/dist/index.d.ts +1151 -0
- package/dist/index.js +6574 -0
- package/dist/plugin-CIKtTMtS.d.cts +246 -0
- package/dist/plugin-CIKtTMtS.d.ts +246 -0
- package/dist/plugins/custom-format.cjs +3818 -0
- package/dist/plugins/custom-format.d.cts +12 -0
- package/dist/plugins/custom-format.d.ts +12 -0
- package/dist/plugins/custom-format.js +3788 -0
- package/dist/plugins/custom-type-example.cjs +3811 -0
- package/dist/plugins/custom-type-example.d.cts +8 -0
- package/dist/plugins/custom-type-example.d.ts +8 -0
- package/dist/plugins/custom-type-example.js +3781 -0
- package/dist/plugins/custom-validator.cjs +144 -0
- package/dist/plugins/custom-validator.d.cts +10 -0
- package/dist/plugins/custom-validator.d.ts +10 -0
- package/dist/plugins/custom-validator.js +119 -0
- package/docs/FEATURE-INDEX.md +553 -519
- package/docs/add-custom-locale.md +496 -483
- package/docs/add-keyword.md +24 -0
- package/docs/api-reference.md +1047 -805
- package/docs/api.md +13 -0
- package/docs/best-practices-project-structure.md +417 -408
- package/docs/best-practices.md +712 -672
- package/docs/cache-manager.md +344 -336
- package/docs/compile.md +45 -0
- package/docs/conditional-api.md +1307 -1278
- package/docs/custom-extensions-guide.md +339 -411
- package/docs/design-philosophy.md +606 -601
- package/docs/doc-index.md +324 -0
- package/docs/dsl-syntax.md +714 -664
- package/docs/dynamic-locale.md +608 -598
- package/docs/enum.md +482 -475
- package/docs/error-handling.md +1975 -1966
- package/docs/export-guide.md +501 -462
- package/docs/export-limitations.md +567 -551
- package/docs/faq.md +596 -577
- package/docs/frontend-i18n-guide.md +307 -293
- package/docs/i18n-user-guide.md +487 -474
- package/docs/i18n.md +476 -457
- package/docs/index.md +48 -0
- package/docs/json-schema-basics.md +40 -0
- package/docs/label-vs-description.md +271 -262
- package/docs/markdown-exporter.md +406 -397
- package/docs/mongodb-exporter.md +302 -295
- package/docs/multi-language.md +26 -0
- package/docs/multi-type-support.md +322 -329
- package/docs/mysql-exporter.md +280 -273
- package/docs/number-operators.md +449 -442
- package/docs/optional-marker-guide.md +326 -321
- package/docs/performance-guide.md +49 -0
- package/docs/plugin-system.md +381 -542
- package/docs/plugin-type-registration.md +34 -0
- package/docs/postgresql-exporter.md +311 -304
- package/docs/public/favicon.svg +5 -0
- package/docs/quick-start.md +435 -761
- package/docs/runtime-locale-support.md +532 -521
- package/docs/schema-helper.md +345 -340
- package/docs/schema-utils-advanced-issues.md +23 -0
- package/docs/schema-utils-best-practices.md +20 -0
- package/docs/schema-utils-chaining.md +150 -143
- package/docs/schema-utils.md +524 -490
- package/docs/security-checklist.md +20 -0
- package/docs/string-extensions.md +488 -480
- package/docs/troubleshooting.md +486 -471
- package/docs/type-converter.md +310 -319
- package/docs/type-reference.md +242 -219
- package/docs/typescript-guide.md +584 -573
- package/docs/union-type-guide.md +157 -147
- package/docs/union-types.md +284 -277
- package/docs/validate-async.md +491 -480
- package/docs/validate-batch.md +49 -0
- package/docs/validate-dsl-object-support.md +578 -573
- package/docs/validate.md +506 -486
- package/docs/validation-guide.md +502 -484
- package/docs/validator.md +39 -0
- package/package.json +131 -73
- package/plugins/custom-format.cjs +8 -0
- package/plugins/custom-type-example.cjs +8 -0
- package/plugins/custom-validator.cjs +8 -0
- package/src/adapters/DslAdapter.ts +111 -0
- package/src/adapters/index.ts +1 -0
- package/src/config/constants.ts +83 -0
- package/src/config/index.ts +2 -0
- package/src/config/patterns.ts +77 -0
- package/src/core/CacheManager.ts +169 -0
- package/src/core/ConditionalBuilder.ts +382 -0
- package/src/core/ConditionalRuntime.ts +28 -0
- package/src/core/ConditionalValidator.ts +255 -0
- package/src/core/DslBuilder.ts +687 -0
- package/src/core/ErrorCodes.ts +38 -0
- package/src/core/ErrorFormatter.ts +271 -0
- package/src/core/JSONSchemaCore.ts +65 -0
- package/src/core/Locale.ts +187 -0
- package/src/core/MessageTemplate.ts +42 -0
- package/src/core/ObjectDslBuilder.ts +64 -0
- package/src/core/PluginManager.ts +326 -0
- package/src/core/StringExtensions.ts +140 -0
- package/src/core/TemplateEngine.ts +44 -0
- package/src/core/Validator.ts +448 -0
- package/src/errors/I18nError.ts +159 -0
- package/src/errors/ValidationError.ts +105 -0
- package/src/exporters/BaseExporter.ts +60 -0
- package/src/exporters/MarkdownExporter.ts +305 -0
- package/src/exporters/MongoDBExporter.ts +126 -0
- package/src/exporters/MySQLExporter.ts +156 -0
- package/src/exporters/PostgreSQLExporter.ts +222 -0
- package/src/exporters/index.ts +18 -0
- package/src/index.ts +651 -0
- package/{lib/locales/en-US.js → src/locales/en-US.ts} +160 -176
- package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +160 -113
- package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +160 -113
- package/src/locales/index.ts +103 -0
- package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +160 -118
- package/src/locales/types.ts +156 -0
- package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +160 -177
- package/src/parser/ConstraintParser.ts +101 -0
- package/src/parser/DslParser.ts +470 -0
- package/src/parser/SchemaCompiler.ts +66 -0
- package/src/parser/TypeRegistry.ts +250 -0
- package/src/parser/index.ts +6 -0
- package/src/plugins/custom-format.ts +124 -0
- package/src/plugins/custom-type-example.ts +106 -0
- package/src/plugins/custom-validator.ts +138 -0
- package/src/types/conditional.ts +28 -0
- package/src/types/config.ts +59 -0
- package/src/types/dsl.ts +131 -0
- package/src/types/error.ts +60 -0
- package/src/types/index.ts +17 -0
- package/src/types/infer.ts +128 -0
- package/src/types/plugin.ts +58 -0
- package/src/types/safe-regex.d.ts +9 -0
- package/src/types/schema.ts +66 -0
- package/src/types/validate.ts +71 -0
- package/src/utils/SchemaHelper.ts +196 -0
- package/src/utils/SchemaUtils.ts +365 -0
- package/src/utils/TypeConverter.ts +215 -0
- package/src/utils/index.ts +10 -0
- package/src/validators/CustomKeywords.ts +477 -0
- package/.eslintignore +0 -11
- package/.eslintrc.json +0 -27
- package/CONTRIBUTING.md +0 -368
- package/STATUS.md +0 -491
- package/changelogs/v1.0.0.md +0 -328
- package/changelogs/v1.0.9.md +0 -367
- package/changelogs/v1.1.0.md +0 -389
- package/changelogs/v1.1.1.md +0 -308
- package/changelogs/v1.1.2.md +0 -183
- package/changelogs/v1.1.3.md +0 -161
- package/changelogs/v1.1.4.md +0 -432
- package/changelogs/v1.1.5.md +0 -493
- package/changelogs/v1.1.6.md +0 -211
- package/changelogs/v1.1.8.md +0 -376
- package/changelogs/v1.2.3.md +0 -124
- package/docs/INDEX.md +0 -252
- package/docs/issues-resolved-summary.md +0 -196
- package/docs/performance-benchmark-report.md +0 -179
- package/docs/performance-quick-reference.md +0 -123
- package/docs/user-questions-answered.md +0 -353
- package/docs/validation-rules-v1.0.2.md +0 -1608
- package/examples/README.md +0 -81
- package/examples/array-dsl-example.js +0 -227
- package/examples/conditional-example.js +0 -288
- package/examples/conditional-non-object.js +0 -129
- package/examples/conditional-validate-example.js +0 -321
- package/examples/custom-extension.js +0 -85
- package/examples/dsl-match-example.js +0 -74
- package/examples/dsl-style.js +0 -118
- package/examples/dynamic-locale-configuration.js +0 -348
- package/examples/dynamic-locale-example.js +0 -287
- package/examples/enum.examples.js +0 -324
- package/examples/export-demo.js +0 -130
- package/examples/express-integration.js +0 -376
- package/examples/i18n-error-handling-complete.js +0 -381
- package/examples/i18n-error-handling-quickstart.md +0 -0
- package/examples/i18n-error.examples.js +0 -181
- package/examples/i18n-full-demo.js +0 -301
- package/examples/i18n-memory-safety.examples.js +0 -268
- package/examples/markdown-export.js +0 -71
- package/examples/middleware-usage.js +0 -93
- package/examples/new-features-comparison.js +0 -315
- package/examples/password-reset/README.md +0 -153
- package/examples/password-reset/schema.js +0 -26
- package/examples/password-reset/test.js +0 -101
- package/examples/plugin-system.examples.js +0 -205
- package/examples/schema-utils-chaining.examples.js +0 -250
- package/examples/simple-example.js +0 -122
- package/examples/slug.examples.js +0 -179
- package/examples/string-extensions.js +0 -297
- package/examples/union-type-example.js +0 -127
- package/examples/union-types-example.js +0 -77
- package/examples/user-registration/README.md +0 -156
- package/examples/user-registration/routes.js +0 -92
- package/examples/user-registration/schema.js +0 -150
- package/examples/user-registration/server.js +0 -74
- package/index.d.ts +0 -3658
- package/index.js +0 -475
- package/index.mjs +0 -60
- package/lib/adapters/DslAdapter.js +0 -995
- package/lib/adapters/index.js +0 -20
- package/lib/config/constants.js +0 -286
- package/lib/config/patterns/common.js +0 -47
- package/lib/config/patterns/creditCard.js +0 -9
- package/lib/config/patterns/idCard.js +0 -9
- package/lib/config/patterns/index.js +0 -9
- package/lib/config/patterns/licensePlate.js +0 -4
- package/lib/config/patterns/passport.js +0 -4
- package/lib/config/patterns/phone.js +0 -9
- package/lib/config/patterns/postalCode.js +0 -5
- package/lib/core/CacheManager.js +0 -376
- package/lib/core/ConditionalBuilder.js +0 -503
- package/lib/core/DslBuilder.js +0 -1589
- package/lib/core/ErrorCodes.js +0 -233
- package/lib/core/ErrorFormatter.js +0 -445
- package/lib/core/JSONSchemaCore.js +0 -347
- package/lib/core/Locale.js +0 -130
- package/lib/core/MessageTemplate.js +0 -98
- package/lib/core/PluginManager.js +0 -448
- package/lib/core/StringExtensions.js +0 -240
- package/lib/core/Validator.js +0 -654
- package/lib/errors/I18nError.js +0 -328
- package/lib/errors/ValidationError.js +0 -191
- package/lib/exporters/MarkdownExporter.js +0 -420
- package/lib/exporters/MongoDBExporter.js +0 -162
- package/lib/exporters/MySQLExporter.js +0 -212
- package/lib/exporters/PostgreSQLExporter.js +0 -289
- package/lib/exporters/index.js +0 -24
- package/lib/locales/index.js +0 -8
- package/lib/utils/LRUCache.js +0 -174
- package/lib/utils/SchemaHelper.js +0 -240
- package/lib/utils/SchemaUtils.js +0 -445
- package/lib/utils/TypeConverter.js +0 -245
- package/lib/utils/index.js +0 -13
- package/lib/validators/CustomKeywords.js +0 -616
- package/lib/validators/index.js +0 -11
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Validator 类概述
|
|
2
|
+
|
|
3
|
+
`Validator` 是对 AJV 的封装,提供编译缓存、错误格式化、自定义关键字和批量验证能力。
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
const { Validator, dsl } = require('schema-dsl');
|
|
7
|
+
const validator = new Validator();
|
|
8
|
+
const schema = dsl({ email: 'email!' });
|
|
9
|
+
console.log(validator.validate(schema, { email: 'test@example.com' }));
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 缓存配置
|
|
13
|
+
|
|
14
|
+
`Validator` 构造器支持两种缓存写法:
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
new Validator({ cache: true }); // 使用默认缓存配置
|
|
18
|
+
new Validator({ cache: false }); // 关闭缓存
|
|
19
|
+
|
|
20
|
+
new Validator({
|
|
21
|
+
cache: {
|
|
22
|
+
enabled: true,
|
|
23
|
+
maxSize: 500,
|
|
24
|
+
ttl: 60 * 60 * 1000
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> 如果你希望直接传入 DSL 对象(例如 `validate({ email: 'email!' }, data)`),请使用顶层便捷函数 `validate()` / `validateAsync()`;`Validator` 实例方法仍建议接收标准 JSON Schema 或 `dsl({...})` 的转换结果。
|
|
30
|
+
|
|
31
|
+
相关方法:`compile()`、`validate()`、`validateAsync()`、`validateBatch()`、`addKeyword()`、`addFormat()`。
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 对应示例文件
|
|
36
|
+
|
|
37
|
+
**示例入口**: [validator.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/validator.ts)
|
|
38
|
+
**说明**: 覆盖 `new Validator()` 的常见配置、单次验证、编译缓存命中和 `validateBatch()` 复用路径。
|
|
39
|
+
|
package/package.json
CHANGED
|
@@ -1,73 +1,131 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "schema-dsl",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "index.
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"import":
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "schema-dsl",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "A concise and powerful JSON Schema validation library - DSL syntax + String extensions + convenient validate API",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.cts",
|
|
16
|
+
"default": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"./plugins/custom-format": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/plugins/custom-format.d.ts",
|
|
22
|
+
"default": "./dist/plugins/custom-format.js"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./dist/plugins/custom-format.d.cts",
|
|
26
|
+
"default": "./dist/plugins/custom-format.cjs"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"./plugins/custom-validator": {
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/plugins/custom-validator.d.ts",
|
|
32
|
+
"default": "./dist/plugins/custom-validator.js"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./dist/plugins/custom-validator.d.cts",
|
|
36
|
+
"default": "./dist/plugins/custom-validator.cjs"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"./plugins/custom-type-example": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/plugins/custom-type-example.d.ts",
|
|
42
|
+
"default": "./dist/plugins/custom-type-example.js"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./dist/plugins/custom-type-example.d.cts",
|
|
46
|
+
"default": "./dist/plugins/custom-type-example.cjs"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"dev": "tsup --watch",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:watch": "vitest",
|
|
55
|
+
"test:coverage": "vitest run --coverage",
|
|
56
|
+
"typecheck": "tsc --noEmit",
|
|
57
|
+
"examples:typecheck": "tsc -p tsconfig.examples.json --noEmit",
|
|
58
|
+
"examples:build": "tsc -p tsconfig.examples.json",
|
|
59
|
+
"lint": "eslint src/**/*.ts",
|
|
60
|
+
"test:version": "node -e \"const p=require('./package.json');const {VERSION}=require('./dist/index.cjs');if(p.version!==VERSION)throw new Error('Version mismatch: '+p.version+' vs '+VERSION);console.log('Version OK:',p.version)\"",
|
|
61
|
+
"bench": "node test/benchmarks/library-comparison.js",
|
|
62
|
+
"prepublishOnly": "npm run build && npm run typecheck && npm test"
|
|
63
|
+
},
|
|
64
|
+
"keywords": [
|
|
65
|
+
"schema",
|
|
66
|
+
"validation",
|
|
67
|
+
"validator",
|
|
68
|
+
"dsl",
|
|
69
|
+
"json-schema",
|
|
70
|
+
"data-validation",
|
|
71
|
+
"form-validation",
|
|
72
|
+
"mongodb",
|
|
73
|
+
"mysql",
|
|
74
|
+
"postgresql",
|
|
75
|
+
"database-schema",
|
|
76
|
+
"i18n",
|
|
77
|
+
"internationalization",
|
|
78
|
+
"typescript",
|
|
79
|
+
"express",
|
|
80
|
+
"koa",
|
|
81
|
+
"fastify",
|
|
82
|
+
"rest-api",
|
|
83
|
+
"input-validation"
|
|
84
|
+
],
|
|
85
|
+
"author": "rocky <rockyshi1993@gmail.com>",
|
|
86
|
+
"license": "MIT",
|
|
87
|
+
"repository": {
|
|
88
|
+
"type": "git",
|
|
89
|
+
"url": "https://github.com/vextjs/schema-dsl.git"
|
|
90
|
+
},
|
|
91
|
+
"bugs": {
|
|
92
|
+
"url": "https://github.com/vextjs/schema-dsl/issues"
|
|
93
|
+
},
|
|
94
|
+
"homepage": "https://github.com/vextjs/schema-dsl#readme",
|
|
95
|
+
"engines": {
|
|
96
|
+
"node": ">=18.0.0"
|
|
97
|
+
},
|
|
98
|
+
"dependencies": {
|
|
99
|
+
"ajv": "^8.18.0",
|
|
100
|
+
"ajv-formats": "^2.1.1",
|
|
101
|
+
"cache-hub": "^1.0.0",
|
|
102
|
+
"json5": "^2.2.3",
|
|
103
|
+
"safe-regex": "^2.1.1"
|
|
104
|
+
},
|
|
105
|
+
"devDependencies": {
|
|
106
|
+
"@types/node": "^25.6.0",
|
|
107
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
108
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
109
|
+
"@vitest/coverage-v8": "^3.0.0",
|
|
110
|
+
"eslint": "^9.0.0",
|
|
111
|
+
"fastest-validator": "^1.19.1",
|
|
112
|
+
"joi": "^18.1.2",
|
|
113
|
+
"tsup": "^8.0.0",
|
|
114
|
+
"typescript": "^5.5.0",
|
|
115
|
+
"vitest": "^3.0.0",
|
|
116
|
+
"yup": "^1.7.1",
|
|
117
|
+
"zod": "^4.3.6"
|
|
118
|
+
},
|
|
119
|
+
"type": "module",
|
|
120
|
+
"files": [
|
|
121
|
+
"dist/**/*.js",
|
|
122
|
+
"dist/**/*.cjs",
|
|
123
|
+
"dist/**/*.d.ts",
|
|
124
|
+
"dist/**/*.d.cts",
|
|
125
|
+
"plugins",
|
|
126
|
+
"src",
|
|
127
|
+
"docs",
|
|
128
|
+
"README.md",
|
|
129
|
+
"CHANGELOG.md"
|
|
130
|
+
]
|
|
131
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* DslAdapter — DSL parsing adapter (thin wrapper layer).
|
|
4
|
+
*
|
|
5
|
+
* v2 changes:
|
|
6
|
+
* - All parsing logic delegated to DslParser (replaces v1 DslAdapter._parseType duplication)
|
|
7
|
+
* - Fixes DA-01/DA-02/DA-03 (handled uniformly by the DslParser pipeline)
|
|
8
|
+
* - parseObject delegates to DslParser.parseObject (replaces JSONSchemaCore)
|
|
9
|
+
* - BC-2 fix: parseObject() returns ObjectDslBuilder (supports chain .strict()/.requireAll())
|
|
10
|
+
* - BC-4 fix: typeMap getter exposes all registered types; registerType() convenience entry point
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { JSONSchema } from '../types/schema.js'
|
|
14
|
+
import type { DslDefinition } from '../types/dsl.js'
|
|
15
|
+
import { DslParser } from '../parser/DslParser.js'
|
|
16
|
+
import { TypeRegistry } from '../parser/TypeRegistry.js'
|
|
17
|
+
import { ObjectDslBuilder } from '../core/ObjectDslBuilder.js'
|
|
18
|
+
|
|
19
|
+
type DslMarker = Record<string, unknown>
|
|
20
|
+
|
|
21
|
+
export const DslAdapter = {
|
|
22
|
+
/**
|
|
23
|
+
* Parse a DSL string into a JSON Schema.
|
|
24
|
+
* Equivalent to v1 DslAdapter.parseString(), but delegates to the unified DslParser.
|
|
25
|
+
*/
|
|
26
|
+
parseString(dslString: string): JSONSchema {
|
|
27
|
+
if (!dslString || typeof dslString !== 'string') {
|
|
28
|
+
throw new Error('[schema-dsl] DslAdapter.parseString: DSL must be a string')
|
|
29
|
+
}
|
|
30
|
+
return DslParser.parseString(dslString)
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* parse() — alias for parseString() (backwards compat with v1).
|
|
35
|
+
*/
|
|
36
|
+
parse(dslString: string): JSONSchema {
|
|
37
|
+
if (!dslString || typeof dslString !== 'string') {
|
|
38
|
+
throw new Error('[schema-dsl] DslAdapter.parse: DSL must be a string')
|
|
39
|
+
}
|
|
40
|
+
const schema = DslParser.parseString(dslString)
|
|
41
|
+
// v1 compat: always set _required (false if not set)
|
|
42
|
+
if ((schema as Record<string, unknown>)['_required'] === undefined) {
|
|
43
|
+
(schema as Record<string, unknown>)['_required'] = false
|
|
44
|
+
}
|
|
45
|
+
return schema
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse an object-form DSL definition → ObjectDslBuilder (BC-2 fix).
|
|
50
|
+
* v1: parseObject() returned a chainable builder (.strict()/.requireAll()).
|
|
51
|
+
* v2 fix: returns ObjectDslBuilder wrapping the compiled JSONSchema.
|
|
52
|
+
*/
|
|
53
|
+
parseObject(dslObj: DslDefinition): ObjectDslBuilder {
|
|
54
|
+
const schema = DslParser.parseObject(dslObj)
|
|
55
|
+
return new ObjectDslBuilder(schema)
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create a Match marker (v1 compat). The actual JSON Schema is built per target field in parseObject.
|
|
60
|
+
*/
|
|
61
|
+
match(field: string, map: Record<string, unknown>): DslMarker {
|
|
62
|
+
return { _isMatch: true, field, map }
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create an If marker (v1 compat). The actual JSON Schema is built per target field in parseObject.
|
|
67
|
+
*/
|
|
68
|
+
if(condition: string, thenSchema: unknown, elseSchema?: unknown): DslMarker {
|
|
69
|
+
return { _isIf: true, condition, then: thenSchema, else: elseSchema }
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* toCore() — v1 compat: returns { schema } wrapper
|
|
74
|
+
*/
|
|
75
|
+
toCore(dslInput: string | DslDefinition): { schema: JSONSchema } {
|
|
76
|
+
let schema: JSONSchema
|
|
77
|
+
if (typeof dslInput === 'string') {
|
|
78
|
+
schema = this.parse(dslInput)
|
|
79
|
+
} else {
|
|
80
|
+
schema = DslParser.parseObject(dslInput)
|
|
81
|
+
}
|
|
82
|
+
return { schema }
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* typeMap getter — v1 compat: DslAdapter.typeMap exposes all registered types (BC-4 fix).
|
|
87
|
+
* Assigning typeMap[name] = schema is equivalent to calling TypeRegistry.register(name, schema).
|
|
88
|
+
*/
|
|
89
|
+
get typeMap(): Record<string, JSONSchema> {
|
|
90
|
+
const map: Record<string, JSONSchema> = {}
|
|
91
|
+
for (const [name, def] of TypeRegistry.entries()) {
|
|
92
|
+
map[name] = def.baseSchema as JSONSchema
|
|
93
|
+
}
|
|
94
|
+
return new Proxy(map, {
|
|
95
|
+
set(_target: Record<string, JSONSchema>, key: string, value: JSONSchema) {
|
|
96
|
+
TypeRegistry.register(key, { baseSchema: value })
|
|
97
|
+
return true
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* registerType() — v1 compat: register a custom type into TypeRegistry (BC-4 fix).
|
|
104
|
+
*/
|
|
105
|
+
registerType(name: string, schema: JSONSchema): void {
|
|
106
|
+
TypeRegistry.register(name, { baseSchema: schema })
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type DslAdapterType = typeof DslAdapter
|
|
111
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './DslAdapter.js'
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global constants.
|
|
3
|
+
* Fixes:
|
|
4
|
+
* CF-01 IPv4 regex too permissive → replaced with RFC-compliant standard regex
|
|
5
|
+
* CF-02 IPv6 regex did not support compressed notation → replaced with full RFC 5952 compatible regex
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ========== Validation config ==========
|
|
9
|
+
export const VALIDATION = {
|
|
10
|
+
MAX_RECURSION_DEPTH: 100,
|
|
11
|
+
MAX_ARRAY_SIZE: 100_000,
|
|
12
|
+
MAX_STRING_LENGTH: 1_000_000,
|
|
13
|
+
MAX_OBJECT_KEYS: 10_000,
|
|
14
|
+
DEFAULT_TIMEOUT: 5_000,
|
|
15
|
+
REGEX_TIMEOUT: 100,
|
|
16
|
+
CUSTOM_VALIDATOR_TIMEOUT: 1_000,
|
|
17
|
+
} as const
|
|
18
|
+
|
|
19
|
+
// ========== Cache config ==========
|
|
20
|
+
export const CACHE = {
|
|
21
|
+
ENABLED: true,
|
|
22
|
+
SCHEMA_CACHE: {
|
|
23
|
+
MAX_SIZE: 5_000,
|
|
24
|
+
TTL: 3_600_000, // 1 hour
|
|
25
|
+
STRATEGY: 'LRU',
|
|
26
|
+
},
|
|
27
|
+
STATS_ENABLED: true,
|
|
28
|
+
} as const
|
|
29
|
+
|
|
30
|
+
// ========== Format validation regex ==========
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* CF-01 fix: RFC-compliant IPv4 regex.
|
|
34
|
+
* Each octet 0-255, four groups, full-string match.
|
|
35
|
+
* Rejects invalid addresses such as 999.999.999.999.
|
|
36
|
+
*/
|
|
37
|
+
const IPV4_OCTET = '(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)'
|
|
38
|
+
export const PATTERN_IPV4 = new RegExp(`^(?:${IPV4_OCTET}\\.){3}${IPV4_OCTET}$`)
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* CF-02 fix: Full IPv6 regex (RFC 5952 compatible).
|
|
42
|
+
* Covers:
|
|
43
|
+
* - Fully-expanded: 8 groups of hex
|
|
44
|
+
* - :: compressed: prefix / suffix / standalone :: variants
|
|
45
|
+
* No nested quantifiers (avoids ReDoS).
|
|
46
|
+
*/
|
|
47
|
+
const HEX4 = '[0-9a-fA-F]{1,4}'
|
|
48
|
+
const IPV6_FULL = `(?:${HEX4}:){7}${HEX4}`
|
|
49
|
+
const IPV6_COMPRESS = [
|
|
50
|
+
`(?:${HEX4}:){1,7}:`, // n:...:
|
|
51
|
+
`(?:${HEX4}:){1,6}:${HEX4}`, // n:...:n
|
|
52
|
+
`(?:${HEX4}:){1,5}(?::${HEX4}){1,2}`,
|
|
53
|
+
`(?:${HEX4}:){1,4}(?::${HEX4}){1,3}`,
|
|
54
|
+
`(?:${HEX4}:){1,3}(?::${HEX4}){1,4}`,
|
|
55
|
+
`(?:${HEX4}:){1,2}(?::${HEX4}){1,5}`,
|
|
56
|
+
`${HEX4}:(?::${HEX4}){1,6}`,
|
|
57
|
+
`:(?::${HEX4}){1,7}`, // ::n...
|
|
58
|
+
`::`, // standalone :: (all-zeros)
|
|
59
|
+
].join('|')
|
|
60
|
+
export const PATTERN_IPV6 = new RegExp(`^(?:${IPV6_FULL}|${IPV6_COMPRESS})$`)
|
|
61
|
+
|
|
62
|
+
export const FORMATS = {
|
|
63
|
+
BUILT_IN: [
|
|
64
|
+
'email', 'url', 'uri', 'uuid', 'ipv4', 'ipv6',
|
|
65
|
+
'hostname', 'date', 'date-time', 'time', 'regex', 'json',
|
|
66
|
+
] as const,
|
|
67
|
+
PATTERNS: {
|
|
68
|
+
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
69
|
+
uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
70
|
+
ipv4: PATTERN_IPV4,
|
|
71
|
+
ipv6: PATTERN_IPV6,
|
|
72
|
+
hostname: /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i,
|
|
73
|
+
dateTime: /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z?$/,
|
|
74
|
+
date: /^\d{4}-\d{2}-\d{2}$/,
|
|
75
|
+
time: /^\d{2}:\d{2}:\d{2}$/,
|
|
76
|
+
},
|
|
77
|
+
} as const
|
|
78
|
+
|
|
79
|
+
// ========== Plugin config ==========
|
|
80
|
+
export const PLUGINS = {
|
|
81
|
+
MAX_PLUGINS: 50,
|
|
82
|
+
NAMING_CONVENTION: /^schema-dsl-plugin-/,
|
|
83
|
+
} as const
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in regex validation patterns (migrated from v1 lib/config/patterns/ to a single TypeScript file)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PatternConfig {
|
|
6
|
+
pattern: RegExp
|
|
7
|
+
min?: number
|
|
8
|
+
max?: number
|
|
9
|
+
key: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const phone: Record<string, PatternConfig> = {
|
|
13
|
+
cn: { pattern: /^1[3-9]\d{9}$/, min: 11, max: 11, key: 'pattern.phone.cn' },
|
|
14
|
+
us: { pattern: /^\d{10}$/, min: 10, max: 10, key: 'pattern.phone.us' },
|
|
15
|
+
uk: { pattern: /^(\+44\s?)?0?\d{10}$/, min: 10, max: 15, key: 'pattern.phone.uk' },
|
|
16
|
+
hk: { pattern: /^[5-9]\d{7}$/, min: 8, max: 8, key: 'pattern.phone.hk' },
|
|
17
|
+
tw: { pattern: /^09\d{8}$/, min: 10, max: 10, key: 'pattern.phone.tw' },
|
|
18
|
+
international: { pattern: /^\+[1-9]\d{1,14}$/, min: 8, max: 15, key: 'pattern.phone.international' },
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const idCard: Record<string, PatternConfig> = {
|
|
22
|
+
cn: {
|
|
23
|
+
pattern: /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
|
|
24
|
+
min: 18, max: 18, key: 'pattern.idCard.cn',
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const creditCard: Record<string, PatternConfig> = {
|
|
29
|
+
visa: { pattern: /^4[0-9]{12}(?:[0-9]{3})?$/, key: 'pattern.creditCard.visa' },
|
|
30
|
+
mastercard: { pattern: /^5[1-5][0-9]{14}$/, key: 'pattern.creditCard.mastercard' },
|
|
31
|
+
amex: { pattern: /^3[47][0-9]{13}$/, key: 'pattern.creditCard.amex' },
|
|
32
|
+
discover: { pattern: /^6(?:011|5[0-9]{2})[0-9]{12}$/, key: 'pattern.creditCard.discover' },
|
|
33
|
+
jcb: { pattern: /^(?:2131|1800|35\d{3})\d{11}$/, key: 'pattern.creditCard.jcb' },
|
|
34
|
+
unionpay: { pattern: /^62[0-9]{14,17}$/, key: 'pattern.creditCard.unionpay' },
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const licensePlate: Record<string, PatternConfig> = {
|
|
38
|
+
cn: {
|
|
39
|
+
pattern: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]$/,
|
|
40
|
+
key: 'pattern.licensePlate.cn',
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const postalCode: Record<string, PatternConfig> = {
|
|
45
|
+
cn: { pattern: /^[1-9]\d{5}$/, key: 'pattern.postalCode.cn' },
|
|
46
|
+
us: { pattern: /^\d{5}(-\d{4})?$/, key: 'pattern.postalCode.us' },
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const passport: Record<string, PatternConfig> = {
|
|
50
|
+
cn: {
|
|
51
|
+
pattern: /(^[EeKkGgDdHhMQqSs][0-9]{8}$)|(^(([Ee][a-fA-F])|([DdSPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))[0-9]{7}$)/,
|
|
52
|
+
key: 'pattern.passport.cn',
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const common: Record<string, PatternConfig> = {
|
|
57
|
+
domain: {
|
|
58
|
+
pattern: /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/i,
|
|
59
|
+
key: 'pattern.domain', min: 3, max: 253,
|
|
60
|
+
},
|
|
61
|
+
ip: {
|
|
62
|
+
// Composite IPv4 + IPv6 pattern (same as v1)
|
|
63
|
+
pattern:
|
|
64
|
+
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/,
|
|
65
|
+
key: 'pattern.ip',
|
|
66
|
+
},
|
|
67
|
+
base64: {
|
|
68
|
+
pattern: /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,
|
|
69
|
+
key: 'pattern.base64',
|
|
70
|
+
},
|
|
71
|
+
jwt: {
|
|
72
|
+
pattern: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,
|
|
73
|
+
key: 'pattern.jwt',
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const PATTERNS = { phone, idCard, creditCard, licensePlate, postalCode, passport, common }
|