reliant-type 1.0.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/LICENSE +21 -0
- package/README.md +1305 -0
- package/dist/cjs/constants/SECURITY_CONSTANTS.js +49 -0
- package/dist/cjs/constants/SECURITY_CONSTANTS.js.map +1 -0
- package/dist/cjs/constants/VALIDATION_CONSTANTS.js +103 -0
- package/dist/cjs/constants/VALIDATION_CONSTANTS.js.map +1 -0
- package/dist/cjs/core/schema/extensions/SmartInference.js +200 -0
- package/dist/cjs/core/schema/extensions/SmartInference.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/Docs.js +100 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/Docs.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/DocumentationGenerator.js +192 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/DocumentationGenerator.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/InteractiveDocumentationGenerator.js +174 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/InteractiveDocumentationGenerator.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/SchemaAnalyzer.js +54 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/SchemaAnalyzer.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/TypeScriptGenerator.js +50 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/TypeScriptGenerator.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/index.js +15 -0
- package/dist/cjs/core/schema/extensions/components/AutoDocumentation/index.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/ConditionalBuilder.js +70 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/ConditionalBuilder.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/ConditionalElse.js +40 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/ConditionalElse.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/ConditionalThen.js +19 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/ConditionalThen.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/MultiConditionalBuilder.js +20 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/MultiConditionalBuilder.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/MultiConditionalThen.js +49 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/MultiConditionalThen.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/index.js +98 -0
- package/dist/cjs/core/schema/extensions/components/ConditionalValidation/index.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/FormValidator.js +85 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/FormValidator.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/LiveValidator.js +133 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/LiveValidator.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/StreamValidator.js +351 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/StreamValidator.js.map +1 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/index.js +109 -0
- package/dist/cjs/core/schema/extensions/components/RealtimeValidation/index.js.map +1 -0
- package/dist/cjs/core/schema/extensions/index.js +61 -0
- package/dist/cjs/core/schema/extensions/index.js.map +1 -0
- package/dist/cjs/core/schema/extensions/mods/index.js +51 -0
- package/dist/cjs/core/schema/extensions/mods/index.js.map +1 -0
- package/dist/cjs/core/schema/extensions/mods/openapi-converter.js +227 -0
- package/dist/cjs/core/schema/extensions/mods/openapi-converter.js.map +1 -0
- package/dist/cjs/core/schema/extensions/mods/typescript-generator.js +287 -0
- package/dist/cjs/core/schema/extensions/mods/typescript-generator.js.map +1 -0
- package/dist/cjs/core/schema/extensions/mods/validation-engine.js +224 -0
- package/dist/cjs/core/schema/extensions/mods/validation-engine.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/Interface.js +277 -0
- package/dist/cjs/core/schema/mode/interfaces/Interface.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/InterfaceSchema.js +1431 -0
- package/dist/cjs/core/schema/mode/interfaces/InterfaceSchema.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/evaluator/ConditionalEvaluator.js +520 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/evaluator/ConditionalEvaluator.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/parser/ConditionalAST.js +624 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/parser/ConditionalAST.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/parser/ConditionalLexer.js +811 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/parser/ConditionalLexer.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/parser/ConditionalParser.js +599 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/parser/ConditionalParser.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/types/ConditionalTypes.js +89 -0
- package/dist/cjs/core/schema/mode/interfaces/conditional/types/ConditionalTypes.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/errors/ErrorHandler.js +356 -0
- package/dist/cjs/core/schema/mode/interfaces/errors/ErrorHandler.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/errors/types/errors.type.js +80 -0
- package/dist/cjs/core/schema/mode/interfaces/errors/types/errors.type.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js +778 -0
- package/dist/cjs/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/precompilation/SchemaPrecompiler.js +523 -0
- package/dist/cjs/core/schema/mode/interfaces/precompilation/SchemaPrecompiler.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/ConditionalTypes.js +681 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/ConditionalTypes.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/IDESupport.js +430 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/IDESupport.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/TypeInference.js +225 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/TypeInference.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/index.js +44 -0
- package/dist/cjs/core/schema/mode/interfaces/typescript/index.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/ConstraintParser.js +1134 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/ConstraintParser.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/TypeGuards.js +256 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/TypeGuards.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/TypeValidators.js +429 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/TypeValidators.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/UnionCache.js +404 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/UnionCache.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/ValidationHelpers.js +851 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/ValidationHelpers.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/passValidator.js +262 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/passValidator.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/securityValidator.js +887 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/securityValidator.js.map +1 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/urlValidation.js +191 -0
- package/dist/cjs/core/schema/mode/interfaces/validators/mods/urlValidation.js.map +1 -0
- package/dist/cjs/core/schema/optimization/ObjectValidationCache.js +462 -0
- package/dist/cjs/core/schema/optimization/ObjectValidationCache.js.map +1 -0
- package/dist/cjs/core/schema/optimization/PerformanceMonitor.js +773 -0
- package/dist/cjs/core/schema/optimization/PerformanceMonitor.js.map +1 -0
- package/dist/cjs/core/schema/optimization/SchemaCompiler.js +600 -0
- package/dist/cjs/core/schema/optimization/SchemaCompiler.js.map +1 -0
- package/dist/cjs/core/types/ValidatorTypes.js +70 -0
- package/dist/cjs/core/types/ValidatorTypes.js.map +1 -0
- package/dist/cjs/core/types/parser.type.js +12 -0
- package/dist/cjs/core/types/parser.type.js.map +1 -0
- package/dist/cjs/core/utils/Make.js +61 -0
- package/dist/cjs/core/utils/Make.js.map +1 -0
- package/dist/cjs/core/utils/Mod.js +1033 -0
- package/dist/cjs/core/utils/Mod.js.map +1 -0
- package/dist/cjs/core/utils/UrlArgs.js +102 -0
- package/dist/cjs/core/utils/UrlArgs.js.map +1 -0
- package/dist/cjs/core/utils/arrayToEnum.js +18 -0
- package/dist/cjs/core/utils/arrayToEnum.js.map +1 -0
- package/dist/cjs/core/utils/createUrlArgsEnumFArray.js +13 -0
- package/dist/cjs/core/utils/createUrlArgsEnumFArray.js.map +1 -0
- package/dist/cjs/core/utils/securityHelpers.js +215 -0
- package/dist/cjs/core/utils/securityHelpers.js.map +1 -0
- package/dist/cjs/core/utils/securityValidatorHelpers.js +65 -0
- package/dist/cjs/core/utils/securityValidatorHelpers.js.map +1 -0
- package/dist/cjs/index.js +31 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/esm/constants/SECURITY_CONSTANTS.js +47 -0
- package/dist/esm/constants/SECURITY_CONSTANTS.js.map +1 -0
- package/dist/esm/constants/VALIDATION_CONSTANTS.js +98 -0
- package/dist/esm/constants/VALIDATION_CONSTANTS.js.map +1 -0
- package/dist/esm/core/schema/extensions/SmartInference.js +197 -0
- package/dist/esm/core/schema/extensions/SmartInference.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/Docs.js +98 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/Docs.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/DocumentationGenerator.js +190 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/DocumentationGenerator.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/InteractiveDocumentationGenerator.js +172 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/InteractiveDocumentationGenerator.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/SchemaAnalyzer.js +52 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/SchemaAnalyzer.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/TypeScriptGenerator.js +48 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/TypeScriptGenerator.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/index.js +12 -0
- package/dist/esm/core/schema/extensions/components/AutoDocumentation/index.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/ConditionalBuilder.js +68 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/ConditionalBuilder.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/ConditionalElse.js +38 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/ConditionalElse.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/ConditionalThen.js +17 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/ConditionalThen.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/MultiConditionalBuilder.js +18 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/MultiConditionalBuilder.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/MultiConditionalThen.js +45 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/MultiConditionalThen.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/index.js +92 -0
- package/dist/esm/core/schema/extensions/components/ConditionalValidation/index.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/FormValidator.js +83 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/FormValidator.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/LiveValidator.js +131 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/LiveValidator.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/StreamValidator.js +349 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/StreamValidator.js.map +1 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/index.js +103 -0
- package/dist/esm/core/schema/extensions/components/RealtimeValidation/index.js.map +1 -0
- package/dist/esm/core/schema/extensions/index.js +53 -0
- package/dist/esm/core/schema/extensions/index.js.map +1 -0
- package/dist/esm/core/schema/extensions/mods/index.js +47 -0
- package/dist/esm/core/schema/extensions/mods/index.js.map +1 -0
- package/dist/esm/core/schema/extensions/mods/openapi-converter.js +225 -0
- package/dist/esm/core/schema/extensions/mods/openapi-converter.js.map +1 -0
- package/dist/esm/core/schema/extensions/mods/typescript-generator.js +284 -0
- package/dist/esm/core/schema/extensions/mods/typescript-generator.js.map +1 -0
- package/dist/esm/core/schema/extensions/mods/validation-engine.js +222 -0
- package/dist/esm/core/schema/extensions/mods/validation-engine.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/Interface.js +269 -0
- package/dist/esm/core/schema/mode/interfaces/Interface.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/InterfaceSchema.js +1429 -0
- package/dist/esm/core/schema/mode/interfaces/InterfaceSchema.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/evaluator/ConditionalEvaluator.js +518 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/evaluator/ConditionalEvaluator.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/parser/ConditionalAST.js +620 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/parser/ConditionalAST.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/parser/ConditionalLexer.js +809 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/parser/ConditionalLexer.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/parser/ConditionalParser.js +597 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/parser/ConditionalParser.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/types/ConditionalTypes.js +89 -0
- package/dist/esm/core/schema/mode/interfaces/conditional/types/ConditionalTypes.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/errors/ErrorHandler.js +354 -0
- package/dist/esm/core/schema/mode/interfaces/errors/ErrorHandler.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/errors/types/errors.type.js +80 -0
- package/dist/esm/core/schema/mode/interfaces/errors/types/errors.type.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js +776 -0
- package/dist/esm/core/schema/mode/interfaces/precompilation/FieldPrecompilers.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/precompilation/SchemaPrecompiler.js +521 -0
- package/dist/esm/core/schema/mode/interfaces/precompilation/SchemaPrecompiler.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/ConditionalTypes.js +681 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/ConditionalTypes.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/IDESupport.js +428 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/IDESupport.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/TypeInference.js +223 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/TypeInference.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/index.js +35 -0
- package/dist/esm/core/schema/mode/interfaces/typescript/index.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/ConstraintParser.js +1132 -0
- package/dist/esm/core/schema/mode/interfaces/validators/ConstraintParser.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/TypeGuards.js +254 -0
- package/dist/esm/core/schema/mode/interfaces/validators/TypeGuards.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/TypeValidators.js +427 -0
- package/dist/esm/core/schema/mode/interfaces/validators/TypeValidators.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/UnionCache.js +400 -0
- package/dist/esm/core/schema/mode/interfaces/validators/UnionCache.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/ValidationHelpers.js +849 -0
- package/dist/esm/core/schema/mode/interfaces/validators/ValidationHelpers.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/mods/passValidator.js +260 -0
- package/dist/esm/core/schema/mode/interfaces/validators/mods/passValidator.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/mods/securityValidator.js +881 -0
- package/dist/esm/core/schema/mode/interfaces/validators/mods/securityValidator.js.map +1 -0
- package/dist/esm/core/schema/mode/interfaces/validators/mods/urlValidation.js +189 -0
- package/dist/esm/core/schema/mode/interfaces/validators/mods/urlValidation.js.map +1 -0
- package/dist/esm/core/schema/optimization/ObjectValidationCache.js +460 -0
- package/dist/esm/core/schema/optimization/ObjectValidationCache.js.map +1 -0
- package/dist/esm/core/schema/optimization/PerformanceMonitor.js +771 -0
- package/dist/esm/core/schema/optimization/PerformanceMonitor.js.map +1 -0
- package/dist/esm/core/schema/optimization/SchemaCompiler.js +598 -0
- package/dist/esm/core/schema/optimization/SchemaCompiler.js.map +1 -0
- package/dist/esm/core/types/ValidatorTypes.js +65 -0
- package/dist/esm/core/types/ValidatorTypes.js.map +1 -0
- package/dist/esm/core/types/parser.type.js +12 -0
- package/dist/esm/core/types/parser.type.js.map +1 -0
- package/dist/esm/core/utils/Make.js +59 -0
- package/dist/esm/core/utils/Make.js.map +1 -0
- package/dist/esm/core/utils/Mod.js +1031 -0
- package/dist/esm/core/utils/Mod.js.map +1 -0
- package/dist/esm/core/utils/UrlArgs.js +98 -0
- package/dist/esm/core/utils/UrlArgs.js.map +1 -0
- package/dist/esm/core/utils/arrayToEnum.js +16 -0
- package/dist/esm/core/utils/arrayToEnum.js.map +1 -0
- package/dist/esm/core/utils/createUrlArgsEnumFArray.js +11 -0
- package/dist/esm/core/utils/createUrlArgsEnumFArray.js.map +1 -0
- package/dist/esm/core/utils/securityHelpers.js +207 -0
- package/dist/esm/core/utils/securityHelpers.js.map +1 -0
- package/dist/esm/core/utils/securityValidatorHelpers.js +62 -0
- package/dist/esm/core/utils/securityValidatorHelpers.js.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/schema.d.ts +2595 -0
- package/docs/ALL_TYPES.md +120 -0
- package/docs/API-STABILITY.md +336 -0
- package/docs/CONDITIONAL-VALIDATION.md +637 -0
- package/docs/EXAMPLES.md +876 -0
- package/docs/FIELD-TYPES.md +829 -0
- package/docs/GETTING-STARTED.md +394 -0
- package/docs/LIVE-UTILITY.md +1137 -0
- package/docs/QUICK-REFERENCE.md +346 -0
- package/docs/README.md +205 -0
- package/docs/VSCODE-EXTENSION.md +458 -0
- package/package.json +219 -0
- package/src/bench/BENCHMARK-RESULTS.md +211 -0
- package/src/bench/benchmark-results.json +148 -0
- package/src/bench/performance-comparison.ts +218 -0
- package/src/bench/precompilation-benchmark.ts +218 -0
- package/src/constants/SECURITY_CONSTANTS.ts +44 -0
- package/src/constants/VALIDATION_CONSTANTS.ts +176 -0
- package/src/core/README.md +395 -0
- package/src/core/compiler/SchemaTransformer.ts +279 -0
- package/src/core/compiler/TypeAnalyzer.ts +378 -0
- package/src/core/compiler/TypeScriptCompilerIntegration.ts +220 -0
- package/src/core/compiler/TypeToSchemaConverter.ts +288 -0
- package/src/core/index.ts +70 -0
- package/src/core/schema/extensions/AutoDocumentation.ts +572 -0
- package/src/core/schema/extensions/ConditionalValidation.ts +330 -0
- package/src/core/schema/extensions/README.md +171 -0
- package/src/core/schema/extensions/RealtimeValidation.ts +656 -0
- package/src/core/schema/extensions/SmartInference.ts +224 -0
- package/src/core/schema/extensions/components/AutoDocumentation/Docs.ts +98 -0
- package/src/core/schema/extensions/components/AutoDocumentation/DocumentationGenerator.ts +201 -0
- package/src/core/schema/extensions/components/AutoDocumentation/InteractiveDocumentationGenerator.ts +176 -0
- package/src/core/schema/extensions/components/AutoDocumentation/OpenAPIGenerator.ts +175 -0
- package/src/core/schema/extensions/components/AutoDocumentation/SchemaAnalyzer.ts +49 -0
- package/src/core/schema/extensions/components/AutoDocumentation/TypeScriptGenerator.ts +54 -0
- package/src/core/schema/extensions/components/AutoDocumentation/index.ts +17 -0
- package/src/core/schema/extensions/components/ConditionalValidation/ConditionalBuilder.ts +101 -0
- package/src/core/schema/extensions/components/ConditionalValidation/ConditionalElse.ts +65 -0
- package/src/core/schema/extensions/components/ConditionalValidation/ConditionalThen.ts +33 -0
- package/src/core/schema/extensions/components/ConditionalValidation/Extend.ts +75 -0
- package/src/core/schema/extensions/components/ConditionalValidation/MultiConditionalBuilder.ts +16 -0
- package/src/core/schema/extensions/components/ConditionalValidation/MultiConditionalThen.ts +50 -0
- package/src/core/schema/extensions/components/ConditionalValidation/index.ts +104 -0
- package/src/core/schema/extensions/components/RealtimeValidation/FormValidator.ts +88 -0
- package/src/core/schema/extensions/components/RealtimeValidation/LiveValidator.ts +171 -0
- package/src/core/schema/extensions/components/RealtimeValidation/StreamValidator.ts +397 -0
- package/src/core/schema/extensions/components/RealtimeValidation/index.ts +114 -0
- package/src/core/schema/extensions/index.ts +76 -0
- package/src/core/schema/extensions/mods/index.ts +131 -0
- package/src/core/schema/extensions/mods/openapi-converter.ts +338 -0
- package/src/core/schema/extensions/mods/typescript-generator.ts +379 -0
- package/src/core/schema/extensions/mods/validation-engine.ts +295 -0
- package/src/core/schema/mode/interfaces/Interface.ts +364 -0
- package/src/core/schema/mode/interfaces/InterfaceSchema.ts +1838 -0
- package/src/core/schema/mode/interfaces/README.md +278 -0
- package/src/core/schema/mode/interfaces/conditional/evaluator/ConditionalEvaluator.ts +657 -0
- package/src/core/schema/mode/interfaces/conditional/parser/ConditionalAST.ts +826 -0
- package/src/core/schema/mode/interfaces/conditional/parser/ConditionalLexer.ts +992 -0
- package/src/core/schema/mode/interfaces/conditional/parser/ConditionalParser.ts +803 -0
- package/src/core/schema/mode/interfaces/conditional/parser/readme.md +406 -0
- package/src/core/schema/mode/interfaces/conditional/types/ConditionalTypes.ts +273 -0
- package/src/core/schema/mode/interfaces/errors/ErrorHandler.ts +624 -0
- package/src/core/schema/mode/interfaces/errors/types/errors.type.ts +102 -0
- package/src/core/schema/mode/interfaces/precompilation/FieldPrecompilers.ts +962 -0
- package/src/core/schema/mode/interfaces/precompilation/SchemaPrecompiler.ts +667 -0
- package/src/core/schema/mode/interfaces/typescript/ConditionalTypes.ts +1534 -0
- package/src/core/schema/mode/interfaces/typescript/IDESupport.ts +534 -0
- package/src/core/schema/mode/interfaces/typescript/TypeInference.ts +737 -0
- package/src/core/schema/mode/interfaces/typescript/index.ts +92 -0
- package/src/core/schema/mode/interfaces/validators/ConstraintParser.ts +1438 -0
- package/src/core/schema/mode/interfaces/validators/EnhancedErrorReporting.ts +227 -0
- package/src/core/schema/mode/interfaces/validators/TypeGuards.ts +288 -0
- package/src/core/schema/mode/interfaces/validators/TypeValidators.ts +660 -0
- package/src/core/schema/mode/interfaces/validators/UnionCache.ts +508 -0
- package/src/core/schema/mode/interfaces/validators/ValidationHelpers.ts +1257 -0
- package/src/core/schema/mode/interfaces/validators/index.ts +21 -0
- package/src/core/schema/mode/interfaces/validators/mods/passValidator.ts +424 -0
- package/src/core/schema/mode/interfaces/validators/mods/securityValidator.ts +1634 -0
- package/src/core/schema/mode/interfaces/validators/mods/urlValidation.ts +333 -0
- package/src/core/schema/optimization/ObjectValidationCache.ts +560 -0
- package/src/core/schema/optimization/PerformanceInitializer.ts +188 -0
- package/src/core/schema/optimization/PerformanceMonitor.ts +898 -0
- package/src/core/schema/optimization/SchemaCompiler.ts +730 -0
- package/src/core/testing/TestDataGenerator.ts +590 -0
- package/src/core/types/SchemaValidator.type.ts +210 -0
- package/src/core/types/ValidatorTypes.ts +93 -0
- package/src/core/types/extension.type.ts +109 -0
- package/src/core/types/objValidationCache.ts +17 -0
- package/src/core/types/parser.type.ts +15 -0
- package/src/core/types/perfoMonitor.ts +37 -0
- package/src/core/types/scompiler.ts +22 -0
- package/src/core/types/securityValidator.type.ts +10 -0
- package/src/core/types/types.ts +154 -0
- package/src/core/utils/Make.ts +97 -0
- package/src/core/utils/Mod.ts +1168 -0
- package/src/core/utils/UrlArgs.ts +124 -0
- package/src/core/utils/arrayToEnum.ts +89 -0
- package/src/core/utils/createUrlArgsEnumFArray.ts +11 -0
- package/src/core/utils/securityHelpers.ts +341 -0
- package/src/core/utils/securityValidatorHelpers.ts +76 -0
- package/src/index.ts +124 -0
|
@@ -0,0 +1,1534 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Conditional Types and Operators System
|
|
3
|
+
*
|
|
4
|
+
* A robust, maintainable, and extensible TypeScript conditional types system
|
|
5
|
+
* with improved error handling, better organization, and type safety.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// CORE TYPE UTILITIES - Foundation layer
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Essential utility types for type-level programming
|
|
14
|
+
*/
|
|
15
|
+
export namespace TypeUtils {
|
|
16
|
+
export type IsNever<T> = [T] extends [never] ? true : false;
|
|
17
|
+
export type IsUnknown<T> =
|
|
18
|
+
IsNever<T> extends false
|
|
19
|
+
? [unknown] extends [T]
|
|
20
|
+
? [T] extends [unknown]
|
|
21
|
+
? true
|
|
22
|
+
: false
|
|
23
|
+
: false
|
|
24
|
+
: false;
|
|
25
|
+
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
26
|
+
export type IsUndefined<T> = [T] extends [undefined] ? true : false;
|
|
27
|
+
export type IsNull<T> = [T] extends [null] ? true : false;
|
|
28
|
+
export type IsNullish<T> = IsNull<T> extends true ? true : IsUndefined<T>;
|
|
29
|
+
|
|
30
|
+
// String utilities
|
|
31
|
+
export type Trim<T extends string> = T extends ` ${infer U}`
|
|
32
|
+
? Trim<U>
|
|
33
|
+
: T extends `${infer U} `
|
|
34
|
+
? Trim<U>
|
|
35
|
+
: T;
|
|
36
|
+
|
|
37
|
+
export type Split<
|
|
38
|
+
S extends string,
|
|
39
|
+
D extends string,
|
|
40
|
+
> = S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] : [S];
|
|
41
|
+
|
|
42
|
+
export type Join<
|
|
43
|
+
T extends readonly string[],
|
|
44
|
+
D extends string,
|
|
45
|
+
> = T extends readonly [infer F, ...infer R]
|
|
46
|
+
? F extends string
|
|
47
|
+
? R extends readonly string[]
|
|
48
|
+
? R["length"] extends 0
|
|
49
|
+
? F
|
|
50
|
+
: `${F}${D}${Join<R, D>}`
|
|
51
|
+
: never
|
|
52
|
+
: never
|
|
53
|
+
: "";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// OPERATOR SYSTEM - with validation and metadata
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Comprehensive operator definitions with strict typing
|
|
62
|
+
*/
|
|
63
|
+
export namespace Operators {
|
|
64
|
+
// All supported operators with semantic grouping
|
|
65
|
+
export type ConditionalOperator =
|
|
66
|
+
| ExistenceOperator
|
|
67
|
+
| StateOperator
|
|
68
|
+
| InclusionOperator
|
|
69
|
+
| RegexOperator
|
|
70
|
+
| StringOperator
|
|
71
|
+
| ComparisonOperator;
|
|
72
|
+
|
|
73
|
+
export type ExistenceOperator = "exists" | "!exists";
|
|
74
|
+
export type StateOperator = "empty" | "!empty" | "null" | "!null";
|
|
75
|
+
export type InclusionOperator = "in" | "!in";
|
|
76
|
+
export type RegexOperator = "~" | "!~";
|
|
77
|
+
export type StringOperator =
|
|
78
|
+
| "contains"
|
|
79
|
+
| "!contains"
|
|
80
|
+
| "startsWith"
|
|
81
|
+
| "endsWith";
|
|
82
|
+
export type ComparisonOperator = "=" | "!=" | ">" | ">=" | "<" | "<=";
|
|
83
|
+
|
|
84
|
+
// operator metadata with validation rules
|
|
85
|
+
export interface OperatorMetadata {
|
|
86
|
+
readonly precedence: number;
|
|
87
|
+
readonly requiresValue: boolean;
|
|
88
|
+
readonly typeSupport: readonly TypeSupport[];
|
|
89
|
+
readonly description: string;
|
|
90
|
+
readonly examples: readonly string[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type TypeSupport =
|
|
94
|
+
| "string"
|
|
95
|
+
| "number"
|
|
96
|
+
| "boolean"
|
|
97
|
+
| "array"
|
|
98
|
+
| "object"
|
|
99
|
+
| "date";
|
|
100
|
+
|
|
101
|
+
// Comprehensive operator configuration
|
|
102
|
+
export const OPERATOR_CONFIG: Readonly<
|
|
103
|
+
Record<ConditionalOperator, OperatorMetadata>
|
|
104
|
+
> = {
|
|
105
|
+
// Existence operators (highest precedence)
|
|
106
|
+
"!exists": {
|
|
107
|
+
precedence: 100,
|
|
108
|
+
requiresValue: false,
|
|
109
|
+
typeSupport: ["string", "number", "boolean", "array", "object", "date"],
|
|
110
|
+
description: "Field does not exist or is undefined",
|
|
111
|
+
examples: ["name!exists", "user.email!exists"],
|
|
112
|
+
},
|
|
113
|
+
exists: {
|
|
114
|
+
precedence: 99,
|
|
115
|
+
requiresValue: false,
|
|
116
|
+
typeSupport: ["string", "number", "boolean", "array", "object", "date"],
|
|
117
|
+
description: "Field exists and is not undefined",
|
|
118
|
+
examples: ["name exists", "user.email exists"],
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
// State operators
|
|
122
|
+
"!empty": {
|
|
123
|
+
precedence: 98,
|
|
124
|
+
requiresValue: false,
|
|
125
|
+
typeSupport: ["string", "array", "object"],
|
|
126
|
+
description: "Field is not empty (non-zero length)",
|
|
127
|
+
examples: ["name!empty", "items!empty"],
|
|
128
|
+
},
|
|
129
|
+
empty: {
|
|
130
|
+
precedence: 97,
|
|
131
|
+
requiresValue: false,
|
|
132
|
+
typeSupport: ["string", "array", "object"],
|
|
133
|
+
description: "Field is empty (zero length)",
|
|
134
|
+
examples: ["name empty", "items empty"],
|
|
135
|
+
},
|
|
136
|
+
"!null": {
|
|
137
|
+
precedence: 96,
|
|
138
|
+
requiresValue: false,
|
|
139
|
+
typeSupport: ["string", "number", "boolean", "array", "object", "date"],
|
|
140
|
+
description: "Field is not null",
|
|
141
|
+
examples: ["value!null", "user.id!null"],
|
|
142
|
+
},
|
|
143
|
+
null: {
|
|
144
|
+
precedence: 95,
|
|
145
|
+
requiresValue: false,
|
|
146
|
+
typeSupport: ["string", "number", "boolean", "array", "object", "date"],
|
|
147
|
+
description: "Field is null",
|
|
148
|
+
examples: ["value null", "user.id null"],
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
// Inclusion operators
|
|
152
|
+
"!in": {
|
|
153
|
+
precedence: 94,
|
|
154
|
+
requiresValue: true,
|
|
155
|
+
typeSupport: ["string", "number", "boolean"],
|
|
156
|
+
description: "Field value is not in the provided list",
|
|
157
|
+
examples: ["status!in(active,pending)", "priority!in(1,2,3)"],
|
|
158
|
+
},
|
|
159
|
+
in: {
|
|
160
|
+
precedence: 93,
|
|
161
|
+
requiresValue: true,
|
|
162
|
+
typeSupport: ["string", "number", "boolean"],
|
|
163
|
+
description: "Field value is in the provided list",
|
|
164
|
+
examples: ["status in(active,pending)", "priority in(1,2,3)"],
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
// Regex operators
|
|
168
|
+
"!~": {
|
|
169
|
+
precedence: 92,
|
|
170
|
+
requiresValue: true,
|
|
171
|
+
typeSupport: ["string"],
|
|
172
|
+
description: "Field value does not match the regex pattern",
|
|
173
|
+
examples: ["email!~^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"],
|
|
174
|
+
},
|
|
175
|
+
"~": {
|
|
176
|
+
precedence: 91,
|
|
177
|
+
requiresValue: true,
|
|
178
|
+
typeSupport: ["string"],
|
|
179
|
+
description: "Field value matches the regex pattern",
|
|
180
|
+
examples: ["email~^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"],
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
// String operators
|
|
184
|
+
"!contains": {
|
|
185
|
+
precedence: 90,
|
|
186
|
+
requiresValue: true,
|
|
187
|
+
typeSupport: ["string"],
|
|
188
|
+
description: "Field value does not contain the substring",
|
|
189
|
+
examples: ["name!contains John", "description!contains urgent"],
|
|
190
|
+
},
|
|
191
|
+
contains: {
|
|
192
|
+
precedence: 89,
|
|
193
|
+
requiresValue: true,
|
|
194
|
+
typeSupport: ["string"],
|
|
195
|
+
description: "Field value contains the substring",
|
|
196
|
+
examples: ["name contains John", "description contains urgent"],
|
|
197
|
+
},
|
|
198
|
+
endsWith: {
|
|
199
|
+
precedence: 88,
|
|
200
|
+
requiresValue: true,
|
|
201
|
+
typeSupport: ["string"],
|
|
202
|
+
description: "Field value ends with the substring",
|
|
203
|
+
examples: ["filename endsWith .pdf", "email endsWith @company.com"],
|
|
204
|
+
},
|
|
205
|
+
startsWith: {
|
|
206
|
+
precedence: 87,
|
|
207
|
+
requiresValue: true,
|
|
208
|
+
typeSupport: ["string"],
|
|
209
|
+
description: "Field value starts with the substring",
|
|
210
|
+
examples: ["name startsWith Mr.", "path startsWith /api/"],
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// Comparison operators (lowest precedence)
|
|
214
|
+
"!=": {
|
|
215
|
+
precedence: 86,
|
|
216
|
+
requiresValue: true,
|
|
217
|
+
typeSupport: ["string", "number", "boolean", "date"],
|
|
218
|
+
description: "Field value is not equal to the provided value",
|
|
219
|
+
examples: ["status!=active", "count!=0", "isEnabled!=true"],
|
|
220
|
+
},
|
|
221
|
+
">=": {
|
|
222
|
+
precedence: 85,
|
|
223
|
+
requiresValue: true,
|
|
224
|
+
typeSupport: ["number", "date"],
|
|
225
|
+
description: "Field value is greater than or equal to the provided value",
|
|
226
|
+
examples: ["age>=18", "score>=80"],
|
|
227
|
+
},
|
|
228
|
+
"<=": {
|
|
229
|
+
precedence: 84,
|
|
230
|
+
requiresValue: true,
|
|
231
|
+
typeSupport: ["number", "date"],
|
|
232
|
+
description: "Field value is less than or equal to the provided value",
|
|
233
|
+
examples: ["age<=65", "score<=100"],
|
|
234
|
+
},
|
|
235
|
+
">": {
|
|
236
|
+
precedence: 83,
|
|
237
|
+
requiresValue: true,
|
|
238
|
+
typeSupport: ["number", "date"],
|
|
239
|
+
description: "Field value is greater than the provided value",
|
|
240
|
+
examples: ["age>18", "score>80"],
|
|
241
|
+
},
|
|
242
|
+
"<": {
|
|
243
|
+
precedence: 82,
|
|
244
|
+
requiresValue: true,
|
|
245
|
+
typeSupport: ["number", "date"],
|
|
246
|
+
description: "Field value is less than the provided value",
|
|
247
|
+
examples: ["age<65", "score<100"],
|
|
248
|
+
},
|
|
249
|
+
"=": {
|
|
250
|
+
precedence: 81,
|
|
251
|
+
requiresValue: true,
|
|
252
|
+
typeSupport: ["string", "number", "boolean", "date"],
|
|
253
|
+
description: "Field value is equal to the provided value",
|
|
254
|
+
examples: ["status=active", "count=0", "isEnabled=true"],
|
|
255
|
+
},
|
|
256
|
+
} as const;
|
|
257
|
+
|
|
258
|
+
// Utility functions for operator validation
|
|
259
|
+
export function isValidOperator(op: string): op is ConditionalOperator {
|
|
260
|
+
return op in OPERATOR_CONFIG;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function getOperatorsByPrecedence(): ConditionalOperator[] {
|
|
264
|
+
return Object.entries(OPERATOR_CONFIG)
|
|
265
|
+
.sort(([, a], [, b]) => b.precedence - a.precedence)
|
|
266
|
+
.map(([op]) => op as ConditionalOperator);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function validateOperatorForType(
|
|
270
|
+
operator: ConditionalOperator,
|
|
271
|
+
type: TypeSupport
|
|
272
|
+
): boolean {
|
|
273
|
+
return OPERATOR_CONFIG[operator].typeSupport.includes(type);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ============================================================================
|
|
278
|
+
// CONDITION PARSING - with better error handling
|
|
279
|
+
// ============================================================================
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Advanced condition parsing with comprehensive error handling
|
|
283
|
+
*/
|
|
284
|
+
export namespace ConditionParser {
|
|
285
|
+
export interface ParsedCondition<
|
|
286
|
+
TField extends string = string,
|
|
287
|
+
TOperator extends
|
|
288
|
+
Operators.ConditionalOperator = Operators.ConditionalOperator,
|
|
289
|
+
TValue extends string = string,
|
|
290
|
+
> {
|
|
291
|
+
readonly field: TField;
|
|
292
|
+
readonly operator: TOperator;
|
|
293
|
+
readonly value: TValue;
|
|
294
|
+
readonly isValid: boolean;
|
|
295
|
+
readonly error?: string;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export type ParseResult<T extends string> =
|
|
299
|
+
ParseConditionPattern<T> extends infer R
|
|
300
|
+
? R extends ParsedCondition
|
|
301
|
+
? R
|
|
302
|
+
: ParsedCondition<never, never, never> & {
|
|
303
|
+
isValid: false;
|
|
304
|
+
error: "Invalid condition format";
|
|
305
|
+
}
|
|
306
|
+
: ParsedCondition<never, never, never> & {
|
|
307
|
+
isValid: false;
|
|
308
|
+
error: "Parse failed";
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// parsing with all operators in precedence order
|
|
312
|
+
export type ParseConditionPattern<T extends string> =
|
|
313
|
+
T extends `${infer Field}!exists`
|
|
314
|
+
? ParsedCondition<Field, "!exists", "">
|
|
315
|
+
: T extends `${infer Field}exists`
|
|
316
|
+
? ParsedCondition<Field, "exists", "">
|
|
317
|
+
: T extends `${infer Field}!empty`
|
|
318
|
+
? ParsedCondition<Field, "!empty", "">
|
|
319
|
+
: T extends `${infer Field}empty`
|
|
320
|
+
? ParsedCondition<Field, "empty", "">
|
|
321
|
+
: T extends `${infer Field}!null`
|
|
322
|
+
? ParsedCondition<Field, "!null", "">
|
|
323
|
+
: T extends `${infer Field}null`
|
|
324
|
+
? ParsedCondition<Field, "null", "">
|
|
325
|
+
: T extends `${infer Field}!in${infer Value}`
|
|
326
|
+
? ParsedCondition<Field, "!in", Value>
|
|
327
|
+
: T extends `${infer Field}in${infer Value}`
|
|
328
|
+
? ParsedCondition<Field, "in", Value>
|
|
329
|
+
: T extends `${infer Field}!~${infer Value}`
|
|
330
|
+
? ParsedCondition<Field, "!~", Value>
|
|
331
|
+
: T extends `${infer Field}~${infer Value}`
|
|
332
|
+
? ParsedCondition<Field, "~", Value>
|
|
333
|
+
: T extends `${infer Field}!contains${infer Value}`
|
|
334
|
+
? ParsedCondition<Field, "!contains", Value>
|
|
335
|
+
: T extends `${infer Field}contains${infer Value}`
|
|
336
|
+
? ParsedCondition<Field, "contains", Value>
|
|
337
|
+
: T extends `${infer Field}endsWith${infer Value}`
|
|
338
|
+
? ParsedCondition<Field, "endsWith", Value>
|
|
339
|
+
: T extends `${infer Field}startsWith${infer Value}`
|
|
340
|
+
? ParsedCondition<Field, "startsWith", Value>
|
|
341
|
+
: T extends `${infer Field}!=${infer Value}`
|
|
342
|
+
? ParsedCondition<Field, "!=", Value>
|
|
343
|
+
: T extends `${infer Field}>=${infer Value}`
|
|
344
|
+
? ParsedCondition<Field, ">=", Value>
|
|
345
|
+
: T extends `${infer Field}<=${infer Value}`
|
|
346
|
+
? ParsedCondition<Field, "<=", Value>
|
|
347
|
+
: T extends `${infer Field}>${infer Value}`
|
|
348
|
+
? ParsedCondition<Field, ">", Value>
|
|
349
|
+
: T extends `${infer Field}<${infer Value}`
|
|
350
|
+
? ParsedCondition<Field, "<", Value>
|
|
351
|
+
: T extends `${infer Field}=${infer Value}`
|
|
352
|
+
? ParsedCondition<Field, "=", Value>
|
|
353
|
+
: ParsedCondition<
|
|
354
|
+
never,
|
|
355
|
+
never,
|
|
356
|
+
never
|
|
357
|
+
> & {
|
|
358
|
+
isValid: false;
|
|
359
|
+
error: "No matching operator pattern found";
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ============================================================================
|
|
364
|
+
// SCHEMA UTILITIES - type extraction and validation
|
|
365
|
+
// ============================================================================
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Advanced schema type utilities with better path handling
|
|
369
|
+
*/
|
|
370
|
+
export namespace SchemaUtils {
|
|
371
|
+
// field path extraction with support for nested objects and arrays
|
|
372
|
+
export type FieldPaths<T, MaxDepth extends number = 5> = MaxDepth extends 0
|
|
373
|
+
? never
|
|
374
|
+
: T extends ReadonlyArray<infer U>
|
|
375
|
+
? `${number}` | `${number}.${FieldPaths<U, Prev<MaxDepth>>}`
|
|
376
|
+
: T extends object
|
|
377
|
+
? {
|
|
378
|
+
[K in keyof T]-?: K extends string | number
|
|
379
|
+
? T[K] extends object
|
|
380
|
+
? K | `${K}.${FieldPaths<T[K], Prev<MaxDepth>>}`
|
|
381
|
+
: K
|
|
382
|
+
: never;
|
|
383
|
+
}[keyof T]
|
|
384
|
+
: never;
|
|
385
|
+
|
|
386
|
+
type Prev<T extends number> = T extends 0
|
|
387
|
+
? 0
|
|
388
|
+
: T extends 1
|
|
389
|
+
? 0
|
|
390
|
+
: T extends 2
|
|
391
|
+
? 1
|
|
392
|
+
: T extends 3
|
|
393
|
+
? 2
|
|
394
|
+
: T extends 4
|
|
395
|
+
? 3
|
|
396
|
+
: T extends 5
|
|
397
|
+
? 4
|
|
398
|
+
: number;
|
|
399
|
+
|
|
400
|
+
// value extraction with better error handling
|
|
401
|
+
export type GetValueByPath<T, P extends string> = P extends keyof T
|
|
402
|
+
? T[P]
|
|
403
|
+
: P extends `${infer K}.${infer Rest}`
|
|
404
|
+
? K extends keyof T
|
|
405
|
+
? GetValueByPath<T[K], Rest>
|
|
406
|
+
: K extends `${number}`
|
|
407
|
+
? T extends ReadonlyArray<infer U>
|
|
408
|
+
? GetValueByPath<U, Rest>
|
|
409
|
+
: never
|
|
410
|
+
: never
|
|
411
|
+
: P extends `${number}`
|
|
412
|
+
? T extends ReadonlyArray<infer U>
|
|
413
|
+
? U
|
|
414
|
+
: never
|
|
415
|
+
: never;
|
|
416
|
+
|
|
417
|
+
// type extraction with better handling of complex types
|
|
418
|
+
export type ExtractFieldType<T> = T extends string
|
|
419
|
+
? T
|
|
420
|
+
: T extends { type: infer U }
|
|
421
|
+
? U extends string
|
|
422
|
+
? U
|
|
423
|
+
: string
|
|
424
|
+
: T extends { const: infer C }
|
|
425
|
+
? C extends string | number | boolean
|
|
426
|
+
? `=${C}`
|
|
427
|
+
: string
|
|
428
|
+
: T extends ReadonlyArray<infer U>
|
|
429
|
+
? `${ExtractFieldType<U>}[]`
|
|
430
|
+
: T extends Date
|
|
431
|
+
? "date"
|
|
432
|
+
: T extends number
|
|
433
|
+
? "number"
|
|
434
|
+
: T extends boolean
|
|
435
|
+
? "boolean"
|
|
436
|
+
: T extends object
|
|
437
|
+
? "object"
|
|
438
|
+
: "string";
|
|
439
|
+
|
|
440
|
+
// schema type resolution
|
|
441
|
+
export type ResolveSchemaType<T extends string> = T extends "string"
|
|
442
|
+
? string
|
|
443
|
+
: T extends "number"
|
|
444
|
+
? number
|
|
445
|
+
: T extends "boolean"
|
|
446
|
+
? boolean
|
|
447
|
+
: T extends "date"
|
|
448
|
+
? Date
|
|
449
|
+
: T extends "object"
|
|
450
|
+
? object
|
|
451
|
+
: T extends `${infer U}[]`
|
|
452
|
+
? Array<ResolveSchemaType<U>>
|
|
453
|
+
: T extends `${infer U}?`
|
|
454
|
+
? ResolveSchemaType<U> | undefined
|
|
455
|
+
: T extends `=${infer Value}`
|
|
456
|
+
? Value extends "true"
|
|
457
|
+
? true
|
|
458
|
+
: Value extends "false"
|
|
459
|
+
? false
|
|
460
|
+
: Value extends `${number}`
|
|
461
|
+
? number
|
|
462
|
+
: Value
|
|
463
|
+
: any;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// ============================================================================
|
|
467
|
+
// CONDITIONAL RESOLUTION - with better error handling and validation
|
|
468
|
+
// ============================================================================
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Robust conditional type resolution system
|
|
472
|
+
*/
|
|
473
|
+
export namespace ConditionalResolver {
|
|
474
|
+
// conditional syntax parsers
|
|
475
|
+
export type ParseRevolutionarySyntax<T extends string> =
|
|
476
|
+
T extends `when ${infer Condition} *? ${infer ThenType} : ${infer ElseType}`
|
|
477
|
+
? {
|
|
478
|
+
condition: TypeUtils.Trim<Condition>;
|
|
479
|
+
thenType: TypeUtils.Trim<ThenType>;
|
|
480
|
+
elseType: TypeUtils.Trim<ElseType>;
|
|
481
|
+
syntax: "revolutionary";
|
|
482
|
+
}
|
|
483
|
+
: never;
|
|
484
|
+
|
|
485
|
+
export type ParseParenthesesSyntax<T extends string> =
|
|
486
|
+
T extends `when(${infer Condition}) then(${infer ThenType}) else(${infer ElseType})`
|
|
487
|
+
? {
|
|
488
|
+
condition: TypeUtils.Trim<Condition>;
|
|
489
|
+
thenType: TypeUtils.Trim<ThenType>;
|
|
490
|
+
elseType: TypeUtils.Trim<ElseType>;
|
|
491
|
+
syntax: "parentheses";
|
|
492
|
+
}
|
|
493
|
+
: never;
|
|
494
|
+
|
|
495
|
+
export type ParseLegacySyntax<T extends string> =
|
|
496
|
+
T extends `when:${infer Condition}:${infer ThenType}:${infer ElseType}`
|
|
497
|
+
? {
|
|
498
|
+
condition: TypeUtils.Trim<Condition>;
|
|
499
|
+
thenType: TypeUtils.Trim<ThenType>;
|
|
500
|
+
elseType: TypeUtils.Trim<ElseType>;
|
|
501
|
+
syntax: "legacy";
|
|
502
|
+
}
|
|
503
|
+
: never;
|
|
504
|
+
|
|
505
|
+
// conditional type resolution with validation
|
|
506
|
+
export type ResolveConditionalType<
|
|
507
|
+
TCondition extends string,
|
|
508
|
+
TThenType extends string,
|
|
509
|
+
TElseType extends string,
|
|
510
|
+
TSchema extends Record<string, any>,
|
|
511
|
+
> =
|
|
512
|
+
ConditionParser.ParseConditionPattern<TCondition> extends ConditionParser.ParsedCondition<
|
|
513
|
+
infer TField extends string,
|
|
514
|
+
infer TOperator extends Operators.ConditionalOperator,
|
|
515
|
+
infer TValue extends string
|
|
516
|
+
>
|
|
517
|
+
? TField extends SchemaUtils.FieldPaths<TSchema>
|
|
518
|
+
? ResolveOperatorResult<
|
|
519
|
+
TOperator,
|
|
520
|
+
SchemaUtils.GetValueByPath<TSchema, TField>,
|
|
521
|
+
TValue,
|
|
522
|
+
TThenType,
|
|
523
|
+
TElseType
|
|
524
|
+
>
|
|
525
|
+
:
|
|
526
|
+
| SchemaUtils.ResolveSchemaType<TThenType>
|
|
527
|
+
| SchemaUtils.ResolveSchemaType<TElseType>
|
|
528
|
+
:
|
|
529
|
+
| SchemaUtils.ResolveSchemaType<TThenType>
|
|
530
|
+
| SchemaUtils.ResolveSchemaType<TElseType>;
|
|
531
|
+
|
|
532
|
+
// operator result resolution
|
|
533
|
+
type ResolveOperatorResult<
|
|
534
|
+
TOperator extends Operators.ConditionalOperator,
|
|
535
|
+
TFieldType,
|
|
536
|
+
TValue extends string,
|
|
537
|
+
TThenType extends string,
|
|
538
|
+
TElseType extends string,
|
|
539
|
+
> = TOperator extends "=" | "!="
|
|
540
|
+
? SchemaUtils.ExtractFieldType<TFieldType> extends string
|
|
541
|
+
? EvaluateCondition<
|
|
542
|
+
TOperator,
|
|
543
|
+
SchemaUtils.ExtractFieldType<TFieldType>,
|
|
544
|
+
TValue
|
|
545
|
+
> extends true
|
|
546
|
+
? SchemaUtils.ResolveSchemaType<TThenType>
|
|
547
|
+
: EvaluateCondition<
|
|
548
|
+
TOperator,
|
|
549
|
+
SchemaUtils.ExtractFieldType<TFieldType>,
|
|
550
|
+
TValue
|
|
551
|
+
> extends false
|
|
552
|
+
? SchemaUtils.ResolveSchemaType<TElseType>
|
|
553
|
+
:
|
|
554
|
+
| SchemaUtils.ResolveSchemaType<TThenType>
|
|
555
|
+
| SchemaUtils.ResolveSchemaType<TElseType>
|
|
556
|
+
:
|
|
557
|
+
| SchemaUtils.ResolveSchemaType<TThenType>
|
|
558
|
+
| SchemaUtils.ResolveSchemaType<TElseType>
|
|
559
|
+
:
|
|
560
|
+
| SchemaUtils.ResolveSchemaType<TThenType>
|
|
561
|
+
| SchemaUtils.ResolveSchemaType<TElseType>;
|
|
562
|
+
|
|
563
|
+
// condition evaluation
|
|
564
|
+
export type EvaluateCondition<
|
|
565
|
+
TOperator extends Operators.ConditionalOperator,
|
|
566
|
+
TFieldType extends string,
|
|
567
|
+
TValue extends string,
|
|
568
|
+
> = TOperator extends "="
|
|
569
|
+
? TFieldType extends `${string}|${string}`
|
|
570
|
+
? TValue extends ParseUnion<TFieldType>
|
|
571
|
+
? true
|
|
572
|
+
: false
|
|
573
|
+
: TFieldType extends TValue
|
|
574
|
+
? true
|
|
575
|
+
: false
|
|
576
|
+
: TOperator extends "!="
|
|
577
|
+
? TFieldType extends TValue
|
|
578
|
+
? false
|
|
579
|
+
: true
|
|
580
|
+
: "unknown"; // For complex operators, return unknown to use union type
|
|
581
|
+
|
|
582
|
+
// union parsing with better parentheses handling
|
|
583
|
+
export type ParseUnion<T extends string> = T extends `(${infer Content})`
|
|
584
|
+
? ParseUnion<Content>
|
|
585
|
+
: T extends `${infer First}|${infer Rest}`
|
|
586
|
+
? First | ParseUnion<Rest>
|
|
587
|
+
: T;
|
|
588
|
+
|
|
589
|
+
// Main parsing function with all syntax support
|
|
590
|
+
export type ParseConditionalSchema<
|
|
591
|
+
T extends string,
|
|
592
|
+
TSchema extends Record<string, any>,
|
|
593
|
+
> =
|
|
594
|
+
ParseRevolutionarySyntax<T> extends {
|
|
595
|
+
condition: infer C extends string;
|
|
596
|
+
thenType: infer Then extends string;
|
|
597
|
+
elseType: infer Else extends string;
|
|
598
|
+
}
|
|
599
|
+
? ResolveConditionalType<C, Then, Else, TSchema>
|
|
600
|
+
: ParseParenthesesSyntax<T> extends {
|
|
601
|
+
condition: infer C extends string;
|
|
602
|
+
thenType: infer Then extends string;
|
|
603
|
+
elseType: infer Else extends string;
|
|
604
|
+
}
|
|
605
|
+
? ResolveConditionalType<C, Then, Else, TSchema>
|
|
606
|
+
: ParseLegacySyntax<T> extends {
|
|
607
|
+
condition: infer C extends string;
|
|
608
|
+
thenType: infer Then extends string;
|
|
609
|
+
elseType: infer Else extends string;
|
|
610
|
+
}
|
|
611
|
+
? ResolveConditionalType<C, Then, Else, TSchema>
|
|
612
|
+
: SchemaUtils.ResolveSchemaType<T>;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// ============================================================================
|
|
616
|
+
// VALIDATION SYSTEM - with comprehensive checks
|
|
617
|
+
// ============================================================================
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Comprehensive validation system for conditional expressions
|
|
621
|
+
*/
|
|
622
|
+
export namespace Validation {
|
|
623
|
+
export interface ValidationResult<T = any> {
|
|
624
|
+
readonly isValid: boolean;
|
|
625
|
+
readonly errors: readonly string[];
|
|
626
|
+
readonly warnings: readonly string[];
|
|
627
|
+
readonly result?: T;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
export type ValidateConditional<TData, TExpression extends string> =
|
|
631
|
+
ConditionalResolver.ParseRevolutionarySyntax<TExpression> extends {
|
|
632
|
+
condition: infer Condition extends string;
|
|
633
|
+
thenType: infer ThenType extends string;
|
|
634
|
+
elseType: infer ElseType extends string;
|
|
635
|
+
}
|
|
636
|
+
? ValidateConditionAgainstSchema<
|
|
637
|
+
TData,
|
|
638
|
+
Condition
|
|
639
|
+
> extends ValidationResult<infer ConditionResult>
|
|
640
|
+
? ConditionResult extends true
|
|
641
|
+
? {
|
|
642
|
+
isValid: true;
|
|
643
|
+
errors: [];
|
|
644
|
+
warnings: [];
|
|
645
|
+
result: {
|
|
646
|
+
field: ConditionParser.ParseConditionPattern<Condition> extends ConditionParser.ParsedCondition<
|
|
647
|
+
infer F,
|
|
648
|
+
any,
|
|
649
|
+
any
|
|
650
|
+
>
|
|
651
|
+
? F
|
|
652
|
+
: never;
|
|
653
|
+
operator: ConditionParser.ParseConditionPattern<Condition> extends ConditionParser.ParsedCondition<
|
|
654
|
+
any,
|
|
655
|
+
infer O,
|
|
656
|
+
any
|
|
657
|
+
>
|
|
658
|
+
? O
|
|
659
|
+
: never;
|
|
660
|
+
value: ConditionParser.ParseConditionPattern<Condition> extends ConditionParser.ParsedCondition<
|
|
661
|
+
any,
|
|
662
|
+
any,
|
|
663
|
+
infer V
|
|
664
|
+
>
|
|
665
|
+
? V
|
|
666
|
+
: never;
|
|
667
|
+
thenType: SchemaUtils.ResolveSchemaType<ThenType>;
|
|
668
|
+
elseType: SchemaUtils.ResolveSchemaType<ElseType>;
|
|
669
|
+
resultType:
|
|
670
|
+
| SchemaUtils.ResolveSchemaType<ThenType>
|
|
671
|
+
| SchemaUtils.ResolveSchemaType<ElseType>;
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
: {
|
|
675
|
+
isValid: false;
|
|
676
|
+
errors: ["Invalid condition"];
|
|
677
|
+
warnings: [];
|
|
678
|
+
}
|
|
679
|
+
: {
|
|
680
|
+
isValid: false;
|
|
681
|
+
errors: ["Could not validate condition"];
|
|
682
|
+
warnings: [];
|
|
683
|
+
}
|
|
684
|
+
: {
|
|
685
|
+
isValid: false;
|
|
686
|
+
errors: ["Could not parse conditional expression"];
|
|
687
|
+
warnings: [];
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
type ValidateConditionAgainstSchema<TData, TCondition extends string> =
|
|
691
|
+
ConditionParser.ParseConditionPattern<TCondition> extends ConditionParser.ParsedCondition<
|
|
692
|
+
infer TField extends string,
|
|
693
|
+
infer TOperator extends Operators.ConditionalOperator,
|
|
694
|
+
infer TValue extends string
|
|
695
|
+
>
|
|
696
|
+
? TField extends SchemaUtils.FieldPaths<TData>
|
|
697
|
+
? ValidationResult<true>
|
|
698
|
+
: ValidationResult<false> & {
|
|
699
|
+
errors: [`Field '${TField}' does not exist in schema`];
|
|
700
|
+
}
|
|
701
|
+
: ValidationResult<false> & { errors: ["Could not parse condition"] };
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// ============================================================================
|
|
705
|
+
// BUILDER PATTERN - with better type safety
|
|
706
|
+
// ============================================================================
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* builder pattern for creating type-safe conditionals
|
|
710
|
+
*/
|
|
711
|
+
export namespace Builder {
|
|
712
|
+
export interface TypeSafeConditionalBuilder<TData> {
|
|
713
|
+
when<TField extends string>(
|
|
714
|
+
field: TField
|
|
715
|
+
): FieldConditionalBuilder<
|
|
716
|
+
TData,
|
|
717
|
+
any, // Simplified to avoid complex type constraints
|
|
718
|
+
TField
|
|
719
|
+
>;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
export interface FieldConditionalBuilder<
|
|
723
|
+
TData,
|
|
724
|
+
TFieldType,
|
|
725
|
+
TField extends string,
|
|
726
|
+
> {
|
|
727
|
+
equals<TValue extends TFieldType>(
|
|
728
|
+
value: TValue
|
|
729
|
+
): ThenBuilder<TData, TFieldType, TField, "=", TValue>;
|
|
730
|
+
|
|
731
|
+
notEquals<TValue extends TFieldType>(
|
|
732
|
+
value: TValue
|
|
733
|
+
): ThenBuilder<TData, TFieldType, TField, "!=", TValue>;
|
|
734
|
+
|
|
735
|
+
greaterThan<TValue extends TFieldType>(
|
|
736
|
+
value: TFieldType extends number ? TValue : never
|
|
737
|
+
): ThenBuilder<TData, TFieldType, TField, ">", TValue>;
|
|
738
|
+
|
|
739
|
+
greaterEqual<TValue extends TFieldType>(
|
|
740
|
+
value: TFieldType extends number ? TValue : never
|
|
741
|
+
): ThenBuilder<TData, TFieldType, TField, ">=", TValue>;
|
|
742
|
+
|
|
743
|
+
lessThan<TValue extends TFieldType>(
|
|
744
|
+
value: TFieldType extends number ? TValue : never
|
|
745
|
+
): ThenBuilder<TData, TFieldType, TField, "<", TValue>;
|
|
746
|
+
|
|
747
|
+
lessEqual<TValue extends TFieldType>(
|
|
748
|
+
value: TFieldType extends number ? TValue : never
|
|
749
|
+
): ThenBuilder<TData, TFieldType, TField, "<=", TValue>;
|
|
750
|
+
|
|
751
|
+
matches(
|
|
752
|
+
pattern: TFieldType extends string ? string : never
|
|
753
|
+
): ThenBuilder<TData, TFieldType, TField, "~", string>;
|
|
754
|
+
|
|
755
|
+
contains(
|
|
756
|
+
value: TFieldType extends string ? string : never
|
|
757
|
+
): ThenBuilder<TData, TFieldType, TField, "contains", string>;
|
|
758
|
+
|
|
759
|
+
startsWith(
|
|
760
|
+
value: TFieldType extends string ? string : never
|
|
761
|
+
): ThenBuilder<TData, TFieldType, TField, "startsWith", string>;
|
|
762
|
+
|
|
763
|
+
endsWith(
|
|
764
|
+
value: TFieldType extends string ? string : never
|
|
765
|
+
): ThenBuilder<TData, TFieldType, TField, "endsWith", string>;
|
|
766
|
+
|
|
767
|
+
in<TValues extends readonly TFieldType[]>(
|
|
768
|
+
...values: TValues
|
|
769
|
+
): ThenBuilder<TData, TFieldType, TField, "in", TValues>;
|
|
770
|
+
|
|
771
|
+
notIn<TValues extends readonly TFieldType[]>(
|
|
772
|
+
...values: TValues
|
|
773
|
+
): ThenBuilder<TData, TFieldType, TField, "!in", TValues>;
|
|
774
|
+
|
|
775
|
+
exists(): ThenBuilder<TData, TFieldType, TField, "exists", undefined>;
|
|
776
|
+
notExists(): ThenBuilder<TData, TFieldType, TField, "!exists", undefined>;
|
|
777
|
+
empty(): ThenBuilder<TData, TFieldType, TField, "empty", undefined>;
|
|
778
|
+
notEmpty(): ThenBuilder<TData, TFieldType, TField, "!empty", undefined>;
|
|
779
|
+
isNull(): ThenBuilder<TData, TFieldType, TField, "null", undefined>;
|
|
780
|
+
notNull(): ThenBuilder<TData, TFieldType, TField, "!null", undefined>;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
export interface ThenBuilder<
|
|
784
|
+
TData,
|
|
785
|
+
TFieldType,
|
|
786
|
+
TField extends string,
|
|
787
|
+
TOperator extends Operators.ConditionalOperator,
|
|
788
|
+
TValue,
|
|
789
|
+
> {
|
|
790
|
+
then<TThenType>(
|
|
791
|
+
value: TThenType
|
|
792
|
+
): ElseBuilder<TData, TFieldType, TField, TOperator, TValue, TThenType>;
|
|
793
|
+
|
|
794
|
+
thenType<TType extends string>(
|
|
795
|
+
type: TType
|
|
796
|
+
): ElseBuilder<
|
|
797
|
+
TData,
|
|
798
|
+
TFieldType,
|
|
799
|
+
TField,
|
|
800
|
+
TOperator,
|
|
801
|
+
TValue,
|
|
802
|
+
SchemaUtils.ResolveSchemaType<TType>
|
|
803
|
+
>;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
export interface ElseBuilder<
|
|
807
|
+
TData,
|
|
808
|
+
TFieldType,
|
|
809
|
+
TField extends string,
|
|
810
|
+
TOperator extends Operators.ConditionalOperator,
|
|
811
|
+
TValue,
|
|
812
|
+
TThenType,
|
|
813
|
+
> {
|
|
814
|
+
else<TElseType>(
|
|
815
|
+
value: TElseType
|
|
816
|
+
): ConditionalExpression<TElseType | TThenType>;
|
|
817
|
+
|
|
818
|
+
elseType<TType extends string>(
|
|
819
|
+
type: TType
|
|
820
|
+
): ConditionalExpression<TThenType | SchemaUtils.ResolveSchemaType<TType>>;
|
|
821
|
+
|
|
822
|
+
elseWhen<TField2 extends string>(
|
|
823
|
+
field: TField2
|
|
824
|
+
): FieldConditionalBuilder<
|
|
825
|
+
TData,
|
|
826
|
+
any, // Simplified to avoid complex type constraints
|
|
827
|
+
TField2
|
|
828
|
+
>;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
export interface ConditionalExpression<TResultType> {
|
|
832
|
+
readonly expression: string;
|
|
833
|
+
readonly resultType: TResultType;
|
|
834
|
+
readonly metadata: {
|
|
835
|
+
readonly field: string;
|
|
836
|
+
readonly operator: Operators.ConditionalOperator;
|
|
837
|
+
readonly value: any;
|
|
838
|
+
readonly validation: Validation.ValidationResult;
|
|
839
|
+
};
|
|
840
|
+
toString(): string;
|
|
841
|
+
validate<TSchema>(): Validation.ValidationResult<TResultType>;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// ============================================================================
|
|
846
|
+
// MAIN EXPORTS - Public API
|
|
847
|
+
// ============================================================================
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Main exports for the conditional types system
|
|
851
|
+
*/
|
|
852
|
+
|
|
853
|
+
// Core type resolution
|
|
854
|
+
export type InferConditionalType<
|
|
855
|
+
TCondition extends string,
|
|
856
|
+
TThenType extends string,
|
|
857
|
+
TElseType extends string,
|
|
858
|
+
TSchema extends Record<string, any>,
|
|
859
|
+
> = ConditionalResolver.ResolveConditionalType<
|
|
860
|
+
TCondition,
|
|
861
|
+
TThenType,
|
|
862
|
+
TElseType,
|
|
863
|
+
TSchema
|
|
864
|
+
>;
|
|
865
|
+
|
|
866
|
+
// schema parsing
|
|
867
|
+
export type ParseConditionalSchema<
|
|
868
|
+
T extends string,
|
|
869
|
+
TSchema extends Record<string, any>,
|
|
870
|
+
> = ConditionalResolver.ParseConditionalSchema<T, TSchema>;
|
|
871
|
+
|
|
872
|
+
// Validation exports
|
|
873
|
+
export type ValidateConditional<
|
|
874
|
+
TData,
|
|
875
|
+
TExpression extends string,
|
|
876
|
+
> = Validation.ValidateConditional<TData, TExpression>;
|
|
877
|
+
|
|
878
|
+
// Builder exports
|
|
879
|
+
export type CreateConditionalBuilder<TData> =
|
|
880
|
+
Builder.TypeSafeConditionalBuilder<TData>;
|
|
881
|
+
|
|
882
|
+
// Utility exports
|
|
883
|
+
export type FieldPaths<T> = SchemaUtils.FieldPaths<T>;
|
|
884
|
+
export type GetValueByPath<T, P extends string> = SchemaUtils.GetValueByPath<
|
|
885
|
+
T,
|
|
886
|
+
P
|
|
887
|
+
>;
|
|
888
|
+
|
|
889
|
+
// ============================================================================
|
|
890
|
+
// RUNTIME UTILITIES - Implementation helpers
|
|
891
|
+
// ============================================================================
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Runtime utilities for working with conditional expressions
|
|
895
|
+
*/
|
|
896
|
+
export namespace Runtime {
|
|
897
|
+
// Runtime condition evaluator
|
|
898
|
+
export function evaluateCondition(
|
|
899
|
+
fieldValue: any,
|
|
900
|
+
operator: Operators.ConditionalOperator,
|
|
901
|
+
conditionValue: string
|
|
902
|
+
): boolean {
|
|
903
|
+
switch (operator) {
|
|
904
|
+
// Existence operators
|
|
905
|
+
case "exists":
|
|
906
|
+
return fieldValue !== undefined && fieldValue !== null;
|
|
907
|
+
case "!exists":
|
|
908
|
+
return fieldValue === undefined || fieldValue === null;
|
|
909
|
+
|
|
910
|
+
// State operators
|
|
911
|
+
case "empty":
|
|
912
|
+
if (typeof fieldValue === "string") return fieldValue.length === 0;
|
|
913
|
+
if (Array.isArray(fieldValue)) return fieldValue.length === 0;
|
|
914
|
+
if (typeof fieldValue === "object" && fieldValue !== null) {
|
|
915
|
+
return Object.keys(fieldValue).length === 0;
|
|
916
|
+
}
|
|
917
|
+
return false;
|
|
918
|
+
case "!empty":
|
|
919
|
+
if (typeof fieldValue === "string") return fieldValue.length > 0;
|
|
920
|
+
if (Array.isArray(fieldValue)) return fieldValue.length > 0;
|
|
921
|
+
if (typeof fieldValue === "object" && fieldValue !== null) {
|
|
922
|
+
return Object.keys(fieldValue).length > 0;
|
|
923
|
+
}
|
|
924
|
+
return true;
|
|
925
|
+
case "null":
|
|
926
|
+
return fieldValue === null;
|
|
927
|
+
case "!null":
|
|
928
|
+
return fieldValue !== null;
|
|
929
|
+
|
|
930
|
+
// Comparison operators
|
|
931
|
+
case "=":
|
|
932
|
+
return String(fieldValue) === conditionValue;
|
|
933
|
+
case "!=":
|
|
934
|
+
return String(fieldValue) !== conditionValue;
|
|
935
|
+
case ">":
|
|
936
|
+
return Number(fieldValue) > Number(conditionValue);
|
|
937
|
+
case ">=":
|
|
938
|
+
return Number(fieldValue) >= Number(conditionValue);
|
|
939
|
+
case "<":
|
|
940
|
+
return Number(fieldValue) < Number(conditionValue);
|
|
941
|
+
case "<=":
|
|
942
|
+
return Number(fieldValue) <= Number(conditionValue);
|
|
943
|
+
|
|
944
|
+
// String operators
|
|
945
|
+
case "contains":
|
|
946
|
+
return String(fieldValue).includes(conditionValue);
|
|
947
|
+
case "!contains":
|
|
948
|
+
return !String(fieldValue).includes(conditionValue);
|
|
949
|
+
case "startsWith":
|
|
950
|
+
return String(fieldValue).startsWith(conditionValue);
|
|
951
|
+
case "endsWith":
|
|
952
|
+
return String(fieldValue).endsWith(conditionValue);
|
|
953
|
+
|
|
954
|
+
// Regex operators
|
|
955
|
+
case "~":
|
|
956
|
+
try {
|
|
957
|
+
return new RegExp(conditionValue).test(String(fieldValue));
|
|
958
|
+
} catch {
|
|
959
|
+
return false;
|
|
960
|
+
}
|
|
961
|
+
case "!~":
|
|
962
|
+
try {
|
|
963
|
+
return !new RegExp(conditionValue).test(String(fieldValue));
|
|
964
|
+
} catch {
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// Inclusion operators
|
|
969
|
+
case "in":
|
|
970
|
+
const inValues = conditionValue.split(",").map((v) => v.trim());
|
|
971
|
+
return inValues.includes(String(fieldValue));
|
|
972
|
+
case "!in":
|
|
973
|
+
const notInValues = conditionValue.split(",").map((v) => v.trim());
|
|
974
|
+
return !notInValues.includes(String(fieldValue));
|
|
975
|
+
|
|
976
|
+
default:
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// Runtime field value extraction with path support
|
|
982
|
+
export function getFieldValue(data: any, path: string): any {
|
|
983
|
+
if (!path || typeof data !== "object" || data === null) {
|
|
984
|
+
return undefined;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const keys = path.split(".");
|
|
988
|
+
let current = data;
|
|
989
|
+
|
|
990
|
+
for (const key of keys) {
|
|
991
|
+
if (current === null || current === undefined) {
|
|
992
|
+
return undefined;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// Handle array indices
|
|
996
|
+
if (/^\d+$/.test(key)) {
|
|
997
|
+
const index = parseInt(key, 10);
|
|
998
|
+
if (Array.isArray(current) && index >= 0 && index < current.length) {
|
|
999
|
+
current = current[index];
|
|
1000
|
+
} else {
|
|
1001
|
+
return undefined;
|
|
1002
|
+
}
|
|
1003
|
+
} else {
|
|
1004
|
+
current = current[key];
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
return current;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Runtime conditional expression parser
|
|
1012
|
+
export function parseCondition(conditionStr: string): {
|
|
1013
|
+
field: string;
|
|
1014
|
+
operator: Operators.ConditionalOperator;
|
|
1015
|
+
value: string;
|
|
1016
|
+
} | null {
|
|
1017
|
+
const trimmed = conditionStr.trim();
|
|
1018
|
+
|
|
1019
|
+
// Try operators in precedence order
|
|
1020
|
+
for (const operator of Operators.getOperatorsByPrecedence()) {
|
|
1021
|
+
const config = Operators.OPERATOR_CONFIG[operator];
|
|
1022
|
+
|
|
1023
|
+
if (!config.requiresValue) {
|
|
1024
|
+
// For operators that don't require a value (exists, empty, null)
|
|
1025
|
+
if (trimmed.endsWith(operator)) {
|
|
1026
|
+
const field = trimmed.slice(0, -operator.length);
|
|
1027
|
+
return { field, operator, value: "" };
|
|
1028
|
+
}
|
|
1029
|
+
} else {
|
|
1030
|
+
// For operators that require a value
|
|
1031
|
+
const operatorIndex = trimmed.indexOf(operator);
|
|
1032
|
+
if (operatorIndex > 0) {
|
|
1033
|
+
const field = trimmed.slice(0, operatorIndex);
|
|
1034
|
+
const value = trimmed.slice(operatorIndex + operator.length);
|
|
1035
|
+
return { field, operator, value };
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// Runtime conditional expression evaluator
|
|
1044
|
+
export function evaluateConditionalExpression(
|
|
1045
|
+
data: any,
|
|
1046
|
+
expression: string
|
|
1047
|
+
): any {
|
|
1048
|
+
// Parse different syntax formats
|
|
1049
|
+
let condition: string, thenValue: string, elseValue: string;
|
|
1050
|
+
|
|
1051
|
+
// syntax: when condition *? then : else
|
|
1052
|
+
let match = expression.match(/when\s+(.+?)\s*\*\?\s*(.+?)\s*:\s*(.+)/);
|
|
1053
|
+
if (match) {
|
|
1054
|
+
[, condition, thenValue, elseValue] = match;
|
|
1055
|
+
} else {
|
|
1056
|
+
// Parentheses syntax: when(condition) then(value) else(value)
|
|
1057
|
+
match = expression.match(/when\((.+?)\)\s*then\((.+?)\)\s*else\((.+?)\)/);
|
|
1058
|
+
if (match) {
|
|
1059
|
+
[, condition, thenValue, elseValue] = match;
|
|
1060
|
+
} else {
|
|
1061
|
+
// Legacy syntax: when:condition:then:else
|
|
1062
|
+
match = expression.match(/when:(.+?):(.+?):(.+)/);
|
|
1063
|
+
if (match) {
|
|
1064
|
+
[, condition, thenValue, elseValue] = match;
|
|
1065
|
+
} else {
|
|
1066
|
+
throw new Error(
|
|
1067
|
+
`Invalid conditional expression format: ${expression}`
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
// Parse the condition
|
|
1074
|
+
const parsedCondition = parseCondition(condition.trim());
|
|
1075
|
+
if (!parsedCondition) {
|
|
1076
|
+
throw new Error(`Could not parse condition: ${condition}`);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// Get field value
|
|
1080
|
+
const fieldValue = getFieldValue(data, parsedCondition.field);
|
|
1081
|
+
|
|
1082
|
+
// Evaluate condition
|
|
1083
|
+
const conditionResult = evaluateCondition(
|
|
1084
|
+
fieldValue,
|
|
1085
|
+
parsedCondition.operator,
|
|
1086
|
+
parsedCondition.value
|
|
1087
|
+
);
|
|
1088
|
+
|
|
1089
|
+
// Return appropriate value
|
|
1090
|
+
return conditionResult
|
|
1091
|
+
? parseValue(thenValue.trim())
|
|
1092
|
+
: parseValue(elseValue.trim());
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// Parse value with type coercion
|
|
1096
|
+
function parseValue(value: string): any {
|
|
1097
|
+
const trimmed = value.trim();
|
|
1098
|
+
|
|
1099
|
+
// Handle quoted strings
|
|
1100
|
+
if (
|
|
1101
|
+
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
1102
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
|
1103
|
+
) {
|
|
1104
|
+
return trimmed.slice(1, -1);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Handle booleans
|
|
1108
|
+
if (trimmed === "true") return true;
|
|
1109
|
+
if (trimmed === "false") return false;
|
|
1110
|
+
|
|
1111
|
+
// Handle null/undefined
|
|
1112
|
+
if (trimmed === "null") return null;
|
|
1113
|
+
if (trimmed === "undefined") return undefined;
|
|
1114
|
+
|
|
1115
|
+
// Handle numbers
|
|
1116
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
1117
|
+
return Number(trimmed);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// Handle arrays (simple comma-separated values)
|
|
1121
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
1122
|
+
const arrayContent = trimmed.slice(1, -1);
|
|
1123
|
+
if (arrayContent.trim() === "") return [];
|
|
1124
|
+
return arrayContent.split(",").map((item) => parseValue(item.trim()));
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// Default to string
|
|
1128
|
+
return trimmed;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// Validation helper
|
|
1132
|
+
export function validateConditionSyntax(condition: string): {
|
|
1133
|
+
isValid: boolean;
|
|
1134
|
+
errors: string[];
|
|
1135
|
+
warnings: string[];
|
|
1136
|
+
} {
|
|
1137
|
+
const errors: string[] = [];
|
|
1138
|
+
const warnings: string[] = [];
|
|
1139
|
+
|
|
1140
|
+
try {
|
|
1141
|
+
const parsed = parseCondition(condition);
|
|
1142
|
+
if (!parsed) {
|
|
1143
|
+
errors.push("Could not parse condition syntax");
|
|
1144
|
+
return { isValid: false, errors, warnings };
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// Validate operator
|
|
1148
|
+
if (!Operators.isValidOperator(parsed.operator)) {
|
|
1149
|
+
errors.push(`Unknown operator: ${parsed.operator}`);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// Validate value requirement
|
|
1153
|
+
const config = Operators.OPERATOR_CONFIG[parsed.operator];
|
|
1154
|
+
if (config.requiresValue && !parsed.value) {
|
|
1155
|
+
errors.push(`Operator '${parsed.operator}' requires a value`);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// Check for common mistakes
|
|
1159
|
+
if (parsed.field.includes(" ")) {
|
|
1160
|
+
warnings.push("Field names with spaces may cause issues");
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
if (parsed.operator === "~" || parsed.operator === "!~") {
|
|
1164
|
+
try {
|
|
1165
|
+
new RegExp(parsed.value);
|
|
1166
|
+
} catch {
|
|
1167
|
+
errors.push("Invalid regex pattern");
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
errors.push(
|
|
1172
|
+
`Validation error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
return {
|
|
1177
|
+
isValid: errors.length === 0,
|
|
1178
|
+
errors,
|
|
1179
|
+
warnings,
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// ============================================================================
|
|
1185
|
+
// FACTORY FUNCTIONS - Convenient creation helpers
|
|
1186
|
+
// ============================================================================
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Factory functions for creating conditional expressions
|
|
1190
|
+
*/
|
|
1191
|
+
export namespace Factory {
|
|
1192
|
+
export function createConditionalBuilder<
|
|
1193
|
+
TData,
|
|
1194
|
+
>(): Builder.TypeSafeConditionalBuilder<TData> {
|
|
1195
|
+
return {
|
|
1196
|
+
when<TField extends string>(field: TField) {
|
|
1197
|
+
return createFieldBuilder<
|
|
1198
|
+
TData,
|
|
1199
|
+
any, // Simplified to avoid complex type constraints
|
|
1200
|
+
TField
|
|
1201
|
+
>(field);
|
|
1202
|
+
},
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
function createFieldBuilder<TData, TFieldType, TField extends string>(
|
|
1207
|
+
field: TField
|
|
1208
|
+
): Builder.FieldConditionalBuilder<TData, TFieldType, TField> {
|
|
1209
|
+
return {
|
|
1210
|
+
equals: <TValue extends TFieldType>(value: TValue) =>
|
|
1211
|
+
createThenBuilder(field, "=", value),
|
|
1212
|
+
notEquals: <TValue extends TFieldType>(value: TValue) =>
|
|
1213
|
+
createThenBuilder(field, "!=", value),
|
|
1214
|
+
greaterThan: <TValue extends TFieldType>(
|
|
1215
|
+
value: TFieldType extends number ? TValue : never
|
|
1216
|
+
) => createThenBuilder(field, ">", value),
|
|
1217
|
+
greaterEqual: <TValue extends TFieldType>(
|
|
1218
|
+
value: TFieldType extends number ? TValue : never
|
|
1219
|
+
) => createThenBuilder(field, ">=", value),
|
|
1220
|
+
lessThan: <TValue extends TFieldType>(
|
|
1221
|
+
value: TFieldType extends number ? TValue : never
|
|
1222
|
+
) => createThenBuilder(field, "<", value),
|
|
1223
|
+
lessEqual: <TValue extends TFieldType>(
|
|
1224
|
+
value: TFieldType extends number ? TValue : never
|
|
1225
|
+
) => createThenBuilder(field, "<=", value),
|
|
1226
|
+
matches: (pattern: TFieldType extends string ? string : never) =>
|
|
1227
|
+
createThenBuilder(field, "~", pattern),
|
|
1228
|
+
contains: (value: TFieldType extends string ? string : never) =>
|
|
1229
|
+
createThenBuilder(field, "contains", value),
|
|
1230
|
+
startsWith: (value: TFieldType extends string ? string : never) =>
|
|
1231
|
+
createThenBuilder(field, "startsWith", value),
|
|
1232
|
+
endsWith: (value: TFieldType extends string ? string : never) =>
|
|
1233
|
+
createThenBuilder(field, "endsWith", value),
|
|
1234
|
+
in: <TValues extends readonly TFieldType[]>(...values: TValues) =>
|
|
1235
|
+
createThenBuilder(field, "in", values.join(",")),
|
|
1236
|
+
notIn: <TValues extends readonly TFieldType[]>(...values: TValues) =>
|
|
1237
|
+
createThenBuilder(field, "!in", values.join(",")),
|
|
1238
|
+
exists: () => createThenBuilder(field, "exists", undefined),
|
|
1239
|
+
notExists: () => createThenBuilder(field, "!exists", undefined),
|
|
1240
|
+
empty: () => createThenBuilder(field, "empty", undefined),
|
|
1241
|
+
notEmpty: () => createThenBuilder(field, "!empty", undefined),
|
|
1242
|
+
isNull: () => createThenBuilder(field, "null", undefined),
|
|
1243
|
+
notNull: () => createThenBuilder(field, "!null", undefined),
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
function createThenBuilder<
|
|
1248
|
+
TData,
|
|
1249
|
+
TFieldType,
|
|
1250
|
+
TField extends string,
|
|
1251
|
+
TOperator extends Operators.ConditionalOperator,
|
|
1252
|
+
TValue,
|
|
1253
|
+
>(
|
|
1254
|
+
field: TField,
|
|
1255
|
+
operator: TOperator,
|
|
1256
|
+
value: TValue
|
|
1257
|
+
): Builder.ThenBuilder<TData, TFieldType, TField, TOperator, TValue> {
|
|
1258
|
+
return {
|
|
1259
|
+
then: <TThenType>(thenValue: TThenType) =>
|
|
1260
|
+
createElseBuilder(field, operator, value, thenValue),
|
|
1261
|
+
thenType: <TType extends string>(type: TType) =>
|
|
1262
|
+
createElseBuilder(field, operator, value, type),
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
function createElseBuilder<
|
|
1267
|
+
TData,
|
|
1268
|
+
TFieldType,
|
|
1269
|
+
TField extends string,
|
|
1270
|
+
TOperator extends Operators.ConditionalOperator,
|
|
1271
|
+
TValue,
|
|
1272
|
+
TThenType,
|
|
1273
|
+
>(
|
|
1274
|
+
field: TField,
|
|
1275
|
+
operator: TOperator,
|
|
1276
|
+
value: TValue,
|
|
1277
|
+
thenType: TThenType
|
|
1278
|
+
): Builder.ElseBuilder<
|
|
1279
|
+
TData,
|
|
1280
|
+
TFieldType,
|
|
1281
|
+
TField,
|
|
1282
|
+
TOperator,
|
|
1283
|
+
TValue,
|
|
1284
|
+
TThenType
|
|
1285
|
+
> {
|
|
1286
|
+
return {
|
|
1287
|
+
else: <TElseType>(elseValue: TElseType) =>
|
|
1288
|
+
createConditionalExpression(
|
|
1289
|
+
field,
|
|
1290
|
+
operator,
|
|
1291
|
+
value,
|
|
1292
|
+
thenType,
|
|
1293
|
+
elseValue
|
|
1294
|
+
) as Builder.ConditionalExpression<TElseType | TThenType>,
|
|
1295
|
+
elseType: <TType extends string>(type: TType) =>
|
|
1296
|
+
createConditionalExpression(field, operator, value, thenType, type),
|
|
1297
|
+
elseWhen: <TField2 extends string>(field2: TField2) =>
|
|
1298
|
+
createFieldBuilder<
|
|
1299
|
+
TData,
|
|
1300
|
+
any, // Simplified to avoid complex type constraints
|
|
1301
|
+
TField2
|
|
1302
|
+
>(field2),
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
function createConditionalExpression<TResultType>(
|
|
1307
|
+
field: string,
|
|
1308
|
+
operator: Operators.ConditionalOperator,
|
|
1309
|
+
value: any,
|
|
1310
|
+
thenType: any,
|
|
1311
|
+
elseType: any
|
|
1312
|
+
): Builder.ConditionalExpression<TResultType> {
|
|
1313
|
+
const valueStr = value === undefined ? "" : String(value);
|
|
1314
|
+
const condition = `${field}${operator}${valueStr}`;
|
|
1315
|
+
const expression = `when ${condition} *? ${thenType} : ${elseType}`;
|
|
1316
|
+
|
|
1317
|
+
return {
|
|
1318
|
+
expression,
|
|
1319
|
+
resultType: (thenType || elseType) as TResultType,
|
|
1320
|
+
metadata: {
|
|
1321
|
+
field,
|
|
1322
|
+
operator,
|
|
1323
|
+
value,
|
|
1324
|
+
validation: Runtime.validateConditionSyntax(condition),
|
|
1325
|
+
},
|
|
1326
|
+
toString: () => expression,
|
|
1327
|
+
validate: <TSchema>() => ({
|
|
1328
|
+
isValid: true,
|
|
1329
|
+
errors: [],
|
|
1330
|
+
warnings: [],
|
|
1331
|
+
result: (thenType || elseType) as TResultType,
|
|
1332
|
+
}),
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
// Quick creation helpers
|
|
1337
|
+
export function when<TData>() {
|
|
1338
|
+
return createConditionalBuilder<TData>();
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
export function condition(conditionStr: string) {
|
|
1342
|
+
return {
|
|
1343
|
+
then: (thenValue: any) => ({
|
|
1344
|
+
else: (elseValue: any) =>
|
|
1345
|
+
`when ${conditionStr} *? ${thenValue} : ${elseValue}`,
|
|
1346
|
+
elseType: (elseType: string) =>
|
|
1347
|
+
`when ${conditionStr} *? ${thenValue} : ${elseType}`,
|
|
1348
|
+
}),
|
|
1349
|
+
thenType: (thenType: string) => ({
|
|
1350
|
+
else: (elseValue: any) =>
|
|
1351
|
+
`when ${conditionStr} *? ${thenType} : ${elseValue}`,
|
|
1352
|
+
elseType: (elseType: string) =>
|
|
1353
|
+
`when ${conditionStr} *? ${thenType} : ${elseType}`,
|
|
1354
|
+
}),
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// ============================================================================
|
|
1360
|
+
// TESTING UTILITIES - For development and debugging
|
|
1361
|
+
// ============================================================================
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* Testing and debugging utilities
|
|
1365
|
+
*/
|
|
1366
|
+
export namespace Testing {
|
|
1367
|
+
export interface TestCase<TData = any> {
|
|
1368
|
+
name: string;
|
|
1369
|
+
data: TData;
|
|
1370
|
+
expression: string;
|
|
1371
|
+
expected: any;
|
|
1372
|
+
description?: string;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
export function runTest<TData>(testCase: TestCase<TData>): {
|
|
1376
|
+
passed: boolean;
|
|
1377
|
+
actual: any;
|
|
1378
|
+
expected: any;
|
|
1379
|
+
error?: string;
|
|
1380
|
+
} {
|
|
1381
|
+
try {
|
|
1382
|
+
const actual = Runtime.evaluateConditionalExpression(
|
|
1383
|
+
testCase.data,
|
|
1384
|
+
testCase.expression
|
|
1385
|
+
);
|
|
1386
|
+
const passed =
|
|
1387
|
+
JSON.stringify(actual) === JSON.stringify(testCase.expected);
|
|
1388
|
+
|
|
1389
|
+
return {
|
|
1390
|
+
passed,
|
|
1391
|
+
actual,
|
|
1392
|
+
expected: testCase.expected,
|
|
1393
|
+
};
|
|
1394
|
+
} catch (error) {
|
|
1395
|
+
return {
|
|
1396
|
+
passed: false,
|
|
1397
|
+
actual: undefined,
|
|
1398
|
+
expected: testCase.expected,
|
|
1399
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
export function runTestSuite(testCases: TestCase[]): {
|
|
1405
|
+
passed: number;
|
|
1406
|
+
failed: number;
|
|
1407
|
+
results: Array<{ testCase: TestCase; result: ReturnType<typeof runTest> }>;
|
|
1408
|
+
} {
|
|
1409
|
+
const results = testCases.map((testCase) => ({
|
|
1410
|
+
testCase,
|
|
1411
|
+
result: runTest(testCase),
|
|
1412
|
+
}));
|
|
1413
|
+
|
|
1414
|
+
const passed = results.filter((r) => r.result.passed).length;
|
|
1415
|
+
const failed = results.length - passed;
|
|
1416
|
+
|
|
1417
|
+
return { passed, failed, results };
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// Example test cases
|
|
1421
|
+
export const EXAMPLE_TESTS: TestCase[] = [
|
|
1422
|
+
{
|
|
1423
|
+
name: "Simple equality",
|
|
1424
|
+
data: { status: "active" },
|
|
1425
|
+
expression: "when status=active *? enabled : disabled",
|
|
1426
|
+
expected: "enabled",
|
|
1427
|
+
},
|
|
1428
|
+
{
|
|
1429
|
+
name: "Numeric comparison",
|
|
1430
|
+
data: { age: 25 },
|
|
1431
|
+
expression: "when age>=18 *? adult : minor",
|
|
1432
|
+
expected: "adult",
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
name: "String contains",
|
|
1436
|
+
data: { email: "user@example.com" },
|
|
1437
|
+
expression: "when email contains @ *? valid : invalid",
|
|
1438
|
+
expected: "valid",
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
name: "Existence check",
|
|
1442
|
+
data: { name: "John" },
|
|
1443
|
+
expression: "when name exists *? present : missing",
|
|
1444
|
+
expected: "present",
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
name: "Array inclusion",
|
|
1448
|
+
data: { role: "admin" },
|
|
1449
|
+
expression: "when role in(admin,moderator) *? authorized : unauthorized",
|
|
1450
|
+
expected: "authorized",
|
|
1451
|
+
},
|
|
1452
|
+
];
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// ============================================================================
|
|
1456
|
+
// DOCUMENTATION HELPERS - Auto-generated docs
|
|
1457
|
+
// ============================================================================
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* Documentation generation utilities
|
|
1461
|
+
*/
|
|
1462
|
+
export namespace Documentation {
|
|
1463
|
+
export function generateOperatorDocs(): string {
|
|
1464
|
+
let docs = "# Conditional Operators Reference\n\n";
|
|
1465
|
+
|
|
1466
|
+
const groupedOps = {
|
|
1467
|
+
"Existence Operators": ["exists", "!exists"] as const,
|
|
1468
|
+
"State Operators": ["empty", "!empty", "null", "!null"] as const,
|
|
1469
|
+
"Inclusion Operators": ["in", "!in"] as const,
|
|
1470
|
+
"String Operators": [
|
|
1471
|
+
"contains",
|
|
1472
|
+
"!contains",
|
|
1473
|
+
"startsWith",
|
|
1474
|
+
"endsWith",
|
|
1475
|
+
] as const,
|
|
1476
|
+
"Regex Operators": ["~", "!~"] as const,
|
|
1477
|
+
"Comparison Operators": ["=", "!=", ">", ">=", "<", "<="] as const,
|
|
1478
|
+
};
|
|
1479
|
+
|
|
1480
|
+
Object.entries(groupedOps).forEach(([group, operators]) => {
|
|
1481
|
+
docs += `## ${group}\n\n`;
|
|
1482
|
+
|
|
1483
|
+
operators.forEach((op) => {
|
|
1484
|
+
const config = Operators.OPERATOR_CONFIG[op];
|
|
1485
|
+
docs += `### \`${op}\`\n`;
|
|
1486
|
+
docs += `${config.description}\n\n`;
|
|
1487
|
+
docs += `**Type Support:** ${config.typeSupport.join(", ")}\n`;
|
|
1488
|
+
docs += `**Requires Value:** ${config.requiresValue ? "Yes" : "No"}\n`;
|
|
1489
|
+
docs += `**Examples:**\n`;
|
|
1490
|
+
config.examples.forEach((example) => {
|
|
1491
|
+
docs += `- \`${example}\`\n`;
|
|
1492
|
+
});
|
|
1493
|
+
docs += "\n";
|
|
1494
|
+
});
|
|
1495
|
+
});
|
|
1496
|
+
|
|
1497
|
+
return docs;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
export function generateSyntaxDocs(): string {
|
|
1501
|
+
return `# Conditional Syntax Reference
|
|
1502
|
+
|
|
1503
|
+
## Syntax (Recommended)
|
|
1504
|
+
\`\`\`
|
|
1505
|
+
when <condition> *? <then_value> : <else_value>
|
|
1506
|
+
\`\`\`
|
|
1507
|
+
|
|
1508
|
+
Example:
|
|
1509
|
+
\`\`\`
|
|
1510
|
+
when status=active *? enabled : disabled
|
|
1511
|
+
\`\`\`
|
|
1512
|
+
|
|
1513
|
+
## Parentheses Syntax
|
|
1514
|
+
\`\`\`
|
|
1515
|
+
when(<condition>) then(<then_value>) else(<else_value>)
|
|
1516
|
+
\`\`\`
|
|
1517
|
+
|
|
1518
|
+
Example:
|
|
1519
|
+
\`\`\`
|
|
1520
|
+
when(status=active) then(enabled) else(disabled)
|
|
1521
|
+
\`\`\`
|
|
1522
|
+
|
|
1523
|
+
## Legacy Syntax
|
|
1524
|
+
\`\`\`
|
|
1525
|
+
when:<condition>:<then_value>:<else_value>
|
|
1526
|
+
\`\`\`
|
|
1527
|
+
|
|
1528
|
+
Example:
|
|
1529
|
+
\`\`\`
|
|
1530
|
+
when:status=active:enabled:disabled
|
|
1531
|
+
\`\`\`
|
|
1532
|
+
`;
|
|
1533
|
+
}
|
|
1534
|
+
}
|