@vendure/dashboard 3.3.6-master-202507110238 → 3.3.6

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 (68) hide show
  1. package/dist/plugin/types.d.ts +40 -0
  2. package/dist/plugin/utils/ast-utils.d.ts +0 -5
  3. package/dist/plugin/utils/ast-utils.js +0 -67
  4. package/dist/plugin/utils/ast-utils.spec.js +1 -76
  5. package/dist/plugin/utils/compiler.d.ts +22 -0
  6. package/dist/plugin/utils/compiler.js +162 -0
  7. package/dist/plugin/utils/config-loader.d.ts +0 -120
  8. package/dist/plugin/utils/config-loader.js +1 -367
  9. package/dist/plugin/utils/logger.d.ts +3 -0
  10. package/dist/plugin/utils/logger.js +39 -0
  11. package/dist/plugin/utils/plugin-discovery.d.ts +27 -0
  12. package/dist/plugin/utils/plugin-discovery.js +343 -0
  13. package/dist/plugin/utils/tsconfig-utils.d.ts +9 -0
  14. package/dist/plugin/utils/tsconfig-utils.js +50 -0
  15. package/dist/plugin/vite-plugin-config-loader.d.ts +3 -3
  16. package/dist/plugin/vite-plugin-config-loader.js +13 -13
  17. package/dist/plugin/vite-plugin-dashboard-metadata.js +19 -2
  18. package/dist/plugin/vite-plugin-vendure-dashboard.d.ts +7 -7
  19. package/dist/plugin/vite-plugin-vendure-dashboard.js +2 -2
  20. package/package.json +134 -131
  21. package/src/app/routes/_authenticated/_orders/components/customer-address-selector.tsx +0 -1
  22. package/src/app/routes/_authenticated/_orders/components/payment-details.tsx +6 -2
  23. package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +2 -2
  24. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +0 -1
  25. package/src/app/routes/_authenticated/_products/components/option-value-input.tsx +1 -1
  26. package/src/app/routes/_authenticated/_zones/components/zone-countries-table.tsx +0 -7
  27. package/src/lib/components/layout/content-language-selector.tsx +1 -1
  28. package/src/lib/components/shared/asset/asset-preview.tsx +0 -6
  29. package/src/lib/components/shared/option-value-input.tsx +1 -1
  30. package/src/lib/components/shared/product-variant-selector.tsx +1 -1
  31. package/src/lib/components/ui/calendar.tsx +1 -1
  32. package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +1 -1
  33. package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +0 -2
  34. package/src/lib/hooks/use-extended-list-query.ts +32 -30
  35. package/vite/tests/barrel-exports.spec.ts +13 -4
  36. package/{dist/plugin/tests/barrel-exports/my-plugin/src/my.plugin.js → vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/index.js} +6 -6
  37. package/vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/package.json +8 -0
  38. package/vite/tests/fixtures-npm-plugin/package.json +6 -0
  39. package/{dist/plugin/tests/barrel-exports/vendure-config.js → vite/tests/fixtures-npm-plugin/vendure-config.ts} +5 -6
  40. package/vite/tests/fixtures-path-alias/aliased-plugin/index.ts +1 -0
  41. package/vite/tests/fixtures-path-alias/aliased-plugin/src/aliased.plugin.ts +8 -0
  42. package/vite/tests/fixtures-path-alias/package.json +6 -0
  43. package/vite/tests/fixtures-path-alias/vendure-config.ts +19 -0
  44. package/vite/tests/npm-plugin.spec.ts +46 -0
  45. package/vite/tests/path-alias.spec.ts +33 -0
  46. package/vite/tests/tsconfig.json +11 -0
  47. package/vite/types.ts +44 -0
  48. package/vite/utils/ast-utils.spec.ts +1 -80
  49. package/vite/utils/ast-utils.ts +0 -86
  50. package/vite/utils/compiler.ts +244 -0
  51. package/vite/utils/config-loader.ts +0 -555
  52. package/vite/utils/logger.ts +43 -0
  53. package/vite/utils/plugin-discovery.ts +442 -0
  54. package/vite/utils/tsconfig-utils.ts +79 -0
  55. package/vite/vite-plugin-config-loader.ts +20 -17
  56. package/vite/vite-plugin-dashboard-metadata.ts +26 -7
  57. package/vite/vite-plugin-tailwind-source.ts +2 -2
  58. package/vite/vite-plugin-vendure-dashboard.ts +9 -9
  59. package/dist/plugin/tests/barrel-exports/my-plugin/index.d.ts +0 -1
  60. package/dist/plugin/tests/barrel-exports/my-plugin/index.js +0 -17
  61. package/dist/plugin/tests/barrel-exports/my-plugin/src/my.plugin.d.ts +0 -2
  62. package/dist/plugin/tests/barrel-exports/vendure-config.d.ts +0 -2
  63. package/dist/plugin/tests/barrel-exports.spec.js +0 -14
  64. /package/dist/plugin/{tests/barrel-exports.spec.d.ts → types.js} +0 -0
  65. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/my-plugin/index.ts +0 -0
  66. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/my-plugin/src/my.plugin.ts +0 -0
  67. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/package.json +0 -0
  68. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/vendure-config.ts +0 -0
