@open-mercato/cli 0.5.1-develop.2699.f8b50c8046 → 0.5.1-develop.2709.b6bdd776ac
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/cli",
|
|
3
|
-
"version": "0.5.1-develop.
|
|
3
|
+
"version": "0.5.1-develop.2709.b6bdd776ac",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"@mikro-orm/decorators": "^7.0.10",
|
|
60
60
|
"@mikro-orm/migrations": "^7.0.10",
|
|
61
61
|
"@mikro-orm/postgresql": "^7.0.10",
|
|
62
|
-
"@open-mercato/queue": "0.5.1-develop.
|
|
63
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
62
|
+
"@open-mercato/queue": "0.5.1-develop.2709.b6bdd776ac",
|
|
63
|
+
"@open-mercato/shared": "0.5.1-develop.2709.b6bdd776ac",
|
|
64
64
|
"cross-spawn": "^7.0.6",
|
|
65
65
|
"pg": "8.20.0",
|
|
66
66
|
"semver": "^7.7.4",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"typescript": "^5.9.3"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
73
|
+
"@open-mercato/shared": "0.5.1-develop.2709.b6bdd776ac"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
76
|
+
"@open-mercato/shared": "0.5.1-develop.2709.b6bdd776ac",
|
|
77
77
|
"@types/jest": "^30.0.0",
|
|
78
78
|
"jest": "^30.3.0",
|
|
79
79
|
"ts-jest": "^29.4.9"
|
|
@@ -416,6 +416,76 @@ describe('generateModuleRegistry with module subsets', () => {
|
|
|
416
416
|
expect(output).toContain('subscriber_meta:on-event')
|
|
417
417
|
})
|
|
418
418
|
|
|
419
|
+
it('extracts worker metadata from imported queue constants when runtime import fails', async () => {
|
|
420
|
+
touchFile(
|
|
421
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'worker_meta', 'lib', 'queue.ts'),
|
|
422
|
+
"export const IMPORTED_QUEUE = 'worker.meta.queue'\n",
|
|
423
|
+
)
|
|
424
|
+
touchFile(
|
|
425
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'worker_meta', 'workers', 'process-job.ts'),
|
|
426
|
+
[
|
|
427
|
+
"import { IMPORTED_QUEUE } from '../lib/queue'",
|
|
428
|
+
"import { helper } from '../lib/helper'",
|
|
429
|
+
"export const metadata = { queue: IMPORTED_QUEUE, id: 'worker_meta:process-job', concurrency: 4 }",
|
|
430
|
+
'export default async function handle() { return helper }',
|
|
431
|
+
'',
|
|
432
|
+
].join('\n'),
|
|
433
|
+
)
|
|
434
|
+
touchFile(
|
|
435
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'worker_meta', 'lib', 'helper.ts'),
|
|
436
|
+
'export const helper = true\n',
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
const resolver = createMockResolver(tmpDir, [
|
|
440
|
+
{ id: 'worker_meta', from: '@open-mercato/core' },
|
|
441
|
+
])
|
|
442
|
+
|
|
443
|
+
const result = await generateModuleRegistry({ resolver, quiet: true })
|
|
444
|
+
|
|
445
|
+
expect(result.errors).toEqual([])
|
|
446
|
+
const output = readGenerated(tmpDir, 'modules.generated.ts')!
|
|
447
|
+
expect(output).toContain('queue: "worker.meta.queue"')
|
|
448
|
+
expect(output).toContain('id: "worker_meta:process-job"')
|
|
449
|
+
expect(output).toContain('concurrency: 4')
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it('extracts subscriber metadata from imported event objects when runtime import fails', async () => {
|
|
453
|
+
touchFile(
|
|
454
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'subscriber_event_meta', 'lib', 'events.ts'),
|
|
455
|
+
[
|
|
456
|
+
'export const SUBSCRIBER_EVENTS = {',
|
|
457
|
+
" CREATED: 'subscriber.event.created',",
|
|
458
|
+
"} as const",
|
|
459
|
+
'',
|
|
460
|
+
].join('\n'),
|
|
461
|
+
)
|
|
462
|
+
touchFile(
|
|
463
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'subscriber_event_meta', 'lib', 'helper.ts'),
|
|
464
|
+
'export const helper = true\n',
|
|
465
|
+
)
|
|
466
|
+
touchFile(
|
|
467
|
+
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'subscriber_event_meta', 'subscribers', 'on-created.ts'),
|
|
468
|
+
[
|
|
469
|
+
"import { helper } from '../lib/helper'",
|
|
470
|
+
"import { SUBSCRIBER_EVENTS } from '../lib/events'",
|
|
471
|
+
"export const metadata = { event: SUBSCRIBER_EVENTS.CREATED, persistent: true, id: 'subscriber_event_meta:on-created' }",
|
|
472
|
+
'export default async function handle() { return helper }',
|
|
473
|
+
'',
|
|
474
|
+
].join('\n'),
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
const resolver = createMockResolver(tmpDir, [
|
|
478
|
+
{ id: 'subscriber_event_meta', from: '@open-mercato/core' },
|
|
479
|
+
])
|
|
480
|
+
|
|
481
|
+
const result = await generateModuleRegistry({ resolver, quiet: true })
|
|
482
|
+
|
|
483
|
+
expect(result.errors).toEqual([])
|
|
484
|
+
const output = readGenerated(tmpDir, 'modules.generated.ts')!
|
|
485
|
+
expect(output).toContain('subscriber.event.created')
|
|
486
|
+
expect(output).toContain('subscriber_event_meta:on-created')
|
|
487
|
+
})
|
|
488
|
+
|
|
419
489
|
it('keeps backend route metadata runtime-backed when icons are non-serializable', async () => {
|
|
420
490
|
touchFile(
|
|
421
491
|
path.join(tmpDir, 'packages', 'core', 'src', 'modules', 'iconic', 'backend', 'dashboard', 'page.tsx'),
|
|
@@ -402,6 +402,83 @@ function collectLocalDeclarations(parsed: ts.SourceFile): Map<string, ts.Express
|
|
|
402
402
|
return locals
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
+
type ImportedBinding =
|
|
406
|
+
| {
|
|
407
|
+
kind: 'named'
|
|
408
|
+
sourceFile: string
|
|
409
|
+
exportName: string
|
|
410
|
+
}
|
|
411
|
+
| {
|
|
412
|
+
kind: 'default'
|
|
413
|
+
sourceFile: string
|
|
414
|
+
}
|
|
415
|
+
| {
|
|
416
|
+
kind: 'namespace'
|
|
417
|
+
sourceFile: string
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
type ParsedModuleResolutionContext = {
|
|
421
|
+
sourceFile: string
|
|
422
|
+
parsed: ts.SourceFile
|
|
423
|
+
locals: Map<string, ts.Expression>
|
|
424
|
+
exportedNames: Set<string>
|
|
425
|
+
imports: Map<string, ImportedBinding>
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function resolveImportedModuleFile(sourceFile: string, moduleSpecifier: string): string | null {
|
|
429
|
+
if (!moduleSpecifier.startsWith('.')) return null
|
|
430
|
+
return findExistingModuleFileByBaseNames(path.dirname(sourceFile), [
|
|
431
|
+
moduleSpecifier,
|
|
432
|
+
path.join(moduleSpecifier, 'index'),
|
|
433
|
+
])
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function collectImportedBindings(
|
|
437
|
+
parsed: ts.SourceFile,
|
|
438
|
+
sourceFile: string,
|
|
439
|
+
): Map<string, ImportedBinding> {
|
|
440
|
+
const bindings = new Map<string, ImportedBinding>()
|
|
441
|
+
|
|
442
|
+
for (const statement of parsed.statements) {
|
|
443
|
+
if (!ts.isImportDeclaration(statement)) continue
|
|
444
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) continue
|
|
445
|
+
|
|
446
|
+
const resolvedSourceFile = resolveImportedModuleFile(sourceFile, statement.moduleSpecifier.text)
|
|
447
|
+
if (!resolvedSourceFile) continue
|
|
448
|
+
|
|
449
|
+
const importClause = statement.importClause
|
|
450
|
+
if (!importClause) continue
|
|
451
|
+
|
|
452
|
+
if (importClause.name) {
|
|
453
|
+
bindings.set(importClause.name.text, {
|
|
454
|
+
kind: 'default',
|
|
455
|
+
sourceFile: resolvedSourceFile,
|
|
456
|
+
})
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const namedBindings = importClause.namedBindings
|
|
460
|
+
if (!namedBindings) continue
|
|
461
|
+
|
|
462
|
+
if (ts.isNamespaceImport(namedBindings)) {
|
|
463
|
+
bindings.set(namedBindings.name.text, {
|
|
464
|
+
kind: 'namespace',
|
|
465
|
+
sourceFile: resolvedSourceFile,
|
|
466
|
+
})
|
|
467
|
+
continue
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
for (const element of namedBindings.elements) {
|
|
471
|
+
bindings.set(element.name.text, {
|
|
472
|
+
kind: 'named',
|
|
473
|
+
sourceFile: resolvedSourceFile,
|
|
474
|
+
exportName: element.propertyName?.text ?? element.name.text,
|
|
475
|
+
})
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return bindings
|
|
480
|
+
}
|
|
481
|
+
|
|
405
482
|
function collectReexportedNames(parsed: ts.SourceFile): Set<string> {
|
|
406
483
|
const exportedNames = new Set<string>()
|
|
407
484
|
for (const statement of parsed.statements) {
|
|
@@ -464,10 +541,128 @@ function findExportedInitializer(
|
|
|
464
541
|
return null
|
|
465
542
|
}
|
|
466
543
|
|
|
544
|
+
function findDefaultExportInitializer(parsed: ts.SourceFile): ts.Expression | null {
|
|
545
|
+
for (const statement of parsed.statements) {
|
|
546
|
+
if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
547
|
+
return statement.expression
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (!ts.isVariableStatement(statement)) continue
|
|
551
|
+
const modifiers = ts.canHaveModifiers(statement) ? ts.getModifiers(statement) : undefined
|
|
552
|
+
const isDefaultExport = modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword) ?? false
|
|
553
|
+
if (!isDefaultExport) continue
|
|
554
|
+
|
|
555
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
556
|
+
if (declaration.initializer) return declaration.initializer
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
return null
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function loadParsedModuleResolutionContext(
|
|
564
|
+
sourceFile: string,
|
|
565
|
+
cache: Map<string, ParsedModuleResolutionContext | null>,
|
|
566
|
+
): ParsedModuleResolutionContext | null {
|
|
567
|
+
if (cache.has(sourceFile)) {
|
|
568
|
+
return cache.get(sourceFile) ?? null
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
let source = ''
|
|
572
|
+
try {
|
|
573
|
+
source = fs.readFileSync(sourceFile, 'utf8')
|
|
574
|
+
} catch {
|
|
575
|
+
cache.set(sourceFile, null)
|
|
576
|
+
return null
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const parsed = ts.createSourceFile(
|
|
580
|
+
sourceFile,
|
|
581
|
+
source,
|
|
582
|
+
ts.ScriptTarget.Latest,
|
|
583
|
+
true,
|
|
584
|
+
inferScriptKind(sourceFile),
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
const context: ParsedModuleResolutionContext = {
|
|
588
|
+
sourceFile,
|
|
589
|
+
parsed,
|
|
590
|
+
locals: collectLocalDeclarations(parsed),
|
|
591
|
+
exportedNames: collectReexportedNames(parsed),
|
|
592
|
+
imports: collectImportedBindings(parsed, sourceFile),
|
|
593
|
+
}
|
|
594
|
+
cache.set(sourceFile, context)
|
|
595
|
+
return context
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function resolveImportedBindingValue(
|
|
599
|
+
binding: ImportedBinding,
|
|
600
|
+
pathSegments: string[],
|
|
601
|
+
visited: Set<string>,
|
|
602
|
+
cache: Map<string, ParsedModuleResolutionContext | null>,
|
|
603
|
+
): unknown {
|
|
604
|
+
const importedContext = loadParsedModuleResolutionContext(binding.sourceFile, cache)
|
|
605
|
+
if (!importedContext) return undefined
|
|
606
|
+
|
|
607
|
+
if (binding.kind === 'namespace') {
|
|
608
|
+
if (pathSegments.length === 0) return undefined
|
|
609
|
+
const [exportName, ...restPath] = pathSegments
|
|
610
|
+
const importKey = `${binding.sourceFile}::${exportName}`
|
|
611
|
+
if (visited.has(importKey)) return undefined
|
|
612
|
+
|
|
613
|
+
let initializer = findExportedInitializer(importedContext.parsed, exportName, importedContext.exportedNames)
|
|
614
|
+
if (!initializer && importedContext.exportedNames.has(exportName)) {
|
|
615
|
+
initializer = importedContext.locals.get(exportName) ?? null
|
|
616
|
+
}
|
|
617
|
+
if (!initializer) return undefined
|
|
618
|
+
|
|
619
|
+
const nextVisited = new Set(visited)
|
|
620
|
+
nextVisited.add(importKey)
|
|
621
|
+
let value = resolveExpressionValue(initializer, importedContext, nextVisited, cache)
|
|
622
|
+
for (const segment of restPath) {
|
|
623
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && segment in (value as Record<string, unknown>)) {
|
|
624
|
+
value = (value as Record<string, unknown>)[segment]
|
|
625
|
+
} else {
|
|
626
|
+
return undefined
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return value
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const importKey = binding.kind === 'default'
|
|
633
|
+
? `${binding.sourceFile}::default`
|
|
634
|
+
: `${binding.sourceFile}::${binding.exportName}`
|
|
635
|
+
if (visited.has(importKey)) return undefined
|
|
636
|
+
|
|
637
|
+
let initializer = binding.kind === 'default'
|
|
638
|
+
? findDefaultExportInitializer(importedContext.parsed)
|
|
639
|
+
: findExportedInitializer(importedContext.parsed, binding.exportName, importedContext.exportedNames)
|
|
640
|
+
|
|
641
|
+
if (!initializer && binding.kind === 'named' && importedContext.exportedNames.has(binding.exportName)) {
|
|
642
|
+
initializer = importedContext.locals.get(binding.exportName) ?? null
|
|
643
|
+
}
|
|
644
|
+
if (!initializer) return undefined
|
|
645
|
+
|
|
646
|
+
const nextVisited = new Set(visited)
|
|
647
|
+
nextVisited.add(importKey)
|
|
648
|
+
let value = resolveExpressionValue(initializer, importedContext, nextVisited, cache)
|
|
649
|
+
|
|
650
|
+
for (const segment of pathSegments) {
|
|
651
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && segment in (value as Record<string, unknown>)) {
|
|
652
|
+
value = (value as Record<string, unknown>)[segment]
|
|
653
|
+
} else {
|
|
654
|
+
return undefined
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return value
|
|
659
|
+
}
|
|
660
|
+
|
|
467
661
|
function resolveExpressionValue(
|
|
468
662
|
expression: ts.Expression,
|
|
469
|
-
|
|
663
|
+
context: ParsedModuleResolutionContext,
|
|
470
664
|
visited: Set<string>,
|
|
665
|
+
cache: Map<string, ParsedModuleResolutionContext | null>,
|
|
471
666
|
): unknown {
|
|
472
667
|
const expr = unwrapExpression(expression)
|
|
473
668
|
|
|
@@ -488,19 +683,19 @@ function resolveExpressionValue(
|
|
|
488
683
|
: ts.isStringLiteral(property.name) ? property.name.text
|
|
489
684
|
: null
|
|
490
685
|
if (!key) continue
|
|
491
|
-
const value = resolveExpressionValue(property.initializer,
|
|
686
|
+
const value = resolveExpressionValue(property.initializer, context, visited, cache)
|
|
492
687
|
if (value !== undefined) result[key] = value
|
|
493
688
|
} else if (ts.isShorthandPropertyAssignment(property)) {
|
|
494
689
|
const key = property.name.text
|
|
495
|
-
const initializer = locals.get(key)
|
|
690
|
+
const initializer = context.locals.get(key)
|
|
496
691
|
if (initializer && !visited.has(key)) {
|
|
497
692
|
const nextVisited = new Set(visited)
|
|
498
693
|
nextVisited.add(key)
|
|
499
|
-
const value = resolveExpressionValue(initializer,
|
|
694
|
+
const value = resolveExpressionValue(initializer, context, nextVisited, cache)
|
|
500
695
|
if (value !== undefined) result[key] = value
|
|
501
696
|
}
|
|
502
697
|
} else if (ts.isSpreadAssignment(property)) {
|
|
503
|
-
const spread = resolveExpressionValue(property.expression,
|
|
698
|
+
const spread = resolveExpressionValue(property.expression, context, visited, cache)
|
|
504
699
|
if (spread && typeof spread === 'object' && !Array.isArray(spread)) {
|
|
505
700
|
Object.assign(result, spread)
|
|
506
701
|
}
|
|
@@ -513,11 +708,11 @@ function resolveExpressionValue(
|
|
|
513
708
|
const result: unknown[] = []
|
|
514
709
|
for (const element of expr.elements) {
|
|
515
710
|
if (ts.isSpreadElement(element)) {
|
|
516
|
-
const spread = resolveExpressionValue(element.expression,
|
|
711
|
+
const spread = resolveExpressionValue(element.expression, context, visited, cache)
|
|
517
712
|
if (Array.isArray(spread)) result.push(...spread)
|
|
518
713
|
continue
|
|
519
714
|
}
|
|
520
|
-
const value = resolveExpressionValue(element as ts.Expression,
|
|
715
|
+
const value = resolveExpressionValue(element as ts.Expression, context, visited, cache)
|
|
521
716
|
if (value !== undefined) result.push(value)
|
|
522
717
|
}
|
|
523
718
|
return result
|
|
@@ -525,11 +720,16 @@ function resolveExpressionValue(
|
|
|
525
720
|
|
|
526
721
|
if (ts.isIdentifier(expr)) {
|
|
527
722
|
if (visited.has(expr.text)) return undefined
|
|
528
|
-
const initializer = locals.get(expr.text)
|
|
529
|
-
if (
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
723
|
+
const initializer = context.locals.get(expr.text)
|
|
724
|
+
if (initializer) {
|
|
725
|
+
const nextVisited = new Set(visited)
|
|
726
|
+
nextVisited.add(expr.text)
|
|
727
|
+
return resolveExpressionValue(initializer, context, nextVisited, cache)
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const importBinding = context.imports.get(expr.text)
|
|
731
|
+
if (!importBinding) return undefined
|
|
732
|
+
return resolveImportedBindingValue(importBinding, [], visited, cache)
|
|
533
733
|
}
|
|
534
734
|
|
|
535
735
|
if (ts.isPropertyAccessExpression(expr)) {
|
|
@@ -542,40 +742,46 @@ function resolveExpressionValue(
|
|
|
542
742
|
}
|
|
543
743
|
if (!ts.isIdentifier(cursor)) return undefined
|
|
544
744
|
const rootName = cursor.text
|
|
545
|
-
if (visited.has(rootName))
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
745
|
+
if (!visited.has(rootName)) {
|
|
746
|
+
const rootInit = context.locals.get(rootName)
|
|
747
|
+
if (rootInit) {
|
|
748
|
+
const unwrappedRoot = unwrapExpression(rootInit)
|
|
749
|
+
const nextVisited = new Set(visited)
|
|
750
|
+
nextVisited.add(rootName)
|
|
751
|
+
// Handle `const crud = makeCrudRoute({ metadata: routeMetadata, ... })`
|
|
752
|
+
if (ts.isCallExpression(unwrappedRoot) && unwrappedRoot.arguments.length > 0) {
|
|
753
|
+
const firstArg = unwrapExpression(unwrappedRoot.arguments[0])
|
|
754
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
755
|
+
const argObject = resolveExpressionValue(firstArg, context, nextVisited, cache)
|
|
756
|
+
if (argObject && typeof argObject === 'object' && !Array.isArray(argObject)) {
|
|
757
|
+
let current: unknown = argObject
|
|
758
|
+
for (const segment of pathSegments) {
|
|
759
|
+
if (current && typeof current === 'object' && !Array.isArray(current) && segment in (current as Record<string, unknown>)) {
|
|
760
|
+
current = (current as Record<string, unknown>)[segment]
|
|
761
|
+
} else {
|
|
762
|
+
current = undefined
|
|
763
|
+
break
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (current !== undefined) return current
|
|
564
767
|
}
|
|
565
768
|
}
|
|
566
|
-
if (current !== undefined) return current
|
|
567
769
|
}
|
|
770
|
+
let value = resolveExpressionValue(rootInit, context, nextVisited, cache)
|
|
771
|
+
for (const segment of pathSegments) {
|
|
772
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && segment in (value as Record<string, unknown>)) {
|
|
773
|
+
value = (value as Record<string, unknown>)[segment]
|
|
774
|
+
} else {
|
|
775
|
+
return undefined
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return value
|
|
568
779
|
}
|
|
569
780
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
} else {
|
|
575
|
-
return undefined
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
return value
|
|
781
|
+
|
|
782
|
+
const importBinding = context.imports.get(rootName)
|
|
783
|
+
if (!importBinding) return undefined
|
|
784
|
+
return resolveImportedBindingValue(importBinding, pathSegments, visited, cache)
|
|
579
785
|
}
|
|
580
786
|
|
|
581
787
|
return undefined
|
|
@@ -629,27 +835,16 @@ export function hasNamedExport(sourceFile: string, exportName: string): boolean
|
|
|
629
835
|
}
|
|
630
836
|
|
|
631
837
|
export function resolveNamedObjectExport(sourceFile: string, exportName: string): Record<string, unknown> | null {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
sourceFile,
|
|
640
|
-
source,
|
|
641
|
-
ts.ScriptTarget.Latest,
|
|
642
|
-
true,
|
|
643
|
-
inferScriptKind(sourceFile),
|
|
644
|
-
)
|
|
645
|
-
const locals = collectLocalDeclarations(parsed)
|
|
646
|
-
const exportedNames = collectReexportedNames(parsed)
|
|
647
|
-
let initializer = findExportedInitializer(parsed, exportName, exportedNames)
|
|
648
|
-
if (!initializer && exportedNames.has(exportName)) {
|
|
649
|
-
initializer = locals.get(exportName) ?? null
|
|
838
|
+
const cache = new Map<string, ParsedModuleResolutionContext | null>()
|
|
839
|
+
const context = loadParsedModuleResolutionContext(sourceFile, cache)
|
|
840
|
+
if (!context) return null
|
|
841
|
+
|
|
842
|
+
let initializer = findExportedInitializer(context.parsed, exportName, context.exportedNames)
|
|
843
|
+
if (!initializer && context.exportedNames.has(exportName)) {
|
|
844
|
+
initializer = context.locals.get(exportName) ?? null
|
|
650
845
|
}
|
|
651
846
|
if (!initializer) return null
|
|
652
|
-
const value = resolveExpressionValue(initializer,
|
|
847
|
+
const value = resolveExpressionValue(initializer, context, new Set<string>(), cache)
|
|
653
848
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return null
|
|
654
849
|
const record = value as Record<string, unknown>
|
|
655
850
|
return Object.keys(record).length > 0 ? record : null
|