@nu-art/build-and-install 0.401.0 → 0.401.1

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.
Files changed (155) hide show
  1. package/BuildAndInstall.d.ts +40 -0
  2. package/BuildAndInstall.js +155 -0
  3. package/build-and-install-v3.d.ts +1 -44
  4. package/build-and-install-v3.js +1 -157
  5. package/build-and-install.js +11 -11
  6. package/config/consts.d.ts +43 -0
  7. package/config/consts.js +42 -0
  8. package/{core → config}/package/consts.d.ts +1 -1
  9. package/{core → config}/types/project-config.d.ts +3 -0
  10. package/core/FilesCache.d.ts +50 -0
  11. package/core/FilesCache.js +76 -0
  12. package/core/Unit_HelpPrinter.d.ts +16 -0
  13. package/core/Unit_HelpPrinter.js +47 -0
  14. package/core/params/params.d.ts +1 -41
  15. package/core/params/params.js +1 -332
  16. package/core/params.d.ts +50 -0
  17. package/core/params.js +441 -0
  18. package/{v3/core → core}/types.d.ts +1 -1
  19. package/{v3/UnitsDependencyMapper → dependencies}/UnitsDependencyMapper.d.ts +21 -1
  20. package/{v3/UnitsDependencyMapper → dependencies}/UnitsDependencyMapper.js +26 -3
  21. package/dependencies/types.d.ts +1 -0
  22. package/dependencies/types.js +1 -0
  23. package/exceptions/PhaseAggregatedException.d.ts +34 -0
  24. package/{core/exceptions → exceptions}/PhaseAggregatedException.js +26 -0
  25. package/exceptions/UnitPhaseException.d.ts +20 -0
  26. package/exceptions/UnitPhaseException.js +21 -0
  27. package/exports/ExportIndexCache.d.ts +25 -0
  28. package/exports/ExportIndexCache.js +115 -0
  29. package/exports/ExportMapper.d.ts +43 -0
  30. package/exports/ExportMapper.js +519 -0
  31. package/exports/IndicesMcpServer.d.ts +22 -0
  32. package/exports/IndicesMcpServer.js +220 -0
  33. package/exports/types.js +3 -0
  34. package/package.json +20 -9
  35. package/phases/PhaseManager.d.ts +130 -0
  36. package/{v3 → phases}/PhaseManager.js +99 -2
  37. package/{v3/phase → phases/definitions}/consts.d.ts +36 -0
  38. package/{v3/phase → phases/definitions}/consts.js +44 -2
  39. package/phases/definitions/types.d.ts +40 -0
  40. package/phases/index.d.ts +2 -0
  41. package/phases/index.js +2 -0
  42. package/run.js +10 -0
  43. package/runtime/RunningStatusHandler.d.ts +104 -0
  44. package/runtime/RunningStatusHandler.js +153 -0
  45. package/runtime/types.d.ts +1 -0
  46. package/runtime/types.js +2 -0
  47. package/{defaults → templates}/consts.d.ts +9 -0
  48. package/{defaults → templates}/consts.js +12 -2
  49. package/templates/firebase/functions/cloudbuild.yaml +17 -0
  50. package/templates/firebase/functions/dockerfile +19 -0
  51. package/templates/firebase/functions/service.yaml +49 -0
  52. package/{v3/units → units/base}/BaseUnit.d.ts +34 -4
  53. package/{v3/units → units/base}/BaseUnit.js +22 -2
  54. package/units/base/ProjectUnit.d.ts +32 -0
  55. package/units/base/ProjectUnit.js +25 -0
  56. package/units/base/types.js +1 -0
  57. package/units/discovery/UnitsMapper.d.ts +69 -0
  58. package/{v3/UnitsMapper → units/discovery}/UnitsMapper.js +50 -2
  59. package/units/discovery/resolvers/UnitMapper_Base.d.ts +65 -0
  60. package/units/discovery/resolvers/UnitMapper_Base.js +46 -0
  61. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_FirebaseFunction.d.ts +5 -3
  62. package/units/discovery/resolvers/UnitMapper_FirebaseFunction.js +105 -0
  63. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_FirebaseHosting.d.ts +3 -2
  64. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_FirebaseHosting.js +14 -10
  65. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_Node.d.ts +1 -1
  66. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_Node.js +2 -2
  67. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_NodeLib.d.ts +24 -1
  68. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_NodeLib.js +24 -1
  69. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_NodeProject.d.ts +22 -1
  70. package/{v3/UnitsMapper → units/discovery}/resolvers/UnitMapper_NodeProject.js +22 -1
  71. package/units/discovery/types.js +1 -0
  72. package/units/implementations/Unit_NodeProject.d.ts +59 -0
  73. package/{v3/units → units/implementations}/Unit_NodeProject.js +65 -5
  74. package/units/implementations/Unit_PackageJson.d.ts +56 -0
  75. package/{v3/units → units/implementations}/Unit_PackageJson.js +39 -3
  76. package/{v3/units → units/implementations}/Unit_TypescriptLib.d.ts +40 -4
  77. package/{v3/units → units/implementations}/Unit_TypescriptLib.js +167 -17
  78. package/units/implementations/firebase/Unit_FirebaseFunctionsApp.d.ts +233 -0
  79. package/units/implementations/firebase/Unit_FirebaseFunctionsApp.js +804 -0
  80. package/units/implementations/firebase/Unit_FirebaseHostingApp.d.ts +113 -0
  81. package/units/implementations/firebase/Unit_FirebaseHostingApp.js +320 -0
  82. package/units/implementations/firebase/common.d.ts +26 -0
  83. package/units/implementations/firebase/common.js +65 -0
  84. package/units/index.d.ts +6 -0
  85. package/units/index.js +6 -0
  86. package/v3/core/Unit_HelpPrinter.d.ts +1 -16
  87. package/v3/core/Unit_HelpPrinter.js +1 -47
  88. package/{v3 → workspace}/Workspace.d.ts +30 -15
  89. package/{v3 → workspace}/Workspace.js +48 -35
  90. package/core/consts.d.ts +0 -13
  91. package/core/consts.js +0 -12
  92. package/core/exceptions/PhaseAggregatedException.d.ts +0 -8
  93. package/core/exceptions/UnitPhaseException.d.ts +0 -5
  94. package/core/exceptions/UnitPhaseException.js +0 -6
  95. package/old/PhaseRunnerDispatcher.d.ts +0 -24
  96. package/old/PhaseRunnerDispatcher.js +0 -32
  97. package/old/runner-dispatchers.d.ts +0 -10
  98. package/old/runner-dispatchers.js +0 -3
  99. package/v3/PhaseManager.d.ts +0 -27
  100. package/v3/RunningStatusHandler.d.ts +0 -18
  101. package/v3/RunningStatusHandler.js +0 -67
  102. package/v3/UnitsMapper/UnitsMapper.d.ts +0 -21
  103. package/v3/UnitsMapper/resolvers/UnitMapper_Base.d.ts +0 -23
  104. package/v3/UnitsMapper/resolvers/UnitMapper_Base.js +0 -16
  105. package/v3/UnitsMapper/resolvers/UnitMapper_FirebaseFunction.js +0 -66
  106. package/v3/core/FilesCache.d.ts +0 -7
  107. package/v3/core/FilesCache.js +0 -33
  108. package/v3/phase/types.d.ts +0 -10
  109. package/v3/units/ProjectUnit.d.ts +0 -18
  110. package/v3/units/ProjectUnit.js +0 -11
  111. package/v3/units/Unit_NodeProject.d.ts +0 -30
  112. package/v3/units/Unit_PackageJson.d.ts +0 -17
  113. package/v3/units/firebase/Unit_FirebaseFunctionsApp.d.ts +0 -64
  114. package/v3/units/firebase/Unit_FirebaseFunctionsApp.js +0 -306
  115. package/v3/units/firebase/Unit_FirebaseHostingApp.d.ts +0 -49
  116. package/v3/units/firebase/Unit_FirebaseHostingApp.js +0 -118
  117. package/v3/units/firebase/common.d.ts +0 -3
  118. package/v3/units/firebase/common.js +0 -13
  119. package/v3/units/index.d.ts +0 -6
  120. package/v3/units/index.js +0 -6
  121. /package/{core → config}/package/consts.js +0 -0
  122. /package/{core → config}/types/configs/firebasejson.d.ts +0 -0
  123. /package/{core → config}/types/configs/firebasejson.js +0 -0
  124. /package/{core → config}/types/configs/firebaserc.d.ts +0 -0
  125. /package/{core → config}/types/configs/firebaserc.js +0 -0
  126. /package/{core → config}/types/configs/index.d.ts +0 -0
  127. /package/{core → config}/types/configs/index.js +0 -0
  128. /package/{core → config}/types/configs/package-json.d.ts +0 -0
  129. /package/{core → config}/types/configs/package-json.js +0 -0
  130. /package/{core → config}/types/core.d.ts +0 -0
  131. /package/{core → config}/types/core.js +0 -0
  132. /package/{core → config}/types/index.d.ts +0 -0
  133. /package/{core → config}/types/index.js +0 -0
  134. /package/{core → config}/types/package/index.d.ts +0 -0
  135. /package/{core → config}/types/package/index.js +0 -0
  136. /package/{core → config}/types/package/package.d.ts +0 -0
  137. /package/{core → config}/types/package/package.js +0 -0
  138. /package/{core → config}/types/package/runtime-package.d.ts +0 -0
  139. /package/{core → config}/types/package/runtime-package.js +0 -0
  140. /package/{core → config}/types/project-config.js +0 -0
  141. /package/{v3/core → core}/types.js +0 -0
  142. /package/{v3/UnitsMapper/types.js → exports/types.d.ts} +0 -0
  143. /package/{v3/phase → phases/definitions}/index.d.ts +0 -0
  144. /package/{v3/phase → phases/definitions}/index.js +0 -0
  145. /package/{v3/phase → phases/definitions}/types.js +0 -0
  146. /package/{v3/units/types.js → run.d.ts} +0 -0
  147. /package/{defaults/backend-proxy → templates/backend/proxy}/proxy._ts +0 -0
  148. /package/{defaults/.firebase_config → templates/firebase/config}/database.rules.json +0 -0
  149. /package/{defaults/.firebase_config → templates/firebase/config}/firestore.indexes.json +0 -0
  150. /package/{defaults/.firebase_config → templates/firebase/config}/firestore.rules +0 -0
  151. /package/{defaults/.firebase_config → templates/firebase/config}/storage.rules +0 -0
  152. /package/{v3/units → units/base}/types.d.ts +0 -0
  153. /package/{v3/UnitsMapper → units/discovery}/resolvers/index.d.ts +0 -0
  154. /package/{v3/UnitsMapper → units/discovery}/resolvers/index.js +0 -0
  155. /package/{v3/UnitsMapper → units/discovery}/types.d.ts +0 -0