@@ -0,0 +1,8 @@
1
+ import { PluginCommonModule, VendurePlugin } from '@vendure/core';
2
+
3
+ @VendurePlugin({
4
+ imports: [PluginCommonModule],
5
+ providers: [],
6
+ dashboard: './dashboard/index.tsx',
7
+ })
8
+ export class AliasedPlugin {}
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "commonjs",
3
+ "name": "aliased-plugin",
4
+ "version": "0.0.1",
5
+ "main": "index.ts"
6
+ }
@@ -0,0 +1,19 @@
1
+ import { VendureConfig } from '@vendure/core';
2
+
3
+ import { AliasedPlugin } from './aliased-plugin';
4
+
5
+ export const config: VendureConfig = {
6
+ apiOptions: {
7
+ port: 3000,
8
+ },
9
+ authOptions: {
10
+ tokenMethod: 'bearer',
11
+ },
12
+ dbConnectionOptions: {
13
+ type: 'postgres',
14
+ },
15
+ paymentOptions: {
16
+ paymentMethodHandlers: [],
17
+ },
18
+ plugins: [AliasedPlugin],
19
+ };
@@ -0,0 +1,46 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import tsconfigPaths from 'tsconfig-paths';
4
+ import { describe, expect, it } from 'vitest';
5
+
6
+ import { compile } from '../utils/compiler.js';
7
+ import { debugLogger, noopLogger } from '../utils/logger.js';
8
+
9
+ describe('detecting plugins in npm packages', () => {
10
+ it(
11
+ 'should detect plugins in npm packages',
12
+ async () => {
13
+ const tempDir = join(__dirname, './__temp/npm-plugin');
14
+ await rm(tempDir, { recursive: true, force: true });
15
+ const fakeNodeModules = join(__dirname, 'fixtures-npm-plugin', 'fake_node_modules');
16
+
17
+ // For this test to work, we need to use tsconfigPaths to point
18
+ // the `test-plugin` package to the `fake_node_modules` directory.
19
+ // This is because the `test-plugin` package is not installed in
20
+ // the `node_modules` directory, but in the `fake_node_modules`
21
+ // directory.
22
+ tsconfigPaths.register({
23
+ baseUrl: fakeNodeModules,
24
+ paths: {
25
+ 'test-plugin': [join(fakeNodeModules, 'test-plugin')],
26
+ },
27
+ });
28
+
29
+ const result = await compile({
30
+ outputPath: tempDir,
31
+ vendureConfigPath: join(__dirname, 'fixtures-npm-plugin', 'vendure-config.ts'),
32
+ logger: process.env.LOG ? debugLogger : noopLogger,
33
+ pluginPackageScanner: {
34
+ nodeModulesRoot: fakeNodeModules,
35
+ },
36
+ });
37
+
38
+ expect(result.pluginInfo).toHaveLength(1);
39
+ expect(result.pluginInfo[0].name).toBe('TestPlugin');
40
+ expect(result.pluginInfo[0].dashboardEntryPath).toBe('./dashboard/index.tsx');
41
+ expect(result.pluginInfo[0].sourcePluginPath).toBeUndefined();
42
+ expect(result.pluginInfo[0].pluginPath).toBe(join(fakeNodeModules, 'test-plugin', 'index.js'));
43
+ },
44
+ { timeout: 10_000 },
45
+ );
46
+ });
@@ -0,0 +1,33 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ import { compile } from '../utils/compiler.js';
6
+ import { debugLogger, noopLogger } from '../utils/logger.js';
7
+
8
+ describe('detecting plugins using tsconfig path aliases', () => {
9
+ it(
10
+ 'should detect plugins using tsconfig path aliases',
11
+ async () => {
12
+ const tempDir = join(__dirname, './__temp/path-alias');
13
+ await rm(tempDir, { recursive: true, force: true });
14
+
15
+ const result = await compile({
16
+ outputPath: tempDir,
17
+ vendureConfigPath: join(__dirname, 'fixtures-path-alias', 'vendure-config.ts'),
18
+ logger: process.env.LOG ? debugLogger : noopLogger,
19
+ });
20
+
21
+ expect(result.pluginInfo).toHaveLength(1);
22
+ expect(result.pluginInfo[0].name).toBe('AliasedPlugin');
23
+ expect(result.pluginInfo[0].dashboardEntryPath).toBe('./dashboard/index.tsx');
24
+ expect(result.pluginInfo[0].sourcePluginPath).toBe(
25
+ join(__dirname, 'fixtures-path-alias', 'aliased-plugin', 'src', 'aliased.plugin.ts'),
26
+ );
27
+ expect(result.pluginInfo[0].pluginPath).toBe(
28
+ join(tempDir, 'aliased-plugin', 'src', 'aliased.plugin.js'),
29
+ );
30
+ },
31
+ { timeout: 10_000 },
32
+ );
33
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "NodeNext",
4
+ "sourceMap": true,
5
+ "jsx": "react-jsx",
6
+ "paths": {
7
+ "@plugins/*": ["./fixtures-path-alias/*"]
8
+ }
9
+ },
10
+ "exclude": ["node_modules"]
11
+ }
package/vite/types.ts ADDED
@@ -0,0 +1,44 @@
1
+ export type Logger = {
2
+ info: (message: string) => void;
3
+ warn: (message: string) => void;
4
+ debug: (message: string) => void;
5
+ error: (message: string) => void;
6
+ };
7
+
8
+ export type PluginInfo = {
9
+ name: string;
10
+ pluginPath: string;
11
+ dashboardEntryPath: string | undefined;
12
+ /** The original source path of the plugin, only set for local plugins that are compiled */
13
+ sourcePluginPath?: string;
14
+ };
15
+
16
+ export type GetCompiledConfigPathFn = (params: {
17
+ inputRootDir: string;
18
+ outputPath: string;
19
+ configFileName: string;
20
+ }) => string;
21
+
22
+ export type TransformTsConfigPathMappingsFn = (params: {
23
+ phase: 'compiling' | 'loading';
24
+ alias: string;
25
+ patterns: string[];
26
+ }) => string[];
27
+
28
+ /**
29
+ * @description
30
+ * The PathAdapter interface allows customization of how paths are handled
31
+ * when compiling the Vendure config and its imports.
32
+ */
33
+ export interface PathAdapter {
34
+ /**
35
+ * @description
36
+ * A function to determine the path to the compiled Vendure config file.
37
+ */
38
+ getCompiledConfigPath?: GetCompiledConfigPathFn;
39
+ /**
40
+ * If your project makes use of the TypeScript `paths` configuration, the compiler will
41
+ * attempt to use these paths when compiling the Vendure config and its imports.
42
+ */
43
+ transformTsConfigPathMappings?: TransformTsConfigPathMappingsFn;
44
+ }
@@ -1,86 +1,7 @@
1
1
  import ts from 'typescript';
