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,992 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Conditional Lexer
|
|
3
|
+
*
|
|
4
|
+
* Tokenizes conditional syntax with support for:
|
|
5
|
+
* - Nested conditions
|
|
6
|
+
* - Logical operators (&&, ||)
|
|
7
|
+
* - Method calls (.in(), .exists, etc.)
|
|
8
|
+
* - Complex expressions
|
|
9
|
+
* - Improved error handling and recovery
|
|
10
|
+
* - Performance optimizations
|
|
11
|
+
* - Better memory management
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
Token,
|
|
16
|
+
TokenType,
|
|
17
|
+
ConditionalError,
|
|
18
|
+
ErrorType,
|
|
19
|
+
} from "../types/ConditionalTypes";
|
|
20
|
+
|
|
21
|
+
export class ConditionalLexer {
|
|
22
|
+
private readonly _input: string;
|
|
23
|
+
private _position: number = 0;
|
|
24
|
+
private _line: number = 1;
|
|
25
|
+
private _column: number = 1;
|
|
26
|
+
private readonly _tokens: Token[] = [];
|
|
27
|
+
private readonly _errors: ConditionalError[] = [];
|
|
28
|
+
private _currentTokenStart: number = 0;
|
|
29
|
+
private _parenDepth: number = 0; // Track parentheses depth for method arguments
|
|
30
|
+
|
|
31
|
+
// Operator patterns for efficient matching (order matters - longest first!)
|
|
32
|
+
private static readonly _OPERATORS = new Map<string, TokenType>([
|
|
33
|
+
// Multi-character operators first
|
|
34
|
+
["!~", TokenType.NOT_MATCHES],
|
|
35
|
+
["!exists", TokenType.NOT_EXISTS],
|
|
36
|
+
["!empty", TokenType.NOT_EMPTY],
|
|
37
|
+
["!null", TokenType.NOT_NULL],
|
|
38
|
+
["!in", TokenType.NOT_IN],
|
|
39
|
+
["!contains", TokenType.NOT_CONTAINS],
|
|
40
|
+
[">=", TokenType.GREATER_EQUAL],
|
|
41
|
+
["<=", TokenType.LESS_EQUAL],
|
|
42
|
+
["!=", TokenType.NOT_EQUALS],
|
|
43
|
+
["==", TokenType.EQUALS],
|
|
44
|
+
["*?", TokenType.CONDITIONAL_THEN],
|
|
45
|
+
["&&", TokenType.AND],
|
|
46
|
+
["||", TokenType.OR],
|
|
47
|
+
// Single character operators
|
|
48
|
+
["=", TokenType.EQUALS],
|
|
49
|
+
[">", TokenType.GREATER_THAN],
|
|
50
|
+
["<", TokenType.LESS_THAN],
|
|
51
|
+
["~", TokenType.MATCHES],
|
|
52
|
+
["!", TokenType.NOT],
|
|
53
|
+
[":", TokenType.COLON],
|
|
54
|
+
["(", TokenType.LPAREN],
|
|
55
|
+
[")", TokenType.RPAREN],
|
|
56
|
+
["[", TokenType.LBRACKET],
|
|
57
|
+
["]", TokenType.RBRACKET],
|
|
58
|
+
[",", TokenType.COMMA],
|
|
59
|
+
[".", TokenType.DOT],
|
|
60
|
+
["|", TokenType.PIPE], // For regex alternation
|
|
61
|
+
["^", TokenType.CARET], // For regex start anchor
|
|
62
|
+
["$", TokenType.DOLLAR], // For regex end anchor
|
|
63
|
+
["@", TokenType.AT], // For email patterns
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
// Method patterns
|
|
67
|
+
private static readonly _METHODS = new Map<string, TokenType>([
|
|
68
|
+
["in", TokenType.IN],
|
|
69
|
+
["notIn", TokenType.NOT_IN],
|
|
70
|
+
["!in", TokenType.NOT_IN], // Support .!in() syntax
|
|
71
|
+
["exists", TokenType.EXISTS],
|
|
72
|
+
["notExists", TokenType.NOT_EXISTS],
|
|
73
|
+
["!exists", TokenType.NOT_EXISTS], // Support .!exists syntax
|
|
74
|
+
["empty", TokenType.EMPTY],
|
|
75
|
+
["!empty", TokenType.NOT_EMPTY], // Support .!empty syntax
|
|
76
|
+
["null", TokenType.NULL], // Support .null syntax
|
|
77
|
+
["!null", TokenType.NOT_NULL], // Support .!null syntax
|
|
78
|
+
["contains", TokenType.CONTAINS],
|
|
79
|
+
["notContains", TokenType.NOT_CONTAINS],
|
|
80
|
+
["!contains", TokenType.NOT_CONTAINS], // Support .!contains() syntax
|
|
81
|
+
["startsWith", TokenType.STARTS_WITH],
|
|
82
|
+
["endsWith", TokenType.ENDS_WITH],
|
|
83
|
+
["between", TokenType.BETWEEN],
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
// Keywords
|
|
87
|
+
private static readonly _KEYWORDS = new Map<string, TokenType>([
|
|
88
|
+
["when", TokenType.WHEN],
|
|
89
|
+
["true", TokenType.BOOLEAN],
|
|
90
|
+
["false", TokenType.BOOLEAN],
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
// Special characters that can appear in regex patterns
|
|
94
|
+
private static readonly _REGEX_SPECIAL_CHARS = new Set(["|", "^", "$", "@"]);
|
|
95
|
+
|
|
96
|
+
// Characters that should be treated as special in type syntax
|
|
97
|
+
private static readonly _TYPE_SYNTAX_CHARS = new Map<string, TokenType>([
|
|
98
|
+
["?", TokenType.UNKNOWN], // Will be handled as part of type syntax
|
|
99
|
+
["[", TokenType.LBRACKET],
|
|
100
|
+
["]", TokenType.RBRACKET],
|
|
101
|
+
["{", TokenType.LBRACE],
|
|
102
|
+
["}", TokenType.RBRACE],
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
// Whitespace characters
|
|
106
|
+
private static readonly _WHITESPACE_CHARS = new Set([" ", "\t", "\n", "\r"]);
|
|
107
|
+
|
|
108
|
+
// String quote characters
|
|
109
|
+
private static readonly _STRING_QUOTES = new Set(['"', "'"]);
|
|
110
|
+
|
|
111
|
+
// Escape sequence mappings
|
|
112
|
+
private static readonly _ESCAPE_SEQUENCES = new Map<string, string>([
|
|
113
|
+
["n", "\n"],
|
|
114
|
+
["t", "\t"],
|
|
115
|
+
["r", "\r"],
|
|
116
|
+
["\\", "\\"],
|
|
117
|
+
['"', '"'],
|
|
118
|
+
["'", "'"],
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
constructor(input: string) {
|
|
122
|
+
if (typeof input !== "string") {
|
|
123
|
+
throw new TypeError("Input must be a string");
|
|
124
|
+
}
|
|
125
|
+
this._input = input;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Tokenize the input string
|
|
130
|
+
*/
|
|
131
|
+
tokenize(): { tokens: Token[]; errors: ConditionalError[] } {
|
|
132
|
+
this._resetState();
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
while (!this._isAtEnd()) {
|
|
136
|
+
this._currentTokenStart = this._position;
|
|
137
|
+
this._scanToken();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Add EOF token
|
|
141
|
+
this._addToken(TokenType.EOF, "");
|
|
142
|
+
} catch (error) {
|
|
143
|
+
this._addError(
|
|
144
|
+
ErrorType.SYNTAX_ERROR,
|
|
145
|
+
`Unexpected error during tokenization: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
146
|
+
"Check the input syntax for correctness"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
tokens: [...this._tokens],
|
|
152
|
+
errors: [...this._errors],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Reset lexer state for reuse
|
|
158
|
+
*/
|
|
159
|
+
private _resetState(): void {
|
|
160
|
+
this._position = 0;
|
|
161
|
+
this._line = 1;
|
|
162
|
+
this._column = 1;
|
|
163
|
+
this._currentTokenStart = 0;
|
|
164
|
+
this._tokens.length = 0;
|
|
165
|
+
this._errors.length = 0;
|
|
166
|
+
this._parenDepth = 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Scan next token with improved error recovery
|
|
171
|
+
*/
|
|
172
|
+
private _scanToken(): void {
|
|
173
|
+
const char = this._advance();
|
|
174
|
+
|
|
175
|
+
// Skip whitespace efficiently
|
|
176
|
+
if (this._isWhitespace(char)) {
|
|
177
|
+
this._skipWhitespace();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Handle constant values (=value) ONLY in type definition contexts
|
|
182
|
+
// This should only trigger after *? operator, not in comparison contexts like role=admin
|
|
183
|
+
if (
|
|
184
|
+
char === "=" &&
|
|
185
|
+
this._peek() !== "=" &&
|
|
186
|
+
this._peek() !== "!" &&
|
|
187
|
+
this._isConstantContext()
|
|
188
|
+
) {
|
|
189
|
+
this._scanConstant();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Handle unquoted literals in method arguments BEFORE operators
|
|
194
|
+
if (this._parenDepth > 0 && this._isLiteralStartChar(char)) {
|
|
195
|
+
this._scanUnquotedLiteral();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Handle operators (multi-character first)
|
|
200
|
+
if (this._tryOperator()) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Handle strings
|
|
205
|
+
if (ConditionalLexer._STRING_QUOTES.has(char)) {
|
|
206
|
+
this._scanString(char);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Handle numbers (including negative numbers)
|
|
211
|
+
if (this._isDigit(char)) {
|
|
212
|
+
this._scanNumber();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Handle negative numbers (- followed by digit)
|
|
217
|
+
if (char === "-" && this._isDigit(this._peek())) {
|
|
218
|
+
this._scanNumber();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Handle identifiers and keywords
|
|
223
|
+
if (this._isAlpha(char)) {
|
|
224
|
+
this._scanIdentifier();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Handle method names that start with ! (like !exists, !empty) when after a dot
|
|
229
|
+
if (char === "!" && this._isAfterDotToken()) {
|
|
230
|
+
this._scanMethodName();
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Handle special characters that are part of type syntax
|
|
235
|
+
const typeToken = ConditionalLexer._TYPE_SYNTAX_CHARS.get(char);
|
|
236
|
+
if (typeToken) {
|
|
237
|
+
// Track parentheses depth for method argument parsing
|
|
238
|
+
if (char === "(") {
|
|
239
|
+
this._parenDepth++;
|
|
240
|
+
} else if (char === ")") {
|
|
241
|
+
this._parenDepth--;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
this._addToken(typeToken, char);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Handle forward slash patterns (like /secure/, /admin/)
|
|
249
|
+
if (char === "/" && this._isRegexSlashContext()) {
|
|
250
|
+
this._scanSlashPattern();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Handle regex patterns after ~ operator
|
|
255
|
+
if (this._isRegexContext()) {
|
|
256
|
+
this._scanRegexPattern();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Allow special regex characters in certain contexts
|
|
261
|
+
if (ConditionalLexer._REGEX_SPECIAL_CHARS.has(char)) {
|
|
262
|
+
this._addToken(this._getRegexCharToken(char), char);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Unknown character - add error but continue parsing
|
|
267
|
+
this._addError(
|
|
268
|
+
ErrorType.SYNTAX_ERROR,
|
|
269
|
+
`Unexpected character: '${char}'`,
|
|
270
|
+
`Remove or escape the character '${char}'`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Try to match multi-character operators with improved efficiency
|
|
276
|
+
*/
|
|
277
|
+
private _tryOperator(): boolean {
|
|
278
|
+
// Get remaining input from current position - 1 (since we already advanced)
|
|
279
|
+
const remaining = this._input.substring(this._position - 1);
|
|
280
|
+
|
|
281
|
+
if (remaining.length === 0) return false;
|
|
282
|
+
|
|
283
|
+
// Check if we're after a dot - if so, don't treat !exists/!empty as operators
|
|
284
|
+
const isAfterDot = this._isAfterDotToken();
|
|
285
|
+
|
|
286
|
+
for (const [op, tokenType] of ConditionalLexer._OPERATORS) {
|
|
287
|
+
if (remaining.startsWith(op)) {
|
|
288
|
+
// Skip !exists and !empty when after a dot (they should be method names)
|
|
289
|
+
if (
|
|
290
|
+
isAfterDot &&
|
|
291
|
+
(op === "!exists" ||
|
|
292
|
+
op === "!empty" ||
|
|
293
|
+
op === "!null" ||
|
|
294
|
+
op === "!in" ||
|
|
295
|
+
op === "!contains")
|
|
296
|
+
) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Advance position for multi-character operators
|
|
301
|
+
for (let i = 1; i < op.length; i++) {
|
|
302
|
+
this._advance();
|
|
303
|
+
}
|
|
304
|
+
this._addToken(tokenType, op);
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Check if the last token is a DOT token
|
|
314
|
+
*/
|
|
315
|
+
private _isAfterDotToken(): boolean {
|
|
316
|
+
return (
|
|
317
|
+
this._tokens.length > 0 &&
|
|
318
|
+
this._tokens[this._tokens.length - 1].type === TokenType.DOT
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Check if we're in a constant context (after *? operator in type definitions)
|
|
324
|
+
* This prevents treating comparison operators like role=admin as constants
|
|
325
|
+
*/
|
|
326
|
+
private _isConstantContext(): boolean {
|
|
327
|
+
if (this._tokens.length === 0) return false;
|
|
328
|
+
|
|
329
|
+
// Look for the *? (CONDITIONAL_THEN) token in recent tokens
|
|
330
|
+
// Constants should only appear after *? in patterns like "when condition *? =value : type"
|
|
331
|
+
for (
|
|
332
|
+
let i = this._tokens.length - 1;
|
|
333
|
+
i >= Math.max(0, this._tokens.length - 5);
|
|
334
|
+
i--
|
|
335
|
+
) {
|
|
336
|
+
const token = this._tokens[i];
|
|
337
|
+
|
|
338
|
+
// If we find *? operator, we're in a type definition context
|
|
339
|
+
if (token.type === TokenType.CONDITIONAL_THEN) {
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// If we find : (colon), we're past the constant context
|
|
344
|
+
if (token.type === TokenType.COLON) {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// If we find logical operators, we're in a condition context, not type context
|
|
349
|
+
if (token.type === TokenType.AND || token.type === TokenType.OR) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Check if character is an operator character that should stop identifier scanning
|
|
359
|
+
*/
|
|
360
|
+
private _isOperatorChar(char: string): boolean {
|
|
361
|
+
// Check if the character starts any operator
|
|
362
|
+
for (const [op] of ConditionalLexer._OPERATORS) {
|
|
363
|
+
if (op.startsWith(char)) {
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Scan string literal with improved escape handling
|
|
372
|
+
*/
|
|
373
|
+
private _scanString(quote: string): void {
|
|
374
|
+
let value = "";
|
|
375
|
+
const startLine = this._line;
|
|
376
|
+
const startColumn = this._column - 1;
|
|
377
|
+
|
|
378
|
+
while (!this._isAtEnd() && this._peek() !== quote) {
|
|
379
|
+
if (this._peek() === "\n") {
|
|
380
|
+
this._line++;
|
|
381
|
+
this._column = 1;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Handle escape sequences
|
|
385
|
+
if (this._peek() === "\\") {
|
|
386
|
+
this._advance(); // Skip backslash
|
|
387
|
+
|
|
388
|
+
if (this._isAtEnd()) {
|
|
389
|
+
this._addError(
|
|
390
|
+
ErrorType.SYNTAX_ERROR,
|
|
391
|
+
"Unterminated escape sequence in string",
|
|
392
|
+
`Add a character after \\ or close the string with ${quote}`
|
|
393
|
+
);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const escaped = this._advance();
|
|
398
|
+
const escapedValue = ConditionalLexer._ESCAPE_SEQUENCES.get(escaped);
|
|
399
|
+
|
|
400
|
+
if (escapedValue !== undefined) {
|
|
401
|
+
value += escapedValue;
|
|
402
|
+
} else {
|
|
403
|
+
// Unknown escape sequence - keep the character
|
|
404
|
+
value += escaped;
|
|
405
|
+
this._addError(
|
|
406
|
+
ErrorType.SYNTAX_ERROR,
|
|
407
|
+
`Unknown escape sequence: \\${escaped}`,
|
|
408
|
+
`Use a valid escape sequence or remove the backslash`
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
} else {
|
|
412
|
+
value += this._advance();
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (this._isAtEnd()) {
|
|
417
|
+
this._addError(
|
|
418
|
+
ErrorType.SYNTAX_ERROR,
|
|
419
|
+
`Unterminated string starting at line ${startLine}, column ${startColumn}`,
|
|
420
|
+
`Add closing ${quote} to complete the string`
|
|
421
|
+
);
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Consume closing quote
|
|
426
|
+
this._advance();
|
|
427
|
+
this._addToken(TokenType.STRING, value);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Scan numeric literal with improved validation
|
|
432
|
+
*/
|
|
433
|
+
private _scanNumber(): void {
|
|
434
|
+
let value = this._input[this._position - 1];
|
|
435
|
+
let hasDecimalPoint = false;
|
|
436
|
+
|
|
437
|
+
// If the first character is '-', we're scanning a negative number
|
|
438
|
+
const isNegative = value === "-";
|
|
439
|
+
|
|
440
|
+
// Scan integer part
|
|
441
|
+
while (this._isDigit(this._peek())) {
|
|
442
|
+
value += this._advance();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Handle decimal point
|
|
446
|
+
if (this._peek() === "." && this._isDigit(this._peekNext())) {
|
|
447
|
+
hasDecimalPoint = true;
|
|
448
|
+
value += this._advance(); // Consume '.'
|
|
449
|
+
|
|
450
|
+
while (this._isDigit(this._peek())) {
|
|
451
|
+
value += this._advance();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Validate number format
|
|
456
|
+
if (value === "." || value.endsWith(".") || value === "-") {
|
|
457
|
+
this._addError(
|
|
458
|
+
ErrorType.SYNTAX_ERROR,
|
|
459
|
+
"Invalid number format",
|
|
460
|
+
"Ensure the number has digits before and after the decimal point"
|
|
461
|
+
);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
this._addToken(TokenType.NUMBER, value);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Scan identifier, keyword, or method with improved logic
|
|
470
|
+
*/
|
|
471
|
+
private _scanIdentifier(): void {
|
|
472
|
+
let value = this._input[this._position - 1];
|
|
473
|
+
|
|
474
|
+
// Handle multi-byte Unicode characters (like emojis)
|
|
475
|
+
// FIXED: Stop at operator characters to prevent consuming "role=admin" as single token
|
|
476
|
+
while (
|
|
477
|
+
(this._isAlphaNumeric(this._peek()) || this._isEmojiContinuation()) &&
|
|
478
|
+
!this._isOperatorChar(this._peek())
|
|
479
|
+
) {
|
|
480
|
+
value += this._advance();
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Check if it's a keyword (case-insensitive)
|
|
484
|
+
const keywordType = ConditionalLexer._KEYWORDS.get(value.toLowerCase());
|
|
485
|
+
if (keywordType) {
|
|
486
|
+
this._addToken(keywordType, value);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Check if it's followed by a method call
|
|
491
|
+
if (this._peek() === ".") {
|
|
492
|
+
const methodName = this._peekMethodName();
|
|
493
|
+
if (methodName && ConditionalLexer._METHODS.has(methodName)) {
|
|
494
|
+
// This is a field access followed by a method
|
|
495
|
+
this._addToken(TokenType.IDENTIFIER, value);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
this._addToken(TokenType.IDENTIFIER, value);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Check if the current character is part of an emoji continuation
|
|
505
|
+
*/
|
|
506
|
+
private _isEmojiContinuation(): boolean {
|
|
507
|
+
const char = this._peek();
|
|
508
|
+
const code = char.charCodeAt(0);
|
|
509
|
+
|
|
510
|
+
// Low surrogate range (second part of emoji)
|
|
511
|
+
return code >= 0xdc00 && code <= 0xdfff;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Peek ahead to get the method name after a dot
|
|
516
|
+
*/
|
|
517
|
+
private _peekMethodName(): string | null {
|
|
518
|
+
const nextPos = this._position + 1;
|
|
519
|
+
if (nextPos >= this._input.length) return null;
|
|
520
|
+
|
|
521
|
+
let methodName = "";
|
|
522
|
+
let pos = nextPos;
|
|
523
|
+
|
|
524
|
+
// Handle methods that start with ! (like !exists, !empty)
|
|
525
|
+
if (pos < this._input.length && this._input[pos] === "!") {
|
|
526
|
+
methodName += this._input[pos];
|
|
527
|
+
pos++;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Scan the rest of the method name
|
|
531
|
+
while (pos < this._input.length && this._isAlphaNumeric(this._input[pos])) {
|
|
532
|
+
methodName += this._input[pos];
|
|
533
|
+
pos++;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return methodName || null;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Scan method name that starts with ! (like !exists, !empty)
|
|
541
|
+
*/
|
|
542
|
+
private _scanMethodName(): void {
|
|
543
|
+
let value = this._input[this._position - 1]; // Start with the '!' character
|
|
544
|
+
|
|
545
|
+
// Scan the rest of the method name
|
|
546
|
+
while (this._isAlphaNumeric(this._peek())) {
|
|
547
|
+
value += this._advance();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Check if it's a valid method name
|
|
551
|
+
const methodType = ConditionalLexer._METHODS.get(value);
|
|
552
|
+
if (methodType) {
|
|
553
|
+
this._addToken(TokenType.IDENTIFIER, value);
|
|
554
|
+
} else {
|
|
555
|
+
this._addError(
|
|
556
|
+
ErrorType.SYNTAX_ERROR,
|
|
557
|
+
`Unknown method: ${value}`,
|
|
558
|
+
`Check if the method name is correct. Valid methods include: ${Array.from(ConditionalLexer._METHODS.keys()).join(", ")}`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Scan constant value (=value syntax) with improved validation
|
|
565
|
+
*/
|
|
566
|
+
private _scanConstant(): void {
|
|
567
|
+
let value = "";
|
|
568
|
+
|
|
569
|
+
// Skip the '=' character (already consumed)
|
|
570
|
+
// Handle negative numbers by allowing minus sign at the start
|
|
571
|
+
if (this._peek() === "-") {
|
|
572
|
+
// Check if it's a negative number (- followed by digit or .)
|
|
573
|
+
const nextChar = this._peekNext();
|
|
574
|
+
if (this._isDigit(nextChar) || nextChar === ".") {
|
|
575
|
+
value += this._advance(); // consume '-'
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Check if this is an array or object literal
|
|
580
|
+
const isArrayLiteral = this._peek() === "[";
|
|
581
|
+
const isObjectLiteral = this._peek() === "{";
|
|
582
|
+
|
|
583
|
+
if (isArrayLiteral || isObjectLiteral) {
|
|
584
|
+
// Handle complex literals with bracket/brace matching
|
|
585
|
+
value += this._scanComplexLiteral();
|
|
586
|
+
} else {
|
|
587
|
+
// Handle simple constants (strings, numbers, booleans)
|
|
588
|
+
while (
|
|
589
|
+
!this._isAtEnd() &&
|
|
590
|
+
!this._isWhitespace(this._peek()) &&
|
|
591
|
+
this._peek() !== ":" &&
|
|
592
|
+
this._peek() !== ")" &&
|
|
593
|
+
this._peek() !== "]" &&
|
|
594
|
+
this._peek() !== ","
|
|
595
|
+
) {
|
|
596
|
+
value += this._advance();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (value.length === 0) {
|
|
601
|
+
this._addError(
|
|
602
|
+
ErrorType.SYNTAX_ERROR,
|
|
603
|
+
"Empty constant value after =",
|
|
604
|
+
"Provide a value after = (e.g., =admin, =true, =42, =-1, =[1,2,3])"
|
|
605
|
+
);
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
this._addToken(TokenType.CONSTANT, value);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Scan complex literal (array or object) with proper bracket/brace matching
|
|
614
|
+
*/
|
|
615
|
+
private _scanComplexLiteral(): string {
|
|
616
|
+
let value = "";
|
|
617
|
+
let depth = 0;
|
|
618
|
+
const startChar = this._peek();
|
|
619
|
+
const endChar = startChar === "[" ? "]" : "}";
|
|
620
|
+
|
|
621
|
+
// Consume the opening bracket/brace
|
|
622
|
+
value += this._advance();
|
|
623
|
+
depth++;
|
|
624
|
+
|
|
625
|
+
while (!this._isAtEnd() && depth > 0) {
|
|
626
|
+
const char = this._peek();
|
|
627
|
+
|
|
628
|
+
if (char === startChar) {
|
|
629
|
+
depth++;
|
|
630
|
+
} else if (char === endChar) {
|
|
631
|
+
depth--;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
value += this._advance();
|
|
635
|
+
|
|
636
|
+
// Stop at whitespace or conditional operators only if we're at depth 0
|
|
637
|
+
if (
|
|
638
|
+
depth === 0 &&
|
|
639
|
+
(this._isWhitespace(char) || char === ":" || char === "*")
|
|
640
|
+
) {
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return value;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Skip whitespace characters efficiently
|
|
650
|
+
*/
|
|
651
|
+
private _skipWhitespace(): void {
|
|
652
|
+
while (!this._isAtEnd() && this._isWhitespace(this._peek())) {
|
|
653
|
+
if (this._advance() === "\n") {
|
|
654
|
+
this._line++;
|
|
655
|
+
this._column = 1;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Check if we're in a regex context (after ~ or !~ operator)
|
|
662
|
+
*/
|
|
663
|
+
private _isRegexContext(): boolean {
|
|
664
|
+
if (this._tokens.length === 0) return false;
|
|
665
|
+
|
|
666
|
+
const lastToken = this._tokens[this._tokens.length - 1];
|
|
667
|
+
return (
|
|
668
|
+
lastToken.type === TokenType.MATCHES ||
|
|
669
|
+
lastToken.type === TokenType.NOT_MATCHES
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Check if we're in a context where forward slashes should be treated as regex delimiters
|
|
675
|
+
*/
|
|
676
|
+
private _isRegexSlashContext(): boolean {
|
|
677
|
+
if (this._tokens.length < 2) return false;
|
|
678
|
+
|
|
679
|
+
const lastToken = this._tokens[this._tokens.length - 1];
|
|
680
|
+
const secondLastToken = this._tokens[this._tokens.length - 2];
|
|
681
|
+
|
|
682
|
+
// Check if we're inside method arguments like .contains(/pattern/)
|
|
683
|
+
const regexMethodTypes = new Set([
|
|
684
|
+
TokenType.CONTAINS,
|
|
685
|
+
TokenType.NOT_CONTAINS,
|
|
686
|
+
TokenType.STARTS_WITH,
|
|
687
|
+
TokenType.ENDS_WITH,
|
|
688
|
+
]);
|
|
689
|
+
|
|
690
|
+
return (
|
|
691
|
+
lastToken.type === TokenType.LPAREN &&
|
|
692
|
+
regexMethodTypes.has(secondLastToken.type)
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Scan slash-delimited pattern (like /secure/, /admin/) with improved error handling
|
|
698
|
+
*/
|
|
699
|
+
private _scanSlashPattern(): void {
|
|
700
|
+
let pattern = "";
|
|
701
|
+
const startLine = this._line;
|
|
702
|
+
const startColumn = this._column - 1;
|
|
703
|
+
|
|
704
|
+
// Skip the opening slash (already consumed)
|
|
705
|
+
while (!this._isAtEnd() && this._peek() !== "/") {
|
|
706
|
+
if (this._peek() === "\n") {
|
|
707
|
+
this._line++;
|
|
708
|
+
this._column = 1;
|
|
709
|
+
}
|
|
710
|
+
pattern += this._advance();
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
if (this._peek() === "/") {
|
|
714
|
+
this._advance(); // Consume closing slash
|
|
715
|
+
this._addToken(TokenType.STRING, pattern);
|
|
716
|
+
} else {
|
|
717
|
+
this._addError(
|
|
718
|
+
ErrorType.SYNTAX_ERROR,
|
|
719
|
+
`Unterminated regex pattern starting at line ${startLine}, column ${startColumn}`,
|
|
720
|
+
"Add closing / to complete the pattern"
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Scan regex pattern (handles complex patterns with special characters)
|
|
727
|
+
*/
|
|
728
|
+
private _scanRegexPattern(): void {
|
|
729
|
+
let pattern = "";
|
|
730
|
+
let depth = 0;
|
|
731
|
+
|
|
732
|
+
while (!this._isAtEnd()) {
|
|
733
|
+
const char = this._peek();
|
|
734
|
+
|
|
735
|
+
// Stop at whitespace or conditional operators
|
|
736
|
+
if (this._isWhitespace(char) || char === "*" || char === ":") {
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Handle parentheses depth
|
|
741
|
+
if (char === "(") {
|
|
742
|
+
depth++;
|
|
743
|
+
} else if (char === ")") {
|
|
744
|
+
depth--;
|
|
745
|
+
if (depth < 0) break; // Unmatched closing paren
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
pattern += this._advance();
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if (pattern.length > 0) {
|
|
752
|
+
this._addToken(TokenType.REGEX_PATTERN, pattern);
|
|
753
|
+
} else {
|
|
754
|
+
this._addError(
|
|
755
|
+
ErrorType.SYNTAX_ERROR,
|
|
756
|
+
"Empty regex pattern",
|
|
757
|
+
"Provide a valid regex pattern after the ~ operator"
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Get token type for regex special characters
|
|
764
|
+
*/
|
|
765
|
+
private _getRegexCharToken(char: string): TokenType {
|
|
766
|
+
switch (char) {
|
|
767
|
+
case "|":
|
|
768
|
+
return TokenType.PIPE;
|
|
769
|
+
case "^":
|
|
770
|
+
return TokenType.CARET;
|
|
771
|
+
case "$":
|
|
772
|
+
return TokenType.DOLLAR;
|
|
773
|
+
case "@":
|
|
774
|
+
return TokenType.AT;
|
|
775
|
+
default:
|
|
776
|
+
return TokenType.UNKNOWN;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Utility methods with improved type safety
|
|
782
|
+
*/
|
|
783
|
+
private _advance(): string {
|
|
784
|
+
if (this._isAtEnd()) return "\0";
|
|
785
|
+
this._column++;
|
|
786
|
+
return this._input[this._position++];
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
private _peek(): string {
|
|
790
|
+
if (this._isAtEnd()) return "\0";
|
|
791
|
+
return this._input[this._position];
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
private _peekNext(): string {
|
|
795
|
+
if (this._position + 1 >= this._input.length) return "\0";
|
|
796
|
+
return this._input[this._position + 1];
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
private _isAtEnd(): boolean {
|
|
800
|
+
return this._position >= this._input.length;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
private _isWhitespace(char: string): boolean {
|
|
804
|
+
return ConditionalLexer._WHITESPACE_CHARS.has(char);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
private _isDigit(char: string): boolean {
|
|
808
|
+
return char >= "0" && char <= "9";
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
private _isAlpha(char: string): boolean {
|
|
812
|
+
return (
|
|
813
|
+
(char >= "a" && char <= "z") ||
|
|
814
|
+
(char >= "A" && char <= "Z") ||
|
|
815
|
+
char === "_" ||
|
|
816
|
+
this._isUnicodeAlpha(char)
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
private _isAlphaNumeric(char: string): boolean {
|
|
821
|
+
return this._isAlpha(char) || this._isDigit(char);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Check if character is Unicode alphabetic (for international identifiers)
|
|
826
|
+
*/
|
|
827
|
+
private _isUnicodeAlpha(char: string): boolean {
|
|
828
|
+
try {
|
|
829
|
+
// Enhanced Unicode support including emojis and symbols
|
|
830
|
+
return (
|
|
831
|
+
/\p{L}/u.test(char) || // Letters
|
|
832
|
+
/\p{Emoji}/u.test(char) || // Emojis
|
|
833
|
+
/\p{Symbol}/u.test(char) || // Symbols
|
|
834
|
+
/\p{Mark}/u.test(char) || // Combining marks
|
|
835
|
+
this._isEmojiCharacter(char) // Additional emoji detection
|
|
836
|
+
);
|
|
837
|
+
} catch (error) {
|
|
838
|
+
// Fallback for older environments
|
|
839
|
+
return this._isUnicodeAlphaFallback(char);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Enhanced emoji character detection
|
|
845
|
+
*/
|
|
846
|
+
private _isEmojiCharacter(char: string): boolean {
|
|
847
|
+
const code = char.charCodeAt(0);
|
|
848
|
+
|
|
849
|
+
// Common emoji ranges
|
|
850
|
+
return (
|
|
851
|
+
// Emoticons
|
|
852
|
+
(code >= 0x1f600 && code <= 0x1f64f) ||
|
|
853
|
+
// Miscellaneous Symbols and Pictographs
|
|
854
|
+
(code >= 0x1f300 && code <= 0x1f5ff) ||
|
|
855
|
+
// Transport and Map Symbols
|
|
856
|
+
(code >= 0x1f680 && code <= 0x1f6ff) ||
|
|
857
|
+
// Additional Symbols
|
|
858
|
+
(code >= 0x1f700 && code <= 0x1f77f) ||
|
|
859
|
+
// Geometric Shapes Extended
|
|
860
|
+
(code >= 0x1f780 && code <= 0x1f7ff) ||
|
|
861
|
+
// Supplemental Arrows-C
|
|
862
|
+
(code >= 0x1f800 && code <= 0x1f8ff) ||
|
|
863
|
+
// Supplemental Symbols and Pictographs
|
|
864
|
+
(code >= 0x1f900 && code <= 0x1f9ff) ||
|
|
865
|
+
// Chess Symbols
|
|
866
|
+
(code >= 0x1fa00 && code <= 0x1fa6f) ||
|
|
867
|
+
// Symbols and Pictographs Extended-A
|
|
868
|
+
(code >= 0x1fa70 && code <= 0x1faff) ||
|
|
869
|
+
// High surrogate range (for multi-byte emojis)
|
|
870
|
+
(code >= 0xd800 && code <= 0xdbff)
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Fallback Unicode detection for older environments
|
|
876
|
+
*/
|
|
877
|
+
private _isUnicodeAlphaFallback(char: string): boolean {
|
|
878
|
+
const code = char.charCodeAt(0);
|
|
879
|
+
return (
|
|
880
|
+
// Latin Extended
|
|
881
|
+
(code >= 0x00c0 && code <= 0x024f) ||
|
|
882
|
+
// Greek and Coptic
|
|
883
|
+
(code >= 0x0370 && code <= 0x03ff) ||
|
|
884
|
+
// Cyrillic
|
|
885
|
+
(code >= 0x0400 && code <= 0x04ff) ||
|
|
886
|
+
// CJK (Chinese, Japanese, Korean)
|
|
887
|
+
(code >= 0x4e00 && code <= 0x9fff) ||
|
|
888
|
+
// Arabic
|
|
889
|
+
(code >= 0x0600 && code <= 0x06ff) ||
|
|
890
|
+
// Hebrew
|
|
891
|
+
(code >= 0x0590 && code <= 0x05ff) ||
|
|
892
|
+
// Basic emoji ranges
|
|
893
|
+
(code >= 0x1f300 && code <= 0x1f9ff) ||
|
|
894
|
+
// High surrogate range
|
|
895
|
+
(code >= 0xd800 && code <= 0xdbff)
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Add token to the list with improved position tracking
|
|
901
|
+
*/
|
|
902
|
+
private _addToken(type: TokenType, value: string): void {
|
|
903
|
+
this._tokens.push({
|
|
904
|
+
type,
|
|
905
|
+
value,
|
|
906
|
+
position: this._currentTokenStart,
|
|
907
|
+
line: this._line,
|
|
908
|
+
column: this._column - value.length,
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Add error to the list with improved context
|
|
914
|
+
*/
|
|
915
|
+
private _addError(
|
|
916
|
+
type: ErrorType,
|
|
917
|
+
message: string,
|
|
918
|
+
suggestion?: string
|
|
919
|
+
): void {
|
|
920
|
+
this._errors.push({
|
|
921
|
+
type,
|
|
922
|
+
message,
|
|
923
|
+
position: this._currentTokenStart,
|
|
924
|
+
line: this._line,
|
|
925
|
+
column: this._column - (this._position - this._currentTokenStart),
|
|
926
|
+
suggestion,
|
|
927
|
+
context: {
|
|
928
|
+
nearbyTokens: this._tokens.slice(-3), // Last 3 tokens for context
|
|
929
|
+
expectedTokens: [], // Will be filled by parser
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Check if character can start an unquoted literal in method arguments
|
|
936
|
+
*/
|
|
937
|
+
private _isLiteralStartChar(char: string): boolean {
|
|
938
|
+
// Allow letters, digits, and common special characters as literal starts
|
|
939
|
+
return (
|
|
940
|
+
this._isAlphaNumeric(char) ||
|
|
941
|
+
char === "!" ||
|
|
942
|
+
char === "@" ||
|
|
943
|
+
char === "#" ||
|
|
944
|
+
char === "$" ||
|
|
945
|
+
char === "%" ||
|
|
946
|
+
char === "^" ||
|
|
947
|
+
char === "&" ||
|
|
948
|
+
char === "*" ||
|
|
949
|
+
char === "+" ||
|
|
950
|
+
char === "=" ||
|
|
951
|
+
char === "|" ||
|
|
952
|
+
char === "\\" ||
|
|
953
|
+
char === ":" ||
|
|
954
|
+
char === ";" ||
|
|
955
|
+
char === "<" ||
|
|
956
|
+
char === ">" ||
|
|
957
|
+
char === "?" ||
|
|
958
|
+
char === "/" ||
|
|
959
|
+
char === "~" ||
|
|
960
|
+
char === "`" ||
|
|
961
|
+
char === "[" ||
|
|
962
|
+
char === "]" ||
|
|
963
|
+
char === "{" ||
|
|
964
|
+
char === "}" ||
|
|
965
|
+
char === "_" ||
|
|
966
|
+
char === "-" ||
|
|
967
|
+
char === "."
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Scan unquoted literal in method arguments
|
|
973
|
+
*/
|
|
974
|
+
private _scanUnquotedLiteral(): void {
|
|
975
|
+
let value = this._input[this._position - 1];
|
|
976
|
+
|
|
977
|
+
// Continue scanning until we hit a delimiter
|
|
978
|
+
while (
|
|
979
|
+
!this._isAtEnd() &&
|
|
980
|
+
!this._isWhitespace(this._peek()) &&
|
|
981
|
+
this._peek() !== "," &&
|
|
982
|
+
this._peek() !== ")" &&
|
|
983
|
+
this._peek() !== "("
|
|
984
|
+
) {
|
|
985
|
+
value += this._advance();
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if (value.length > 0) {
|
|
989
|
+
this._addToken(TokenType.STRING, value);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|