Skip to content

Commit 34b637c

Browse files
committed
chore: wip
1 parent ece5654 commit 34b637c

File tree

2 files changed

+46
-36
lines changed

2 files changed

+46
-36
lines changed

fixtures/output/variable.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ export declare const complexArrays: {
7676
Array<'a' | 'b' | Array<'c' | 'd'>> |
7777
Array<true | Array<false | Array<true>>>
7878
>;
79-
tuples: Array<
79+
tuples: readonly [
8080
readonly [1, 'string', true] |
8181
readonly ['literal', 42, false]
82-
>;
82+
];
8383
mixedArrays: Array<
8484
unknown |
8585
unknown |
@@ -105,7 +105,7 @@ export declare const CONFIG_MAP: {
105105
development: {
106106
features: {
107107
auth: {
108-
providers: Array<'google' | 'github'] as cons>;
108+
providers: readonly ['google', unknown];
109109
settings: {
110110
timeout: 5000;
111111
retries: 3
@@ -116,7 +116,7 @@ export declare const CONFIG_MAP: {
116116
production: {
117117
features: {
118118
auth: {
119-
providers: Array<'google' | 'github' | 'microsoft'] as cons>;
119+
providers: readonly ['google', 'github', unknown];
120120
settings: {
121121
timeout: 3000;
122122
retries: 5

src/extract.ts

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ function cleanParameterTypes(params: string): string {
4141
depth--
4242
}
4343
else if (char === ',' && depth === 0) {
44+
if (currentParam.trim().endsWith('as const')) {
45+
currentParam = currentParam.slice(0, currentParam.indexOf('as const')).trim()
46+
}
4447
cleanParams.push(cleanParameter(currentParam.trim()))
4548
currentParam = ''
4649
continue
@@ -51,6 +54,9 @@ function cleanParameterTypes(params: string): string {
5154
}
5255

5356
if (currentParam.trim()) {
57+
if (currentParam.trim().endsWith('as const')) {
58+
currentParam = currentParam.slice(0, currentParam.indexOf('as const')).trim()
59+
}
5460
cleanParams.push(cleanParameter(currentParam.trim()))
5561
}
5662

@@ -612,8 +618,10 @@ function inferArrayType(value: string, state?: ProcessingState, indentLevel = 0)
612618
debugLog(state, 'infer-array-value', `Input value:\n${value}`)
613619

614620
const content = value.slice(1, -1).trim()
621+
const isConstAssertion = value.trim().endsWith('as const')
622+
615623
if (!content)
616-
return 'unknown[]'
624+
return isConstAssertion ? 'readonly unknown[]' : 'unknown[]'
617625

618626
const baseIndent = ' '.repeat(indentLevel)
619627
debugLog(state, 'infer-array-indent', `Base indent="${baseIndent}"`)
@@ -624,11 +632,14 @@ function inferArrayType(value: string, state?: ProcessingState, indentLevel = 0)
624632
const allConstTuples = elements.every(el => el.trim().endsWith('as const'))
625633
debugLog(state, 'array-tuples', `All const tuples: ${allConstTuples}`)
626634

627-
if (allConstTuples) {
635+
// Handle const assertions
636+
if (isConstAssertion || allConstTuples || content.includes('as const')) {
628637
const tuples = elements.map((el) => {
629-
const tupleContent = el.slice(0, el.indexOf('as const')).trim()
630-
debugLog(state, 'const-tuple', `Processing const tuple: ${tupleContent}`)
631-
return inferConstArrayType(tupleContent, state)
638+
const cleaned = el.trim().endsWith('as const')
639+
? el.slice(0, el.indexOf('as const')).trim()
640+
: el.trim()
641+
debugLog(state, 'const-tuple', `Processing const tuple: ${cleaned}`)
642+
return inferConstArrayType(cleaned, state)
632643
})
633644
debugLog(state, 'const-tuple', `Tuples inferred: ${tuples}`)
634645

@@ -637,10 +648,10 @@ function inferArrayType(value: string, state?: ProcessingState, indentLevel = 0)
637648
const isLast = i === tuples.length - 1
638649
return indentMultilineType(type, `${baseIndent} `, isLast)
639650
}).join('\n')
640-
return `Array<\n${formattedContent}\n${baseIndent}>`
651+
return `readonly [\n${formattedContent}\n${baseIndent}]`
641652
}
642653

643-
return `Array<${tuples.join(' | ')}>`
654+
return `readonly [${tuples.join(', ')}]`
644655
}
645656

646657
const elementTypes = elements.map((element, index) => {
@@ -720,6 +731,11 @@ function inferComplexObjectType(value: string, state?: ProcessingState, indentLe
720731
function inferConstArrayType(value: string, state?: ProcessingState): string {
721732
debugLog(state, 'infer-const', `Inferring const array type for: ${value}`)
722733

734+
// For string literals, return them directly
735+
if (/^['"`].*['"`]$/.test(value)) {
736+
return value // Return the literal directly
737+
}
738+
723739
// Handle array literals
724740
if (value.startsWith('[')) {
725741
const content = value.slice(1, -1).trim()
@@ -730,32 +746,44 @@ function inferConstArrayType(value: string, state?: ProcessingState): string {
730746
const trimmed = element.trim()
731747
debugLog(state, 'const-tuple-element', `Processing tuple element: ${trimmed}`)
732748

749+
// Remove '] as cons' artifact if present
750+
if (trimmed.includes('] as cons')) {
751+
const cleanTrimmed = trimmed.replace('] as cons', '').trim()
752+
return cleanTrimmed.replace(/^['"`]|['"`]$/g, '\'')
753+
}
754+
733755
// Handle nested arrays
734756
if (trimmed.startsWith('[')) {
735-
return inferConstArrayType(trimmed, state)
757+
// Remove any 'as const' from nested arrays
758+
const cleanTrimmed = trimmed.endsWith('as const')
759+
? trimmed.slice(0, trimmed.indexOf('as const')).trim()
760+
: trimmed
761+
return inferConstArrayType(cleanTrimmed, state)
736762
}
737763

738764
// Handle nested objects
739765
if (trimmed.startsWith('{')) {
740-
return inferComplexObjectType(trimmed, state)
766+
const result = inferComplexObjectType(trimmed, state)
767+
// Make object properties readonly for const assertions
768+
return result.replace(/^\{/, '{ readonly').replace(/;\s+/g, '; readonly ')
741769
}
742770

743-
// Preserve string literals
771+
// Handle string literals - ensure they're properly quoted
744772
if (/^['"`].*['"`]$/.test(trimmed)) {
745-
return trimmed
773+
return trimmed.replace(/^['"`]|['"`]$/g, '\'') // Normalize to single quotes
746774
}
747775

748-
// Preserve numeric literals
776+
// Handle numeric literals
749777
if (!Number.isNaN(Number(trimmed))) {
750778
return trimmed
751779
}
752780

753-
// Preserve boolean literals
781+
// Handle boolean literals
754782
if (trimmed === 'true' || trimmed === 'false') {
755783
return trimmed
756784
}
757785

758-
return 'unknown'
786+
return trimmed.replace(/^['"`]|['"`]$/g, '\'') // Normalize any remaining string literals
759787
})
760788

761789
debugLog(state, 'const-tuple-result', `Generated tuple types: [${literalTypes.join(', ')}]`)
@@ -1008,24 +1036,6 @@ export function processBlock(lines: string[], comments: string[], state: Process
10081036
debugLog(state, 'processing', `Unhandled declaration type: ${cleanDeclaration.split('\n')[0]}`)
10091037
}
10101038

1011-
function processDeclaration(declaration: string): boolean {
1012-
let bracketDepth = 0
1013-
let parenDepth = 0
1014-
1015-
for (const char of declaration) {
1016-
if (char === '(')
1017-
parenDepth++
1018-
if (char === ')')
1019-
parenDepth--
1020-
if (char === '{')
1021-
bracketDepth++
1022-
if (char === '}')
1023-
bracketDepth--
1024-
}
1025-
1026-
return bracketDepth === 0 && parenDepth === 0
1027-
}
1028-
10291039
export function processSpecificDeclaration(declarationWithoutComments: string, fullDeclaration: string, state: ProcessingState): void {
10301040
state.debug.currentProcessing = declarationWithoutComments
10311041
debugLog(state, 'processing', `Processing declaration: ${declarationWithoutComments.substring(0, 100)}...`)

0 commit comments

Comments
 (0)