2
2
  import { describe, expect, it } from 'vitest';
3
3
 
4
- import { findConfigExport, getPluginInfo } from './ast-utils.js';
5
-
6
- describe('getPluginInfo', () => {
7
- it('should return undefined when no plugin class is found', () => {
8
- const sourceText = `
9
- class NotAPlugin {
10
- constructor() {}
11
- }
12
- `;
13
- const sourceFile = ts.createSourceFile('path/to/test.ts', sourceText, ts.ScriptTarget.Latest, true);
14
- const result = getPluginInfo(sourceFile);
15
- expect(result).toBeUndefined();
16
- });
17
-
18
- it('should return plugin info when a valid plugin class is found', () => {
19
- const sourceText = `
20
- @VendurePlugin({
21
- imports: [],
22
- providers: []
23
- })
24
- class TestPlugin {
25
- constructor() {}
26
- }
27
- `;
28
- const sourceFile = ts.createSourceFile('path/to/test.ts', sourceText, ts.ScriptTarget.Latest, true);
29
- const result = getPluginInfo(sourceFile);
30
- expect(result).toEqual({
31
- name: 'TestPlugin',
32
- pluginPath: 'path/to',
33
- dashboardEntryPath: undefined,
34
- });
35
- });
36
-
37
- it('should handle multiple classes but only return the plugin one', () => {
38
- const sourceText = `
39
- class NotAPlugin {
40
- constructor() {}
41
- }
42
-
43
- @VendurePlugin({
44
- imports: [],
45
- providers: []
46
- })
47
- class TestPlugin {
48
- constructor() {}
49
- }
50
-
51
- class AnotherClass {
52
- constructor() {}
53
- }
54
- `;
55
- const sourceFile = ts.createSourceFile('path/to/test.ts', sourceText, ts.ScriptTarget.Latest, true);
56
- const result = getPluginInfo(sourceFile);
57
- expect(result).toEqual({
58
- name: 'TestPlugin',
59
- pluginPath: 'path/to',
60
- dashboardEntryPath: undefined,
61
- });
62
- });
63
-
64
- it('should determine the dashboard entry path when it is provided', () => {
65
- const sourceText = `
66
- @VendurePlugin({
67
- imports: [],
68
- providers: [],
69
- dashboard: './dashboard/index.tsx',
70
- })
71
- class TestPlugin {
72
- constructor() {}
73
- }
74
- `;
75
- const sourceFile = ts.createSourceFile('path/to/test.ts', sourceText, ts.ScriptTarget.Latest, true);
76
- const result = getPluginInfo(sourceFile);
77
- expect(result).toEqual({
78
- name: 'TestPlugin',
79
- pluginPath: 'path/to',
80
- dashboardEntryPath: './dashboard/index.tsx',
81
- });
82
- });
83
- });
4
+ import { findConfigExport } from './ast-utils.js';
84
5
 