@@ -0,0 +1,115 @@
1
+ import { resolve as pathResolve } from 'path';
2
+ import { FileSystemUtils } from '@nu-art/ts-common/utils/FileSystemUtils';
3
+ import { FilesCache } from '../core/FilesCache.js';
4
+ import { promises as fs } from 'fs';
5
+ import { glob } from 'node:fs/promises';
6
+ const cache = new Map();
7
+ export const ExportIndexCache = {
8
+ getIndexPath(projectRoot, packageName) {
9
+ return pathResolve(projectRoot, '.trash', 'indices', packageName);
10
+ },
11
+ async load(projectRoot, packageRoot, packageName) {
12
+ const cacheKey = packageRoot;
13
+ const cached = cache.get(cacheKey);
14
+ // Check if we need to reload based on index file mtime
15
+ const indexPath = ExportIndexCache.getIndexPath(projectRoot, packageName);
16
+ const indexFilePath = pathResolve(indexPath, '_export-for-import.json');
17
+ if (!await FileSystemUtils.file.exists(indexFilePath)) {
18
+ throw new Error(`Index file not found: ${indexFilePath}. Run 'bai --map-exports' to generate indices.`);
19
+ }
20
+ const indexStat = await fs.stat(indexFilePath);
21
+ const currentIndexMtime = indexStat.mtimeMs;
22
+ // If cached and mtime matches, return cached
23
+ if (cached && cached.indexMtime === currentIndexMtime) {
24
+ return cached;
25
+ }
26
+ // Load index files
27
+ const exports = await FilesCache.load.json(indexFilePath);
28
+ const byNameData = await FilesCache.load.json(pathResolve(indexPath, '_export-index-by-name.json'));
29
+ const byFileData = await FilesCache.load.json(pathResolve(indexPath, '_export-index-by-file.json'));
30
+ const byTypeData = await FilesCache.load.json(pathResolve(indexPath, '_export-index-by-type.json'));
31
+ // Convert to Maps for faster lookups
32
+ const byName = new Map();
33
+ for (const [name, symbol] of Object.entries(byNameData)) {
34
+ byName.set(name, symbol);
35
+ }
36
+ const byFile = new Map();
37
+ for (const [filePath, symbols] of Object.entries(byFileData)) {
38
+ byFile.set(filePath, symbols);
39
+ }
40
+ const byType = new Map();
41
+ for (const [type, symbols] of Object.entries(byTypeData)) {
42
+ byType.set(type, symbols);
43
+ }
44
+ // Calculate max source file mtime
45
+ const sourceMtime = await ExportIndexCache.calculateSourceMtime(packageRoot);
46
+ const cachedIndex = {
47
+ exports,
48
+ byName,
49
+ byFile,
50
+ byType,
51
+ indexMtime: currentIndexMtime,
52
+ sourceMtime,
53
+ packageRoot,
54
+ packageName,
55
+ projectRoot
56
+ };
57
+ cache.set(cacheKey, cachedIndex);
58
+ return cachedIndex;
59
+ },
60
+ async calculateSourceMtime(packageRoot) {
61
+ const srcMainTs = `${packageRoot}/src/main/**/*.ts`;
62
+ const srcMainTsx = `${packageRoot}/src/main/**/*.tsx`;
63
+ let maxMtime = 0;
64
+ try {
65
+ for await (const file of glob(srcMainTs, {})) {
66
+ const stat = await fs.stat(file);
67
+ maxMtime = Math.max(maxMtime, stat.mtimeMs);
68
+ }
69
+ for await (const file of glob(srcMainTsx, {})) {
70
+ const stat = await fs.stat(file);
71
+ maxMtime = Math.max(maxMtime, stat.mtimeMs);
72
+ }
73
+ }
74
+ catch (error) {
75
+ // If source files don't exist, return 0
76
+ return 0;
77
+ }
78
+ return maxMtime;
79
+ },
80
+ async isStale(projectRoot, packageRoot, packageName) {
81
+ const indexPath = ExportIndexCache.getIndexPath(projectRoot, packageName);
82
+ const indexFilePath = pathResolve(indexPath, '_export-for-import.json');
83
+ if (!await FileSystemUtils.file.exists(indexFilePath)) {
84
+ return true; // No index file means it's stale
85
+ }
86
+ const indexStat = await fs.stat(indexFilePath);
87
+ const indexMtime = indexStat.mtimeMs;
88
+ const sourceMtime = await ExportIndexCache.calculateSourceMtime(packageRoot);
89
+ // Stale if any source file is newer than index file
90
+ return sourceMtime > indexMtime;
91
+ },
92
+ async getByName(projectRoot, packageRoot, packageName, symbolName) {
93
+ const cached = await ExportIndexCache.load(projectRoot, packageRoot, packageName);
94
+ return cached.byName.get(symbolName) || null;
95
+ },
96
+ async getByFile(projectRoot, packageRoot, packageName, filePath) {
97
+ const cached = await ExportIndexCache.load(projectRoot, packageRoot, packageName);
98
+ return cached.byFile.get(filePath) || [];
99
+ },
100
+ async getByType(projectRoot, packageRoot, packageName, symbolType) {
101
+ const cached = await ExportIndexCache.load(projectRoot, packageRoot, packageName);
102
+ return cached.byType.get(symbolType) || [];
103
+ },
104
+ async getAll(projectRoot, packageRoot, packageName) {
105
+ const cached = await ExportIndexCache.load(projectRoot, packageRoot, packageName);
106
+ return cached.exports;
107
+ },
108
+ invalidate(projectRoot, packageRoot, packageName) {
109
+ const cacheKey = packageRoot;
110
+ cache.delete(cacheKey);
111
+ },
112
+ clear() {
113
+ cache.clear();
114
+ }
115
+ };
@@ -0,0 +1,43 @@
1
+ import * as ts from 'typescript';
2
+ export type ExportSymbol = {
3
+ name: string;
4
+ filePath: string;
5
+ line: number;
6
+ symbolType: 'function' | 'class' | 'interface' | 'type' | 'enum' | 'variable' | 'constant' | 'default' | 're-export';
7
+ signature: string | null;
8
+ typeInfo: string | null;
9
+ genericSignature: string | null;
10
+ parentClass: string | null;
11
+ interfaces: string[];
12
+ };
13
+ export type ExportError = {
14
+ level: 'package' | 'folder' | 'file' | 'symbol';
15
+ path: string;
16
+ error: string;
17
+ stack?: string;
18
+ timestamp: string;
19
+ retryable: boolean;
20
+ context?: Record<string, any>;
21
+ };
22
+ export declare class ExportMapper {
23
+ static getIndexPath(projectRoot: string, packageName: string): string;
24
+ static generateIndexFiles(projectRoot: string, packageName: string, exports: ExportSymbol[]): Promise<void>;
25
+ static mapExports(projectRoot: string, packageRoot: string, packageName: string, sourceFiles: string[], retryErrors?: ExportError[]): Promise<{
26
+ exports: ExportSymbol[];
27
+ errors: ExportError[];
28
+ }>;
29
+ static createProgram(sourceFiles: string[], packageRoot: string): ts.Program;
30
+ static extractExportsFromFile(sourceFile: ts.SourceFile, checker: ts.TypeChecker, packageRoot: string, errors: ExportError[], errorMap?: Map<string, ExportError>): ExportSymbol[];
31
+ static extractSymbolMetadata(node: ts.Node, sourceFile: ts.SourceFile, checker: ts.TypeChecker, packageRoot: string, errors: ExportError[], name: string, symbolType: ExportSymbol['symbolType'], errorMap?: Map<string, ExportError>): ExportSymbol | null;
32
+ static extractGenericSignatures(node: ts.Node, checker: ts.TypeChecker): string | null;
33
+ static extractClassInheritance(node: ts.ClassDeclaration, checker: ts.TypeChecker): {
34
+ parentClass: string | null;
35
+ interfaces: string[];
36
+ };
37
+ static hasExportModifier(node: ts.Node): boolean;
38
+ static getLineNumber(sourceFile: ts.SourceFile, node: ts.Node): number;
39
+ static getRelativePath(absolutePath: string, packageRoot: string): string;
40
+ static loadPreviousErrors(projectRoot: string, packageName: string): Promise<ExportError[] | null>;
41
+ static writeErrors(projectRoot: string, packageName: string, errors: ExportError[]): Promise<void>;
42
+ static shouldRetryError(error: ExportError, retryErrors?: ExportError[]): boolean;
43
+ }
@@ -0,0 +1,519 @@
1
+ import * as ts from 'typescript';
2
+ import { resolve as pathResolve } from 'path';
3
+ import { FileSystemUtils } from '@nu-art/ts-common/utils/FileSystemUtils';
4
+ import { __stringify } from '@nu-art/ts-common';
5
+ import { CONST_TS_CONFIG } from '../config/consts.js';
6
+ import { existsSync, readFileSync } from 'fs';
7
+ export class ExportMapper {
8
+ static getIndexPath(projectRoot, packageName) {
9
+ return pathResolve(projectRoot, '.trash', 'indices', packageName);
10
+ }
11
+ static async generateIndexFiles(projectRoot, packageName, exports) {
12
+ const indexPath = ExportMapper.getIndexPath(projectRoot, packageName);
13
+ // Ensure directory exists
14
+ await FileSystemUtils.folder.create(indexPath);
15
+ // Generate by-name index
16
+ const byName = {};
17
+ for (const exp of exports) {
18
+ byName[exp.name] = exp;
19
+ }
20
+ const byNamePath = pathResolve(indexPath, '_export-index-by-name.json');
21
+ await FileSystemUtils.file.write(byNamePath, __stringify(byName, true));
22
+ // Generate by-file index
23
+ const byFile = {};
24
+ for (const exp of exports) {
25
+ if (!byFile[exp.filePath]) {
26
+ byFile[exp.filePath] = [];
27
+ }
28
+ byFile[exp.filePath].push(exp);
29
+ }
30
+ const byFilePath = pathResolve(indexPath, '_export-index-by-file.json');
31
+ await FileSystemUtils.file.write(byFilePath, __stringify(byFile, true));
32
+ // Generate by-type index
33
+ const byType = {};
34
+ for (const exp of exports) {
35
+ if (!byType[exp.symbolType]) {
36
+ byType[exp.symbolType] = [];
37
+ }
38
+ byType[exp.symbolType].push(exp);
39
+ }
40
+ const byTypePath = pathResolve(indexPath, '_export-index-by-type.json');
41
+ await FileSystemUtils.file.write(byTypePath, __stringify(byType, true));
42
+ }
43
+ static async mapExports(projectRoot, packageRoot, packageName, sourceFiles, retryErrors) {
44
+ const errors = [];
45
+ const exports = [];
46
+ // Create error map for quick lookup
47
+ const errorMap = new Map();
48
+ if (retryErrors) {
49
+ for (const error of retryErrors) {
50
+ errorMap.set(error.path, error);
51
+ }
52
+ }
53
+ // Package level: Create TypeScript program
54
+ let program;
55
+ try {
56
+ program = ExportMapper.createProgram(sourceFiles, packageRoot);
57
+ }
58
+ catch (error) {
59
+ errors.push({
60
+ level: 'package',
61
+ path: packageRoot,
62
+ error: error.message || String(error),
63
+ stack: error.stack,
64
+ timestamp: new Date().toISOString(),
65
+ retryable: true,
66
+ context: { operation: 'createProgram' }
67
+ });
68
+ return { exports, errors };
69
+ }
70
+ const checker = program.getTypeChecker();
71
+ // File level: Process each source file
72
+ for (const sourceFile of program.getSourceFiles()) {
73
+ // Skip node_modules and declaration files
74
+ if (sourceFile.fileName.includes('node_modules') || sourceFile.fileName.endsWith('.d.ts')) {
75
+ continue;
76
+ }
77
+ // Only process files in src/main
78
+ if (!sourceFile.fileName.includes('/src/main/')) {
79
+ continue;
80
+ }
81
+ const filePath = ExportMapper.getRelativePath(sourceFile.fileName, packageRoot);
82
+ const fileErrorKey = filePath;
83
+ // Check if this file had a previous non-retryable error - skip those
84
+ // If retryable error exists, we'll process it (retry)
85
+ // If no previous error, process normally
86
+ if (errorMap.has(fileErrorKey)) {
87
+ const prevError = errorMap.get(fileErrorKey);
88
+ if (!prevError.retryable) {
89
+ // Skip non-retryable errors
90
+ continue;
91
+ }
92
+ // If retryable, continue to process (retry it)
93
+ }
94
+ try {
95
+ const fileExports = ExportMapper.extractExportsFromFile(sourceFile, checker, packageRoot, errors, errorMap);
96
+ exports.push(...fileExports);
97
+ // Remove from error map if successfully processed
98
+ if (errorMap.has(fileErrorKey)) {
99
+ errorMap.delete(fileErrorKey);
100
+ }
101
+ }
102
+ catch (error) {
103
+ errors.push({
104
+ level: 'file',
105
+ path: filePath,
106
+ error: error.message || String(error),
107
+ stack: error.stack,
108
+ timestamp: new Date().toISOString(),
109
+ retryable: true,
110
+ context: { fileName: sourceFile.fileName }
111
+ });
112
+ }
113
+ }
114
+ // Add any remaining errors from retry that weren't resolved
115
+ for (const error of errorMap.values()) {
116
+ errors.push(error);
117
+ }
118
+ return { exports, errors };
119
+ }
120
+ static createProgram(sourceFiles, packageRoot) {
121
+ const tsConfigPath = pathResolve(packageRoot, 'src/main', CONST_TS_CONFIG);
122
+ let compilerOptions = {};
123
+ // Try to load tsconfig.json synchronously
124
+ if (existsSync(tsConfigPath)) {
125
+ try {
126
+ const configFileText = readFileSync(tsConfigPath, 'utf8');
127
+ const configFile = ts.parseConfigFileTextToJson(tsConfigPath, configFileText);
128
+ if (configFile.config) {
129
+ const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, pathResolve(packageRoot, 'src/main'));
130
+ compilerOptions = parsedConfig.options;
131
+ }
132
+ }
133
+ catch (error) {
134
+ // Use default options if config loading fails
135
+ }
136
+ }
137
+ // Default compiler options
138
+ compilerOptions = {
139
+ ...compilerOptions,
140
+ allowJs: true,
141
+ skipLibCheck: true,
142
+ noEmit: true,
143
+ };
144
+ return ts.createProgram(sourceFiles, compilerOptions);
145
+ }
146
+ static extractExportsFromFile(sourceFile, checker, packageRoot, errors, errorMap) {
147
+ const exports = [];
148
+ const filePath = ExportMapper.getRelativePath(sourceFile.fileName, packageRoot);
149
+ const visit = (node) => {
150
+ // Check for export declarations
151
+ if (ts.isVariableStatement(node) && ExportMapper.hasExportModifier(node)) {
152
+ // Export variable statements
153
+ for (const declaration of node.declarationList.declarations) {
154
+ if (ts.isIdentifier(declaration.name)) {
155
+ const symbol = ExportMapper.extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, declaration.name.text, 'variable', errorMap);
156
+ if (symbol)
157
+ exports.push(symbol);
158
+ }
159
+ }
160
+ }
161
+ else if (ts.isFunctionDeclaration(node) && ExportMapper.hasExportModifier(node) && node.name) {
162
+ // Export function
163
+ const symbol = ExportMapper.extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, node.name.text, 'function', errorMap);
164
+ if (symbol)
165
+ exports.push(symbol);
166
+ }
167
+ else if (ts.isClassDeclaration(node) && ExportMapper.hasExportModifier(node) && node.name) {
168
+ // Export class
169
+ const symbol = ExportMapper.extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, node.name.text, 'class', errorMap);
170
+ if (symbol)
171
+ exports.push(symbol);
172
+ }
173
+ else if (ts.isInterfaceDeclaration(node) && ExportMapper.hasExportModifier(node)) {
174
+ // Export interface
175
+ const symbol = ExportMapper.extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, node.name.text, 'interface', errorMap);
176
+ if (symbol)
177
+ exports.push(symbol);
178
+ }
179
+ else if (ts.isTypeAliasDeclaration(node) && ExportMapper.hasExportModifier(node)) {
180
+ // Export type
181
+ const symbol = ExportMapper.extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, node.name.text, 'type', errorMap);
182
+ if (symbol)
183
+ exports.push(symbol);
184
+ }
185
+ else if (ts.isEnumDeclaration(node) && ExportMapper.hasExportModifier(node)) {
186
+ // Export enum
187
+ const symbol = ExportMapper.extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, node.name.text, 'enum', errorMap);
188
+ if (symbol)
189
+ exports.push(symbol);
190
+ }
191
+ else if (ts.isExportAssignment(node)) {
192
+ // Default export
193
+ const symbol = ExportMapper.extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, 'default', 'default', errorMap);
194
+ if (symbol)
195
+ exports.push(symbol);
196
+ }
197
+ else if (ts.isExportDeclaration(node)) {
198
+ // Re-export
199
+ if (node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
200
+ const symbol = {
201
+ name: node.moduleSpecifier.text,
202
+ filePath,
203
+ line: ExportMapper.getLineNumber(sourceFile, node),
204
+ symbolType: 're-export',
205
+ signature: null,
206
+ typeInfo: node.moduleSpecifier.text,
207
+ genericSignature: null,
208
+ parentClass: null,
209
+ interfaces: []
210
+ };
211
+ exports.push(symbol);
212
+ }
213
+ }
214
+ ts.forEachChild(node, visit);
215
+ };
216
+ visit(sourceFile);
217
+ return exports;
218
+ }
219
+ static extractSymbolMetadata(node, sourceFile, checker, packageRoot, errors, name, symbolType, errorMap) {
220
+ const filePath = ExportMapper.getRelativePath(sourceFile.fileName, packageRoot);
221
+ const symbolErrorKey = `${filePath}::${name}`;
222
+ // Check if this symbol had a previous non-retryable error
223
+ if (errorMap?.has(symbolErrorKey)) {
224
+ const prevError = errorMap.get(symbolErrorKey);
225
+ if (!prevError.retryable) {
226
+ // Skip non-retryable symbol errors
227
+ return null;
228
+ }
229
+ }
230
+ try {
231
+ const line = ExportMapper.getLineNumber(sourceFile, node);
232
+ let signature = null;
233
+ let typeInfo = null;
234
+ let genericSignature = null;
235
+ let parentClass = null;
236
+ let interfaces = [];
237
+ // Extract generic signature
238
+ try {
239
+ genericSignature = ExportMapper.extractGenericSignatures(node, checker);
240
+ }
241
+ catch (error) {
242
+ errors.push({
243
+ level: 'symbol',
244
+ path: symbolErrorKey,
245
+ error: `Failed to extract generic signature: ${error.message || String(error)}`,
246
+ stack: error.stack,
247
+ timestamp: new Date().toISOString(),
248
+ retryable: true,
249
+ context: { symbolName: name, symbolType, operation: 'extractGenericSignatures' }
250
+ });
251
+ }
252
+ // Extract signature and type info based on symbol type
253
+ if (symbolType === 'function' && ts.isFunctionDeclaration(node)) {
254
+ try {
255
+ const symbol = checker.getSymbolAtLocation(node);
256
+ if (symbol) {
257
+ const type = checker.getTypeOfSymbolAtLocation(symbol, node);
258
+ const signatures = checker.getSignaturesOfType(type, ts.SignatureKind.Call);
259
+ if (signatures.length > 0) {
260
+ signature = checker.signatureToString(signatures[0], node);
261
+ }
262
+ }
263
+ }
264
+ catch (error) {
265
+ errors.push({
266
+ level: 'symbol',
267
+ path: symbolErrorKey,
268
+ error: `Failed to extract function signature: ${error.message || String(error)}`,
269
+ stack: error.stack,
270
+ timestamp: new Date().toISOString(),
271
+ retryable: true,
272
+ context: { symbolName: name, symbolType, operation: 'extractFunctionSignature' }
273
+ });
274
+ }
275
+ }
276
+ else if (symbolType === 'class' && ts.isClassDeclaration(node)) {
277
+ try {
278
+ // Extract class inheritance
279
+ const inheritance = ExportMapper.extractClassInheritance(node, checker);
280
+ parentClass = inheritance.parentClass;
281
+ interfaces = inheritance.interfaces;
282
+ // Build class signature
283
+ const parts = [];
284
+ parts.push('class', name);
285
+ if (genericSignature) {
286
+ parts[1] = `${name}${genericSignature}`;
287
+ }
288
+ if (parentClass) {
289
+ parts.push('extends', parentClass);
290
+ }
291
+ if (interfaces.length > 0) {
292
+ parts.push('implements', interfaces.join(', '));
293
+ }
294
+ signature = parts.join(' ');
295
+ }
296
+ catch (error) {
297
+ errors.push({
298
+ level: 'symbol',
299
+ path: symbolErrorKey,
300
+ error: `Failed to extract class metadata: ${error.message || String(error)}`,
301
+ stack: error.stack,
302
+ timestamp: new Date().toISOString(),
303
+ retryable: true,
304
+ context: { symbolName: name, symbolType, operation: 'extractClassMetadata' }
305
+ });
306
+ }
307
+ }
308
+ else if (symbolType === 'interface' && ts.isInterfaceDeclaration(node)) {
309
+ try {
310
+ const symbol = checker.getSymbolAtLocation(node);
311
+ if (symbol) {
312
+ const type = checker.getTypeOfSymbolAtLocation(symbol, node);
313
+ typeInfo = checker.typeToString(type, node);
314
+ }
315
+ }
316
+ catch (error) {
317
+ errors.push({
318
+ level: 'symbol',
319
+ path: symbolErrorKey,
320
+ error: `Failed to extract interface type info: ${error.message || String(error)}`,
321
+ stack: error.stack,
322
+ timestamp: new Date().toISOString(),
323
+ retryable: true,
324
+ context: { symbolName: name, symbolType, operation: 'extractInterfaceTypeInfo' }
325
+ });
326
+ }
327
+ }
328
+ else if (symbolType === 'type' && ts.isTypeAliasDeclaration(node)) {
329
+ try {
330
+ const symbol = checker.getSymbolAtLocation(node);
331
+ if (symbol) {
332
+ const type = checker.getTypeOfSymbolAtLocation(symbol, node);
333
+ typeInfo = checker.typeToString(type, node);
334
+ }
335
+ }
336
+ catch (error) {
337
+ errors.push({
338
+ level: 'symbol',
339
+ path: symbolErrorKey,
340
+ error: `Failed to extract type info: ${error.message || String(error)}`,
341
+ stack: error.stack,
342
+ timestamp: new Date().toISOString(),
343
+ retryable: true,
344
+ context: { symbolName: name, symbolType, operation: 'extractTypeInfo' }
345
+ });
346
+ }
347
+ }
348
+ else if (symbolType === 'variable' || symbolType === 'constant') {
349
+ try {
350
+ const symbol = checker.getSymbolAtLocation(node);
351
+ if (symbol) {
352
+ const type = checker.getTypeOfSymbolAtLocation(symbol, node);
353
+ typeInfo = checker.typeToString(type, node);
354
+ }
355
+ }
356
+ catch (error) {
357
+ errors.push({
358
+ level: 'symbol',
359
+ path: symbolErrorKey,
360
+ error: `Failed to extract variable type info: ${error.message || String(error)}`,
361
+ stack: error.stack,
362
+ timestamp: new Date().toISOString(),
363
+ retryable: true,
364
+ context: { symbolName: name, symbolType, operation: 'extractVariableTypeInfo' }
365
+ });
366
+ }
367
+ }
368
+ const symbol = {
369
+ name,
370
+ filePath,
371
+ line,
372
+ symbolType,
373
+ signature,
374
+ typeInfo,
375
+ genericSignature,
376
+ parentClass,
377
+ interfaces
378
+ };
379
+ // Remove from error map if successfully processed (retry succeeded)
380
+ if (errorMap?.has(symbolErrorKey)) {
381
+ errorMap.delete(symbolErrorKey);
382
+ }
383
+ return symbol;
384
+ }
385
+ catch (error) {
386
+ errors.push({
387
+ level: 'symbol',
388
+ path: symbolErrorKey,
389
+ error: error.message || String(error),
390
+ stack: error.stack,
391
+ timestamp: new Date().toISOString(),
392
+ retryable: true,
393
+ context: { symbolName: name, symbolType }
394
+ });
395
+ return null;
396
+ }
397
+ }
398
+ static extractGenericSignatures(node, checker) {
399
+ let typeParameters;
400
+ if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
401
+ typeParameters = node.typeParameters;
402
+ }
403
+ else if (ts.isClassDeclaration(node)) {
404
+ typeParameters = node.typeParameters;
405
+ }
406
+ else if (ts.isInterfaceDeclaration(node)) {
407
+ typeParameters = node.typeParameters;
408
+ }
409
+ else if (ts.isTypeAliasDeclaration(node)) {
410
+ typeParameters = node.typeParameters;
411
+ }
412
+ if (!typeParameters || typeParameters.length === 0) {
413
+ return null;
414
+ }
415
+ const params = [];
416
+ for (const param of typeParameters) {
417
+ let paramStr = param.name.text;
418
+ if (param.constraint) {
419
+ paramStr += ` extends ${param.constraint.getText()}`;
420
+ }
421
+ if (param.default) {
422
+ paramStr += ` = ${param.default.getText()}`;
423
+ }
424
+ params.push(paramStr);
425
+ }
426
+ return `<${params.join(', ')}>`;
427
+ }
428
+ static extractClassInheritance(node, checker) {
429
+ let parentClass = null;
430
+ const interfaces = [];
431
+ if (!node.heritageClauses) {
432
+ return { parentClass, interfaces };
433
+ }
434
+ for (const clause of node.heritageClauses) {
435
+ if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
436
+ // Extends clause
437
+ for (const type of clause.types) {
438
+ try {
439
+ const typeNode = checker.getTypeAtLocation(type);
440
+ parentClass = checker.typeToString(typeNode, type);
441
+ }
442
+ catch (error) {
443
+ // If type checking fails, use the text
444
+ parentClass = type.getText();
445
+ }
446
+ }
447
+ }
448
+ else if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
449
+ // Implements clause
450
+ for (const type of clause.types) {
451
+ try {
452
+ const typeNode = checker.getTypeAtLocation(type);
453
+ interfaces.push(checker.typeToString(typeNode, type));
454
+ }
455
+ catch (error) {
456
+ // If type checking fails, use the text
457
+ interfaces.push(type.getText());
458
+ }
459
+ }
460
+ }
461
+ }
462
+ return { parentClass, interfaces };
463
+ }
464
+ static hasExportModifier(node) {
465
+ return (ts.canHaveModifiers(node) && (ts.getModifiers(node)?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword) ?? false));
466
+ }
467
+ static getLineNumber(sourceFile, node) {
468
+ const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
469
+ return line + 1; // Convert to 1-based line number
470
+ }
471
+ static getRelativePath(absolutePath, packageRoot) {
472
+ const relative = absolutePath.replace(packageRoot, '').replace(/^\//, '');
473
+ return relative || absolutePath;
474
+ }
475
+ static async loadPreviousErrors(projectRoot, packageName) {
476
+ const indexPath = ExportMapper.getIndexPath(projectRoot, packageName);
477
+ const errorFilePath = pathResolve(indexPath, '_export-errors.json');
478
+ if (!await FileSystemUtils.file.exists(errorFilePath)) {
479
+ return null;
480
+ }
481
+ try {
482
+ const errorFile = await FileSystemUtils.file.read.json(errorFilePath);
483
+ return errorFile.errors || [];
484
+ }
485
+ catch (error) {
486
+ return null;
487
+ }
488
+ }
489
+ static async writeErrors(projectRoot, packageName, errors) {
490
+ const indexPath = ExportMapper.getIndexPath(projectRoot, packageName);
491
+ await FileSystemUtils.folder.create(indexPath);
492
+ if (errors.length === 0) {
493
+ // Remove error file if no errors
494
+ const errorFilePath = pathResolve(indexPath, '_export-errors.json');
495
+ if (await FileSystemUtils.file.exists(errorFilePath)) {
496
+ await FileSystemUtils.file.delete(errorFilePath);
497
+ }
498
+ return;
499
+ }
500
+ const errorFile = {
501
+ package: packageName,
502
+ timestamp: new Date().toISOString(),
503
+ errors
504
+ };
505
+ const errorFilePath = pathResolve(indexPath, '_export-errors.json');
506
+ await FileSystemUtils.file.write(errorFilePath, __stringify(errorFile, true));
507
+ }
508
+ static shouldRetryError(error, retryErrors) {
509
+ if (!error.retryable) {
510
+ return false;
511
+ }
512
+ if (!retryErrors || retryErrors.length === 0) {
513
+ // If no retryErrors provided, don't retry (means we're not in retry mode)
514
+ return false;
515
+ }
516
+ // Check if this error exists in retryErrors (meaning it should be retried)
517
+ return retryErrors.some(e => e.path === error.path && e.level === error.level);
518
+ }
519
+ }