-
Notifications
You must be signed in to change notification settings - Fork 0
feat(typebox): improve handling of large union types #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { Node, ts } from 'ts-morph' | ||
|
|
||
| export abstract class BaseTypeHandler { | ||
| abstract canHandle(node: Node): boolean | ||
| abstract handle(node: Node): ts.Expression | ||
| abstract handle(node: Node, context: TypeBoxContext): ts.Expression | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,17 @@ | ||
| import { CollectionBaseHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/collection/collection-base-handler' | ||
| import { GenericTypeUtils } from '@daxserver/validation-schema-codegen/utils/generic-type-utils' | ||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { getTypeBoxType } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { makeTypeCall } from '@daxserver/validation-schema-codegen/utils/typebox-codegen-utils' | ||
| import { ArrayTypeNode, Node, ts } from 'ts-morph' | ||
|
|
||
| export class ArrayTypeHandler extends CollectionBaseHandler { | ||
| canHandle(node: Node): boolean { | ||
| return Node.isArrayTypeNode(node) | ||
| } | ||
|
|
||
| handle(node: ArrayTypeNode): ts.Expression { | ||
| const typeboxType = getTypeBoxType(node.getElementTypeNode()) | ||
| handle(node: ArrayTypeNode, context: TypeBoxContext): ts.Expression { | ||
| const typeboxType = getTypeBoxType(node.getElementTypeNode(), context) | ||
|
|
||
| return makeTypeCall('Array', [typeboxType]) | ||
| return GenericTypeUtils.makeTypeCall('Array', [typeboxType]) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,18 @@ | ||
| import { BaseTypeHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/base-type-handler' | ||
| import { GenericTypeUtils } from '@daxserver/validation-schema-codegen/utils/generic-type-utils' | ||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { getTypeBoxType } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { makeTypeCall } from '@daxserver/validation-schema-codegen/utils/typebox-codegen-utils' | ||
| import { Node, ts } from 'ts-morph' | ||
|
|
||
| export abstract class CollectionBaseHandler extends BaseTypeHandler { | ||
| protected processTypeCollection(nodes: Node[], typeBoxFunction: string): ts.Expression { | ||
| const typeBoxTypes = nodes.map((node) => getTypeBoxType(node)) | ||
| protected processTypeCollection( | ||
| nodes: Node[], | ||
| typeBoxFunction: string, | ||
| context: TypeBoxContext, | ||
| ): ts.Expression { | ||
| const typeBoxTypes = nodes.map((node) => getTypeBoxType(node, context)) | ||
| const arrayLiteral = ts.factory.createArrayLiteralExpression(typeBoxTypes) | ||
|
|
||
| return makeTypeCall(typeBoxFunction, [arrayLiteral]) | ||
| return GenericTypeUtils.makeTypeCall(typeBoxFunction, [arrayLiteral]) | ||
| } | ||
|
Comment on lines
+8
to
17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainGuard against empty collections (defensive). 🏁 Script executed: #!/bin/bash
# List all call sites to ensure `nodes.length > 0` is enforced upstream
rg -nP --type=ts -C2 '\bprocessTypeCollection\s*\(' src/handlersLength of output: 1954 Guard empty collections in 🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,13 @@ | ||
| import { CollectionBaseHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/collection/collection-base-handler' | ||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { IntersectionTypeNode, Node, ts } from 'ts-morph' | ||
|
|
||
| export class IntersectionTypeHandler extends CollectionBaseHandler { | ||
| canHandle(node: Node): boolean { | ||
| return Node.isIntersectionTypeNode(node) | ||
| } | ||
|
|
||
| handle(node: IntersectionTypeNode): ts.Expression { | ||
| return this.processTypeCollection(node.getTypeNodes(), 'Intersect') | ||
| handle(node: IntersectionTypeNode, context: TypeBoxContext): ts.Expression { | ||
| return this.processTypeCollection(node.getTypeNodes(), 'Intersect', context) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,14 @@ | ||
| import { CollectionBaseHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/collection/collection-base-handler' | ||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { Node, ts, TupleTypeNode } from 'ts-morph' | ||
|
|
||
| export class TupleTypeHandler extends CollectionBaseHandler { | ||
| canHandle(node: Node): boolean { | ||
| return Node.isTupleTypeNode(node) | ||
| } | ||
|
|
||
| handle(node: TupleTypeNode): ts.Expression { | ||
| return this.processTypeCollection(node.getElements(), 'Tuple') | ||
| handle(node: TupleTypeNode, context: TypeBoxContext): ts.Expression { | ||
| const elements = node.getElements() | ||
| return this.processTypeCollection(elements, 'Tuple', context) | ||
|
Comment on lines
+10
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainContext-plumbed Tuple handler looks correct; verify all call sites pass context The signature and forwarding into processTypeCollection are consistent with the new context-aware API. Run to catch any remaining handlers/call-sites missing the context param: 🏁 Script executed: #!/bin/bash
# 1) Handlers without a `context: TypeBoxContext` param
rg -nP --type=ts '\bhandle\s*\(\s*[^)]*\)' src/handlers/typebox | rg -nPv 'context\s*:\s*TypeBoxContext' || true
# 2) processTypeCollection calls lacking the context arg
rg -nP --type=ts 'processTypeCollection\([^,]+,\s*["'\''](Tuple|Array|Intersect|Union)["'\'']\s*\)' src/handlers/typebox || trueLength of output: 995 Add missing
Update each signature to 🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,14 @@ | ||
| import { CollectionBaseHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/collection/collection-base-handler' | ||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { Node, ts, UnionTypeNode } from 'ts-morph' | ||
|
|
||
| export class UnionTypeHandler extends CollectionBaseHandler { | ||
| canHandle(node: Node): boolean { | ||
| return Node.isUnionTypeNode(node) | ||
| } | ||
|
|
||
| handle(node: UnionTypeNode): ts.Expression { | ||
| return this.processTypeCollection(node.getTypeNodes(), 'Union') | ||
| handle(node: UnionTypeNode, context: TypeBoxContext): ts.Expression { | ||
| const types = node.getTypeNodes() | ||
| return this.processTypeCollection(types, 'Union', context) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||||||||||||||||||
| import { BaseTypeHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/base-type-handler' | ||||||||||||||||||||||||||
| import { makeTypeCall } from '@daxserver/validation-schema-codegen/utils/typebox-codegen-utils' | ||||||||||||||||||||||||||
| import { GenericTypeUtils } from '@daxserver/validation-schema-codegen/utils/generic-type-utils' | ||||||||||||||||||||||||||
| import { Node, ts, TypeReferenceNode } from 'ts-morph' | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export class DateTypeHandler extends BaseTypeHandler { | ||||||||||||||||||||||||||
|
|
@@ -10,6 +10,6 @@ export class DateTypeHandler extends BaseTypeHandler { | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| handle(): ts.Expression { | ||||||||||||||||||||||||||
| return makeTypeCall('Date') | ||||||||||||||||||||||||||
| return GenericTypeUtils.makeTypeCall('Date') | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
Comment on lines
12
to
14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. handle signature must accept (node, context). Apply: +import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call'
@@
- handle(): ts.Expression {
+ handle(_node: TypeReferenceNode, _context: TypeBoxContext): ts.Expression {
return GenericTypeUtils.makeTypeCall('Date')
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,35 +1,36 @@ | ||||||
| import { BaseTypeHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/base-type-handler' | ||||||
| import { GenericTypeUtils } from '@daxserver/validation-schema-codegen/utils/generic-type-utils' | ||||||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||||||
| import { getTypeBoxType } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||||||
| import { makeTypeCall } from '@daxserver/validation-schema-codegen/utils/typebox-codegen-utils' | ||||||
| import { FunctionTypeNode, Node, ts } from 'ts-morph' | ||||||
|
|
||||||
| export class FunctionTypeHandler extends BaseTypeHandler { | ||||||
| canHandle(node: Node): boolean { | ||||||
| return Node.isFunctionTypeNode(node) | ||||||
| } | ||||||
|
|
||||||
| handle(node: FunctionTypeNode): ts.Expression { | ||||||
| handle(node: FunctionTypeNode, context: TypeBoxContext): ts.Expression { | ||||||
| const parameters = node.getParameters() | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exclude
Apply this diff: - const parameters = node.getParameters()
+ const parameters = node.getParameters().filter((p) => !p.isThisParameter())📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| const returnType = node.getReturnTypeNode() | ||||||
|
|
||||||
| // Convert parameters to TypeBox types | ||||||
| const parameterTypes = parameters.map((param) => { | ||||||
| const paramTypeNode = param.getTypeNode() | ||||||
| const paramType = getTypeBoxType(paramTypeNode) | ||||||
| const paramType = getTypeBoxType(paramTypeNode, context) | ||||||
|
|
||||||
| // Check if parameter is optional | ||||||
| if (param.hasQuestionToken()) { | ||||||
| return makeTypeCall('Optional', [paramType]) | ||||||
| return GenericTypeUtils.makeTypeCall('Optional', [paramType]) | ||||||
| } | ||||||
|
|
||||||
| return paramType | ||||||
| }) | ||||||
|
|
||||||
| // Convert return type to TypeBox type | ||||||
| const returnTypeBox = getTypeBoxType(returnType) | ||||||
| const returnTypeBox = getTypeBoxType(returnType, context) | ||||||
|
|
||||||
| // Create TypeBox Function call with parameters array and return type | ||||||
| return makeTypeCall('Function', [ | ||||||
| return GenericTypeUtils.makeTypeCall('Function', [ | ||||||
| ts.factory.createArrayLiteralExpression(parameterTypes), | ||||||
| returnTypeBox, | ||||||
| ]) | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,15 @@ | ||
| import { BaseTypeHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/base-type-handler' | ||
| import { GenericTypeUtils } from '@daxserver/validation-schema-codegen/utils/generic-type-utils' | ||
| import type { TypeBoxContext } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { getTypeBoxType } from '@daxserver/validation-schema-codegen/utils/typebox-call' | ||
| import { makeTypeCall } from '@daxserver/validation-schema-codegen/utils/typebox-codegen-utils' | ||
| import { IndexedAccessTypeNode, Node, ts, TypeNode } from 'ts-morph' | ||
|
|
||
| export class IndexedAccessTypeHandler extends BaseTypeHandler { | ||
| canHandle(node: Node): boolean { | ||
| return node.isKind(ts.SyntaxKind.IndexedAccessType) | ||
| } | ||
|
|
||
| handle(node: IndexedAccessTypeNode): ts.Expression { | ||
| handle(node: IndexedAccessTypeNode, context: TypeBoxContext): ts.Expression { | ||
| const objectType = node.getObjectTypeNode() | ||
| const indexType = node.getIndexTypeNode() | ||
|
|
||
|
|
@@ -17,18 +18,19 @@ export class IndexedAccessTypeHandler extends BaseTypeHandler { | |
| objectType.isKind(ts.SyntaxKind.TypeQuery) && | ||
| indexType.isKind(ts.SyntaxKind.NumberKeyword) | ||
| ) { | ||
| return this.handleTypeofArrayAccess(objectType, node) | ||
| return this.handleTypeofArrayAccess(objectType, node, context) | ||
| } | ||
|
|
||
| const typeboxObjectType = getTypeBoxType(objectType) | ||
| const typeboxIndexType = getTypeBoxType(indexType) | ||
| const typeboxObjectType = getTypeBoxType(objectType, context) | ||
| const typeboxIndexType = getTypeBoxType(indexType, context) | ||
|
|
||
| return makeTypeCall('Index', [typeboxObjectType, typeboxIndexType]) | ||
| return GenericTypeUtils.makeTypeCall('Index', [typeboxObjectType, typeboxIndexType]) | ||
| } | ||
|
|
||
| private handleTypeofArrayAccess( | ||
| typeQuery: Node, | ||
| indexedAccessType: IndexedAccessTypeNode, | ||
| context: TypeBoxContext, | ||
| ): ts.Expression { | ||
| const typeQueryNode = typeQuery.asKindOrThrow(ts.SyntaxKind.TypeQuery) | ||
| const exprName = typeQueryNode.getExprName() | ||
|
|
@@ -54,10 +56,10 @@ export class IndexedAccessTypeHandler extends BaseTypeHandler { | |
| } | ||
|
|
||
| // Fallback to default Index behavior | ||
| const typeboxObjectType = getTypeBoxType(typeQuery) | ||
| const typeboxIndexType = getTypeBoxType(indexedAccessType.getIndexTypeNode()) | ||
| const typeboxObjectType = getTypeBoxType(typeQuery, context) | ||
| const typeboxIndexType = getTypeBoxType(indexedAccessType.getIndexTypeNode(), context) | ||
|
|
||
| return makeTypeCall('Index', [typeboxObjectType, typeboxIndexType]) | ||
| return GenericTypeUtils.makeTypeCall('Index', [typeboxObjectType, typeboxIndexType]) | ||
| } | ||
|
|
||
| private extractTupleUnion(typeNode: TypeNode | undefined): ts.Expression | null { | ||
|
|
@@ -86,14 +88,18 @@ export class IndexedAccessTypeHandler extends BaseTypeHandler { | |
| if (literal.isKind(ts.SyntaxKind.StringLiteral)) { | ||
| const stringLiteral = literal.asKindOrThrow(ts.SyntaxKind.StringLiteral) | ||
| const value = stringLiteral.getLiteralValue() | ||
| literalTypes.push(makeTypeCall('Literal', [ts.factory.createStringLiteral(value)])) | ||
| literalTypes.push( | ||
| GenericTypeUtils.makeTypeCall('Literal', [ts.factory.createStringLiteral(value)]), | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Return union of literal types if we found any | ||
| if (literalTypes.length > 0) { | ||
| return makeTypeCall('Union', [ts.factory.createArrayLiteralExpression(literalTypes)]) | ||
| return GenericTypeUtils.makeTypeCall('Union', [ | ||
| ts.factory.createArrayLiteralExpression(literalTypes), | ||
| ]) | ||
| } | ||
|
Comment on lines
98
to
103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainAvoid bypassing union chunking in typeof A[number] fast-path Constructing Type.Union([...]) directly here will skip the new shouldChunkUnion/createChunkNodes flow, defeating the PR’s goal on large const tuples (e.g., >20 elements). Route this union construction through the same union/chunking pipeline (e.g., a small helper that consults shouldChunkUnion and registers chunk nodes via context.nodeGraph), or delegate to the union handler. Add/adjust an integration test with a large readonly tuple (e.g., 100 string literals) accessed via typeof A[number] and assert chunk types are emitted rather than a monolithic union expression. 🏁 Script executed: #!/bin/bash
set -e
# Search for chunking utilities
rg -n 'shouldChunkUnion' -C3 || true
rg -n 'createChunkNodes' -C3 || true
# Inspect GenericTypeUtils.makeTypeCall usage
rg -n 'GenericTypeUtils\.makeTypeCall' -C3 || true
# Locate the union handler implementation
rg -n 'handleUnion' -g 'src/handlers/typebox/*-handler.ts' -C3 || trueLength of output: 33962 Pipe union creation through the chunking pipeline in
🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||||
| import { BaseTypeHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/base-type-handler' | ||||||||||||
| import { makeTypeCall } from '@daxserver/validation-schema-codegen/utils/typebox-codegen-utils' | ||||||||||||
| import { GenericTypeUtils } from '@daxserver/validation-schema-codegen/utils/generic-type-utils' | ||||||||||||
| import { Node, ts, TypeOperatorTypeNode, VariableDeclaration } from 'ts-morph' | ||||||||||||
|
|
||||||||||||
| export class KeyOfTypeofHandler extends BaseTypeHandler { | ||||||||||||
|
|
@@ -13,13 +13,13 @@ export class KeyOfTypeofHandler extends BaseTypeHandler { | |||||||||||
|
|
||||||||||||
| handle(node: TypeOperatorTypeNode): ts.Expression { | ||||||||||||
| const typeQuery = node.getTypeNode() | ||||||||||||
|
Comment on lines
14
to
15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handler signature missing context parameter — likely breaks getTypeBoxType caller contract. getTypeBoxType invokes handlers as handle(node, context). This override lacks the second parameter, which can cause a type error or silent loss of context. Add the context arg (even if unused for now). - handle(node: TypeOperatorTypeNode): ts.Expression {
+ handle(node: TypeOperatorTypeNode, _context: unknown): ts.Expression {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
| if (!Node.isTypeQuery(typeQuery)) return makeTypeCall('Any') | ||||||||||||
| if (!Node.isTypeQuery(typeQuery)) return GenericTypeUtils.makeTypeCall('Any') | ||||||||||||
|
|
||||||||||||
| const exprName = typeQuery.getExprName() | ||||||||||||
| if (!Node.isIdentifier(exprName)) return makeTypeCall('Any') | ||||||||||||
| if (!Node.isIdentifier(exprName)) return GenericTypeUtils.makeTypeCall('Any') | ||||||||||||
|
|
||||||||||||
| const keys = this.getObjectKeys(exprName) | ||||||||||||
| return keys.length > 0 ? this.createUnion(keys) : makeTypeCall('Any') | ||||||||||||
| return keys.length > 0 ? this.createUnion(keys) : GenericTypeUtils.makeTypeCall('Any') | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| private getObjectKeys(node: Node): string[] { | ||||||||||||
|
|
@@ -80,11 +80,11 @@ export class KeyOfTypeofHandler extends BaseTypeHandler { | |||||||||||
| ? ts.factory.createNumericLiteral(num) | ||||||||||||
| : ts.factory.createStringLiteral(key) | ||||||||||||
|
|
||||||||||||
| return makeTypeCall('Literal', [literal]) | ||||||||||||
| return GenericTypeUtils.makeTypeCall('Literal', [literal]) | ||||||||||||
| }) | ||||||||||||
|
|
||||||||||||
| return literals.length === 1 | ||||||||||||
| ? literals[0]! | ||||||||||||
| : makeTypeCall('Union', [ts.factory.createArrayLiteralExpression(literals)]) | ||||||||||||
| : GenericTypeUtils.makeTypeCall('Union', [ts.factory.createArrayLiteralExpression(literals)]) | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { BaseTypeHandler } from '@daxserver/validation-schema-codegen/handlers/typebox/base-type-handler' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { makeTypeCall } from '@daxserver/validation-schema-codegen/utils/typebox-codegen-utils' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { GenericTypeUtils } from '@daxserver/validation-schema-codegen/utils/generic-type-utils' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { LiteralTypeNode, Node, SyntaxKind, ts } from 'ts-morph' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export class LiteralTypeHandler extends BaseTypeHandler { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -12,19 +12,21 @@ export class LiteralTypeHandler extends BaseTypeHandler { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch (literal.getKind()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case SyntaxKind.StringLiteral: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return makeTypeCall('Literal', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return GenericTypeUtils.makeTypeCall('Literal', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ts.factory.createStringLiteral(literal.getText().slice(1, -1)), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case SyntaxKind.NumericLiteral: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return makeTypeCall('Literal', [ts.factory.createNumericLiteral(literal.getText())]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return GenericTypeUtils.makeTypeCall('Literal', [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ts.factory.createNumericLiteral(literal.getText()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case SyntaxKind.TrueKeyword: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return makeTypeCall('Literal', [ts.factory.createTrue()]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return GenericTypeUtils.makeTypeCall('Literal', [ts.factory.createTrue()]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case SyntaxKind.FalseKeyword: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return makeTypeCall('Literal', [ts.factory.createFalse()]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return GenericTypeUtils.makeTypeCall('Literal', [ts.factory.createFalse()]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case SyntaxKind.NullKeyword: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return makeTypeCall('Null') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return GenericTypeUtils.makeTypeCall('Null') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return makeTypeCall('Any') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return GenericTypeUtils.makeTypeCall('Any') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
13
to
30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Support BigInt and negative numeric literal types BigInt (123n) and negative numbers (-1, -123n) currently fall through to Any. Add explicit handling. switch (literal.getKind()) {
case SyntaxKind.StringLiteral:
return GenericTypeUtils.makeTypeCall('Literal', [
ts.factory.createStringLiteral(literal.getText().slice(1, -1)),
])
case SyntaxKind.NumericLiteral:
return GenericTypeUtils.makeTypeCall('Literal', [
ts.factory.createNumericLiteral(literal.getText()),
])
+ case SyntaxKind.BigIntLiteral:
+ return GenericTypeUtils.makeTypeCall('Literal', [
+ ts.factory.createBigIntLiteral(literal.getText()),
+ ])
+ case SyntaxKind.PrefixUnaryExpression: {
+ if (Node.isPrefixUnaryExpression(literal)) {
+ const operand = literal.getOperand()
+ const op = literal.getOperatorToken()
+ if (op === SyntaxKind.MinusToken && Node.isNumericLiteral(operand)) {
+ const expr = ts.factory.createPrefixUnaryExpression(
+ ts.SyntaxKind.MinusToken,
+ ts.factory.createNumericLiteral(operand.getText()),
+ )
+ return GenericTypeUtils.makeTypeCall('Literal', [expr])
+ }
+ if (op === SyntaxKind.MinusToken && Node.isBigIntLiteral(operand)) {
+ const expr = ts.factory.createPrefixUnaryExpression(
+ ts.SyntaxKind.MinusToken,
+ ts.factory.createBigIntLiteral(operand.getText()),
+ )
+ return GenericTypeUtils.makeTypeCall('Literal', [expr])
+ }
+ }
+ break
+ }
case SyntaxKind.TrueKeyword:
return GenericTypeUtils.makeTypeCall('Literal', [ts.factory.createTrue()])
case SyntaxKind.FalseKeyword:
return GenericTypeUtils.makeTypeCall('Literal', [ts.factory.createFalse()])
case SyntaxKind.NullKeyword:
return GenericTypeUtils.makeTypeCall('Null')
default:
return GenericTypeUtils.makeTypeCall('Any')
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Abstract signature update looks correct; this is a breaking change—verify all subclasses.
Good use of a type-only import. Please ensure all handlers now implement (node, context).
Run to find handlers missing a context parameter:
🏁 Script executed:
Length of output: 7830
Ensure all handlers implement the updated handle(node, context) signature
The following subclasses of BaseTypeHandler still use the old
handle(...)signature and must be updated tohandle(node: X, context: TypeBoxContext): ts.Expression:🤖 Prompt for AI Agents