85
6
  describe('findConfigExport', () => {
86
7
  it('should return undefined when no VendureConfig export is found', () => {
@@ -1,70 +1,5 @@
1
- import path from 'path';
2
1
  import ts from 'typescript';
3
2
 
4
- import { PluginInfo } from './config-loader.js';
5
-
6
- /**
7
- * Get the plugin info from the source file.
8
- */
9
- export function getPluginInfo(sourceFile: ts.SourceFile): PluginInfo | undefined {
10
- const classDeclaration = sourceFile.statements.find(statement => {
11
- return (
12
- statement.kind === ts.SyntaxKind.ClassDeclaration &&
13
- statement.getText().includes('@VendurePlugin(')
14
- );
15
- });
16
- if (classDeclaration) {
17
- const identifier = classDeclaration.getChildren().find(child => {
18
- return child.kind === ts.SyntaxKind.Identifier;
19
- });
20
- const dashboardEntryPath = classDeclaration
21
- .getChildren()
22
- .map(child => {
23
- if (child.kind === ts.SyntaxKind.SyntaxList) {
24
- const pluginDecorator = child.getChildren().find(_child => {
25
- return _child.kind === ts.SyntaxKind.Decorator;
26
- });
27
- if (pluginDecorator) {
28
- const callExpression = findFirstDescendantOfKind(
29
- pluginDecorator,
30
- ts.SyntaxKind.CallExpression,
31
- );
32
- if (callExpression) {
33
- const objectLiteral = findFirstDescendantOfKind(
34
- callExpression,
35
- ts.SyntaxKind.ObjectLiteralExpression,
36
- );
37
- if (objectLiteral && ts.isObjectLiteralExpression(objectLiteral)) {
38
- // Now find the specific 'dashboard' property
39
- const dashboardProperty = objectLiteral.properties.find(
40
- prop =>
41
- ts.isPropertyAssignment(prop) && prop.name?.getText() === 'dashboard',
42
- );
43
-
44
- if (
45
- dashboardProperty &&
46
- ts.isPropertyAssignment(dashboardProperty) &&
47
- ts.isStringLiteral(dashboardProperty.initializer)
48
- ) {
49
- const dashboardPath = dashboardProperty.initializer.text;
50
- return dashboardPath;
51
- }
52
- }
53
- }
54
- }
55
- }
56
- })
57
- .filter(Boolean)?.[0];
58
- if (identifier) {
59
- return {
60
- name: identifier.getText(),
61
- pluginPath: path.dirname(sourceFile.fileName),
62
- dashboardEntryPath,
63
- };
64
- }
65
- }
66
- }
67
-
68
3
  /**
69
4
  * Given the AST of a TypeScript file, finds the name of the variable exported as VendureConfig.
70
5
  */
@@ -96,24 +31,3 @@ export function findConfigExport(sourceFile: ts.SourceFile): string | undefined
96
31
  visit(sourceFile);
97
32
  return exportedSymbolName;
98
33
  }
99
-
100
- function findFirstDescendantOfKind(node: ts.Node, kind: ts.SyntaxKind): ts.Node | undefined {
101
- let foundNode: ts.Node | undefined;
102
-
103
- function visit(_node: ts.Node) {
104
- if (foundNode) {
105
- // Stop searching if we already found it
106
- return;
107
- }
108
- if (_node.kind === kind) {
109
- foundNode = _node;
110
- return;
111
- }
112
- // Recursively visit children
113
- ts.forEachChild(_node, visit);
114
- }
115
-
116
- // Start the traversal from the initial node's children
117
- ts.forEachChild(node, visit);
118
- return foundNode;
119
- }
@@ -0,0 +1,244 @@
1
+ import { VendureConfig } from '@vendure/core';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import tsConfigPaths from 'tsconfig-paths';
5
+ import { RegisterParams } from 'tsconfig-paths/lib/register.js';
6
+ import * as ts from 'typescript';
7
+ import { pathToFileURL } from 'url';
8
+
9
+ import { Logger, PathAdapter, PluginInfo } from '../types.js';
10
+
11
+ import { findConfigExport } from './ast-utils.js';
12
+ import { noopLogger } from './logger.js';
13
+ import { discoverPlugins } from './plugin-discovery.js';
14
+ import { findTsConfigPaths } from './tsconfig-utils.js';
15
+
16
+ const defaultPathAdapter: Required<PathAdapter> = {
17
+ getCompiledConfigPath: ({ outputPath, configFileName }) => path.join(outputPath, configFileName),
18
+ transformTsConfigPathMappings: ({ patterns }) => patterns,
19
+ };
20
+
21
+ export interface PackageScannerConfig {
22
+ nodeModulesRoot?: string;
23
+ }
24
+
25
+ export interface CompilerOptions {
26
+ vendureConfigPath: string;
27
+ outputPath: string;
28
+ pathAdapter?: PathAdapter;
29
+ logger?: Logger;
30
+ pluginPackageScanner?: PackageScannerConfig;
31
+ }
32
+
33
+ export interface CompileResult {
34
+ vendureConfig: VendureConfig;
35
+ exportedSymbolName: string;
36
+ pluginInfo: PluginInfo[];
37
+ }
38
+
39
+ /**
40
+ * Compiles TypeScript files and discovers Vendure plugins in both the compiled output
41
+ * and in node_modules.
42
+ */
43
+ export async function compile(options: CompilerOptions): Promise<CompileResult> {
44
+ const { vendureConfigPath, outputPath, pathAdapter, logger = noopLogger, pluginPackageScanner } = options;
45
+ const getCompiledConfigPath =
46
+ pathAdapter?.getCompiledConfigPath ?? defaultPathAdapter.getCompiledConfigPath;
47
+ const transformTsConfigPathMappings =
48
+ pathAdapter?.transformTsConfigPathMappings ?? defaultPathAdapter.transformTsConfigPathMappings;
49
+
50
+ // 1. Compile TypeScript files
51
+ const compileStart = Date.now();
52
+ await compileTypeScript({
53
+ inputPath: vendureConfigPath,
54
+ outputPath,
55
+ logger,
56
+ transformTsConfigPathMappings,
57
+ });
58
+ logger.info(`TypeScript compilation completed in ${Date.now() - compileStart}ms`);
59
+
60
+ // 2. Discover plugins
61
+ const analyzePluginsStart = Date.now();
62
+ const plugins = await discoverPlugins({
63
+ vendureConfigPath,
64
+ transformTsConfigPathMappings,
65
+ logger,
66
+ outputPath,
67
+ pluginPackageScanner,
68
+ });
69
+ logger.info(
70
+ `Analyzed plugins and found ${plugins.length} dashboard extensions in ${Date.now() - analyzePluginsStart}ms`,
71
+ );
72
+
73
+ // 3. Load the compiled config
74
+ const configFileName = path.basename(vendureConfigPath);
75
+ const compiledConfigFilePath = pathToFileURL(
76
+ getCompiledConfigPath({
77
+ inputRootDir: path.dirname(vendureConfigPath),
78
+ outputPath,
79
+ configFileName,
80
+ }),
81
+ ).href.replace(/.ts$/, '.js');
82
+
83
+ // Create package.json with type commonjs
84
+ await fs.writeFile(
85
+ path.join(outputPath, 'package.json'),
86
+ JSON.stringify({ type: 'commonjs', private: true }, null, 2),
87
+ );
88
+
89
+ // Find the exported config symbol
90
+ const sourceFile = ts.createSourceFile(
91
+ vendureConfigPath,
92
+ await fs.readFile(vendureConfigPath, 'utf-8'),
93
+ ts.ScriptTarget.Latest,
94
+ true,
95
+ );
96
+ const exportedSymbolName = findConfigExport(sourceFile);
97
+ if (!exportedSymbolName) {
98
+ throw new Error(
99
+ `Could not find a variable exported as VendureConfig. Please specify the name of the exported variable.`,
100
+ );
101
+ }
102
+
103
+ const loadConfigStart = Date.now();
104
+
105
+ await registerTsConfigPaths({
106
+ outputPath,
107
+ configPath: vendureConfigPath,
108
+ logger,
109
+ phase: 'loading',
110
+ transformTsConfigPathMappings,
111
+ });
112
+
113
+ let config: any;
114
+ try {
115
+ config = await import(compiledConfigFilePath).then(m => m[exportedSymbolName]);
116
+ } catch (e) {
117
+ logger.error(`Error loading config: ${e instanceof Error ? e.message : String(e)}`);
118
+ }
119
+ if (!config) {
120
+ throw new Error(
121
+ `Could not find a variable exported as VendureConfig with the name "${exportedSymbolName}".`,
122
+ );
123
+ }
124
+ logger.debug(`Loaded config in ${Date.now() - loadConfigStart}ms`);
125
+
126
+ return { vendureConfig: config, exportedSymbolName, pluginInfo: plugins };
127
+ }
128
+
129
+ /**
130
+ * Compiles TypeScript files to JavaScript
131
+ */
132
+ async function compileTypeScript({
133
+ inputPath,
134
+ outputPath,
135
+ logger,
136
+ transformTsConfigPathMappings,
137
+ }: {
138
+ inputPath: string;
139
+ outputPath: string;
140
+ logger: Logger;
141
+ transformTsConfigPathMappings: Required<PathAdapter>['transformTsConfigPathMappings'];
142
+ }): Promise<void> {
143
+ await fs.ensureDir(outputPath);
144
+
145
+ // Find tsconfig paths first
146
+ const tsConfigInfo = await findTsConfigPaths(
147
+ inputPath,
148
+ logger,
149
+ 'compiling',
150
+ transformTsConfigPathMappings,
151
+ );
152
+
153
+ const compilerOptions: ts.CompilerOptions = {
154
+ target: ts.ScriptTarget.ES2020,
155
+ module: ts.ModuleKind.CommonJS,
156
+ moduleResolution: ts.ModuleResolutionKind.Node10, // More explicit CJS resolution
157
+ experimentalDecorators: true,
158
+ emitDecoratorMetadata: true,
159
+ esModuleInterop: true,
160
+ skipLibCheck: true,
161
+ noEmit: false,
162
+ // Speed optimizations
163
+ noEmitOnError: false, // Emit output even if there are errors
164
+ noImplicitAny: false, // Don't require implicit any
165
+ noUnusedLocals: false, // Don't check for unused locals
166
+ noUnusedParameters: false, // Don't check for unused parameters
167
+ allowJs: true,
168
+ checkJs: false, // Don't type check JS files
169
+ skipDefaultLibCheck: true, // Skip checking .d.ts files
170
+ isolatedModules: false, // Need to check cross-file references to compile dependencies
171
+ incremental: false, // Don't use incremental compilation (faster for one-off builds)
172
+ resolveJsonModule: true,
173
+ preserveSymlinks: false,
174
+ outDir: outputPath,
175
+ };
176
+
177
+ logger.debug(`Compiling ${inputPath} to ${outputPath} using TypeScript...`);
178
+
179
+ // Add path mappings if found
180
+ if (tsConfigInfo) {
181
+ // We need to set baseUrl and paths for TypeScript to resolve the imports
182
+ compilerOptions.baseUrl = tsConfigInfo.baseUrl;
183
+ compilerOptions.paths = tsConfigInfo.paths;
184
+ // This is critical - it tells TypeScript to preserve the paths in the output
185
+ // compilerOptions.rootDir = tsConfigInfo.baseUrl;
186
+ }
187
+
188
+ logger.debug(`tsConfig paths: ${JSON.stringify(tsConfigInfo?.paths, null, 2)}`);
189
+ logger.debug(`tsConfig baseUrl: ${tsConfigInfo?.baseUrl ?? 'UNKNOWN'}`);
190
+
191
+ // Create a custom transformer to rewrite the output paths
192
+ const customTransformers: ts.CustomTransformers = {
193
+ after: [
194
+ context => {
195
+ return sourceFile => {
196
+ // Only transform files that are not the entry point
197
+ if (sourceFile.fileName === inputPath) {
198
+ return sourceFile;
199
+ }
200
+ sourceFile.fileName = path.join(outputPath, path.basename(sourceFile.fileName));
201
+ return sourceFile;
202
+ };
203
+ },
204
+ ],
205
+ };
206
+
207
+ const program = ts.createProgram([inputPath], compilerOptions);
208
+ const emitResult = program.emit(undefined, undefined, undefined, undefined, customTransformers);
209
+
210
+ // Only log actual emit errors, not type errors
211
+ if (emitResult.emitSkipped) {
212
+ for (const diagnostic of emitResult.diagnostics) {
213
+ if (diagnostic.file && diagnostic.start !== undefined) {
214
+ const { line, character } = ts.getLineAndCharacterOfPosition(
215
+ diagnostic.file,
216
+ diagnostic.start,
217
+ );
218
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
219
+ logger.warn(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
220
+ } else {
221
+ logger.warn(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ async function registerTsConfigPaths(options: {
228
+ outputPath: string;
229
+ configPath: string;
230
+ logger: Logger;
231
+ phase: 'compiling' | 'loading';
232
+ transformTsConfigPathMappings: Required<PathAdapter>['transformTsConfigPathMappings'];
233
+ }) {
234
+ const { outputPath, configPath, logger, phase, transformTsConfigPathMappings } = options;
235
+ const tsConfigInfo = await findTsConfigPaths(configPath, logger, phase, transformTsConfigPathMappings);
236
+ if (tsConfigInfo) {
237
+ const params: RegisterParams = {
238
+ baseUrl: outputPath,
239
+ paths: tsConfigInfo.paths,
240
+ };
241
+ logger.debug(`Registering tsconfig paths: ${JSON.stringify(params, null, 2)}`);
242
+ tsConfigPaths.register(params);
243
+ }
244
+ }