@vendure/dashboard 3.4.1-master-202508020237 → 3.4.1-master-202508040248
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/dist/vite/utils/schema-generator.js +17 -12
- package/package.json +154 -155
- package/vite/constants.ts +0 -280
- package/vite/index.ts +0 -1
- package/vite/tests/barrel-exports.spec.ts +0 -30
- package/vite/tests/fixtures-barrel-exports/my-plugin/index.ts +0 -1
- package/vite/tests/fixtures-barrel-exports/my-plugin/src/my.plugin.ts +0 -8
- package/vite/tests/fixtures-barrel-exports/package.json +0 -6
- package/vite/tests/fixtures-barrel-exports/vendure-config.ts +0 -19
- package/vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/index.js +0 -20
- package/vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/package.json +0 -8
- package/vite/tests/fixtures-npm-plugin/package.json +0 -6
- package/vite/tests/fixtures-npm-plugin/vendure-config.ts +0 -18
- package/vite/tests/fixtures-path-alias/js-aliased/index.ts +0 -1
- package/vite/tests/fixtures-path-alias/js-aliased/src/js-aliased.plugin.ts +0 -8
- package/vite/tests/fixtures-path-alias/package.json +0 -6
- package/vite/tests/fixtures-path-alias/star-aliased/index.ts +0 -1
- package/vite/tests/fixtures-path-alias/star-aliased/src/star-aliased.plugin.ts +0 -8
- package/vite/tests/fixtures-path-alias/ts-aliased/index.ts +0 -1
- package/vite/tests/fixtures-path-alias/ts-aliased/src/ts-aliased.plugin.ts +0 -8
- package/vite/tests/fixtures-path-alias/vendure-config.ts +0 -20
- package/vite/tests/npm-plugin.spec.ts +0 -46
- package/vite/tests/path-alias.spec.ts +0 -61
- package/vite/tests/tsconfig.json +0 -21
- package/vite/types.ts +0 -44
- package/vite/utils/ast-utils.spec.ts +0 -49
- package/vite/utils/ast-utils.ts +0 -33
- package/vite/utils/compiler.ts +0 -244
- package/vite/utils/config-loader.ts +0 -0
- package/vite/utils/logger.ts +0 -43
- package/vite/utils/plugin-discovery.ts +0 -494
- package/vite/utils/schema-generator.ts +0 -45
- package/vite/utils/tsconfig-utils.ts +0 -79
- package/vite/utils/ui-config.ts +0 -52
- package/vite/vite-plugin-admin-api-schema.ts +0 -131
- package/vite/vite-plugin-config-loader.ts +0 -84
- package/vite/vite-plugin-config.ts +0 -70
- package/vite/vite-plugin-dashboard-metadata.ts +0 -73
- package/vite/vite-plugin-gql-tada.ts +0 -62
- package/vite/vite-plugin-tailwind-source.ts +0 -81
- package/vite/vite-plugin-theme.ts +0 -195
- package/vite/vite-plugin-transform-index.ts +0 -40
- package/vite/vite-plugin-ui-config.ts +0 -163
- package/vite/vite-plugin-vendure-dashboard.ts +0 -174
|
@@ -1,494 +0,0 @@
|
|
|
1
|
-
import { parse } from 'acorn';
|
|
2
|
-
import { simple as walkSimple } from 'acorn-walk';
|
|
3
|
-
import glob from 'fast-glob';
|
|
4
|
-
import fs from 'fs-extra';
|
|
5
|
-
import { open } from 'fs/promises';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import * as ts from 'typescript';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
9
|
-
|
|
10
|
-
import { Logger, PluginInfo, TransformTsConfigPathMappingsFn } from '../types.js';
|
|
11
|
-
|
|
12
|
-
import { PackageScannerConfig } from './compiler.js';
|
|
13
|
-
import { findTsConfigPaths, TsConfigPathsConfig } from './tsconfig-utils.js';
|
|
14
|
-
|
|
15
|
-
export async function discoverPlugins({
|
|
16
|
-
vendureConfigPath,
|
|
17
|
-
transformTsConfigPathMappings,
|
|
18
|
-
logger,
|
|
19
|
-
outputPath,
|
|
20
|
-
pluginPackageScanner,
|
|
21
|
-
}: {
|
|
22
|
-
vendureConfigPath: string;
|
|
23
|
-
transformTsConfigPathMappings: TransformTsConfigPathMappingsFn;
|
|
24
|
-
logger: Logger;
|
|
25
|
-
outputPath: string;
|
|
26
|
-
pluginPackageScanner?: PackageScannerConfig;
|
|
27
|
-
}): Promise<PluginInfo[]> {
|
|
28
|
-
const plugins: PluginInfo[] = [];
|
|
29
|
-
|
|
30
|
-
// Analyze source files to find local plugins and package imports
|
|
31
|
-
const { localPluginLocations, packageImports } = await analyzeSourceFiles(
|
|
32
|
-
vendureConfigPath,
|
|
33
|
-
pluginPackageScanner?.nodeModulesRoot ?? guessNodeModulesRoot(vendureConfigPath, logger),
|
|
34
|
-
logger,
|
|
35
|
-
transformTsConfigPathMappings,
|
|
36
|
-
);
|
|
37
|
-
logger.debug(
|
|
38
|
-
`[discoverPlugins] Found ${localPluginLocations.size} local plugins: ${JSON.stringify([...localPluginLocations.entries()], null, 2)}`,
|
|
39
|
-
);
|
|
40
|
-
logger.debug(
|
|
41
|
-
`[discoverPlugins] Found ${packageImports.length} package imports: ${JSON.stringify(packageImports, null, 2)}`,
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
const filePaths = await findVendurePluginFiles({
|
|
45
|
-
logger,
|
|
46
|
-
nodeModulesRoot: pluginPackageScanner?.nodeModulesRoot,
|
|
47
|
-
packageGlobs: packageImports.map(pkg => pkg + '/**/*.js'),
|
|
48
|
-
outputPath,
|
|
49
|
-
vendureConfigPath,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
for (const filePath of filePaths) {
|
|
53
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
54
|
-
logger.debug(`[discoverPlugins] Checking file ${filePath}`);
|
|
55
|
-
|
|
56
|
-
// First check if this file imports from @vendure/core
|
|
57
|
-
if (!content.includes('@vendure/core')) {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
const ast = parse(content, {
|
|
63
|
-
ecmaVersion: 'latest',
|
|
64
|
-
sourceType: 'module',
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
let hasVendurePlugin = false;
|
|
68
|
-
let pluginName: string | undefined;
|
|
69
|
-
let dashboardPath: string | undefined;
|
|
70
|
-
|
|
71
|
-
// Walk the AST to find the plugin class and its decorator
|
|
72
|
-
walkSimple(ast, {
|
|
73
|
-
CallExpression(node: any) {
|
|
74
|
-
// Look for __decorate calls
|
|
75
|
-
const calleeName = node.callee.name;
|
|
76
|
-
const nodeArgs = node.arguments;
|
|
77
|
-
const isDecoratorWithArgs = calleeName === '__decorate' && nodeArgs.length >= 2;
|
|
78
|
-
|
|
79
|
-
if (isDecoratorWithArgs) {
|
|
80
|
-
// Check the decorators array (first argument)
|
|
81
|
-
const decorators = nodeArgs[0];
|
|
82
|
-
if (decorators.type === 'ArrayExpression') {
|
|
83
|
-
for (const decorator of decorators.elements) {
|
|
84
|
-
const props = getDecoratorObjectProps(decorator);
|
|
85
|
-
for (const prop of props) {
|
|
86
|
-
const isDashboardProd =
|
|
87
|
-
prop.key.name === 'dashboard' && prop.value.type === 'Literal';
|
|
88
|
-
if (isDashboardProd) {
|
|
89
|
-
dashboardPath = prop.value.value;
|
|
90
|
-
hasVendurePlugin = true;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// Get the plugin class name (second argument)
|
|
96
|
-
const targetClass = nodeArgs[1];
|
|
97
|
-
if (targetClass.type === 'Identifier') {
|
|
98
|
-
pluginName = targetClass.name;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
if (hasVendurePlugin && pluginName && dashboardPath) {
|
|
105
|
-
logger.debug(`[discoverPlugins] Found plugin "${pluginName}" in file: ${filePath}`);
|
|
106
|
-
// Keep the dashboard path relative to the plugin file
|
|
107
|
-
const resolvedDashboardPath = dashboardPath.startsWith('.')
|
|
108
|
-
? dashboardPath // Keep the relative path as-is
|
|
109
|
-
: './' + path.relative(path.dirname(filePath), dashboardPath); // Make absolute path relative
|
|
110
|
-
|
|
111
|
-
// Check if this is a local plugin we found earlier
|
|
112
|
-
const sourcePluginPath = localPluginLocations.get(pluginName);
|
|
113
|
-
|
|
114
|
-
plugins.push({
|
|
115
|
-
name: pluginName,
|
|
116
|
-
pluginPath: filePath,
|
|
117
|
-
dashboardEntryPath: resolvedDashboardPath,
|
|
118
|
-
...(sourcePluginPath && { sourcePluginPath }),
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
} catch (e) {
|
|
122
|
-
logger.error(`Failed to parse ${filePath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return plugins;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getDecoratorObjectProps(decorator: any): any[] {
|
|
130
|
-
if (
|
|
131
|
-
decorator.type === 'CallExpression' &&
|
|
132
|
-
decorator.arguments.length === 1 &&
|
|
133
|
-
decorator.arguments[0].type === 'ObjectExpression'
|
|
134
|
-
) {
|
|
135
|
-
// Look for the dashboard property in the decorator config
|
|
136
|
-
return decorator.arguments[0].properties ?? [];
|
|
137
|
-
}
|
|
138
|
-
return [];
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async function isSymlinkedLocalPackage(
|
|
142
|
-
packageName: string,
|
|
143
|
-
nodeModulesRoot: string,
|
|
144
|
-
): Promise<string | undefined> {
|
|
145
|
-
try {
|
|
146
|
-
const packagePath = path.join(nodeModulesRoot, packageName);
|
|
147
|
-
const stats = await fs.lstat(packagePath);
|
|
148
|
-
if (stats.isSymbolicLink()) {
|
|
149
|
-
// Get the real path that the symlink points to
|
|
150
|
-
const realPath = await fs.realpath(packagePath);
|
|
151
|
-
// If the real path is within the project directory (i.e. not in some other node_modules),
|
|
152
|
-
// then it's a local package
|
|
153
|
-
if (!realPath.includes('node_modules')) {
|
|
154
|
-
return realPath;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
} catch (e) {
|
|
158
|
-
// Package doesn't exist or other error - not a local package
|
|
159
|
-
return undefined;
|
|
160
|
-
}
|
|
161
|
-
return undefined;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Analyzes TypeScript source files starting from the config file to discover:
|
|
166
|
-
* 1. Local Vendure plugins
|
|
167
|
-
* 2. All non-local package imports that could contain plugins
|
|
168
|
-
*/
|
|
169
|
-
export async function analyzeSourceFiles(
|
|
170
|
-
vendureConfigPath: string,
|
|
171
|
-
nodeModulesRoot: string,
|
|
172
|
-
logger: Logger,
|
|
173
|
-
transformTsConfigPathMappings: TransformTsConfigPathMappingsFn,
|
|
174
|
-
): Promise<{
|
|
175
|
-
localPluginLocations: Map<string, string>;
|
|
176
|
-
packageImports: string[];
|
|
177
|
-
}> {
|
|
178
|
-
const localPluginLocations = new Map<string, string>();
|
|
179
|
-
const visitedFiles = new Set<string>();
|
|
180
|
-
const packageImportsSet = new Set<string>();
|
|
181
|
-
|
|
182
|
-
// Get tsconfig paths for resolving aliases
|
|
183
|
-
const tsConfigInfo = await findTsConfigPaths(
|
|
184
|
-
vendureConfigPath,
|
|
185
|
-
logger,
|
|
186
|
-
'compiling',
|
|
187
|
-
transformTsConfigPathMappings,
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
async function processFile(filePath: string) {
|
|
191
|
-
if (visitedFiles.has(filePath)) {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
visitedFiles.add(filePath);
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
// First check if this is a directory
|
|
198
|
-
const stat = await fs.stat(filePath);
|
|
199
|
-
if (stat.isDirectory()) {
|
|
200
|
-
// If it's a directory, try to find the plugin file
|
|
201
|
-
const indexFilePath = path.join(filePath, 'index.ts');
|
|
202
|
-
if (await fs.pathExists(indexFilePath)) {
|
|
203
|
-
await processFile(indexFilePath);
|
|
204
|
-
}
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
209
|
-
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
210
|
-
|
|
211
|
-
// Track imports to follow
|
|
212
|
-
const importsToFollow: string[] = [];
|
|
213
|
-
|
|
214
|
-
async function visit(node: ts.Node) {
|
|
215
|
-
// Look for VendurePlugin decorator
|
|
216
|
-
const vendurePluginClassName = getVendurePluginClassName(node);
|
|
217
|
-
if (vendurePluginClassName) {
|
|
218
|
-
localPluginLocations.set(vendurePluginClassName, filePath);
|
|
219
|
-
logger.debug(`Found plugin "${vendurePluginClassName}" at ${filePath}`);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Handle both imports and exports
|
|
223
|
-
const isImportOrExport = ts.isImportDeclaration(node) || ts.isExportDeclaration(node);
|
|
224
|
-
if (isImportOrExport) {
|
|
225
|
-
const moduleSpecifier = node.moduleSpecifier;
|
|
226
|
-
if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
|
|
227
|
-
const importPath = moduleSpecifier.text;
|
|
228
|
-
|
|
229
|
-
// Track non-local imports (packages)
|
|
230
|
-
const npmPackageName = getNpmPackageNameFromImport(importPath);
|
|
231
|
-
if (npmPackageName) {
|
|
232
|
-
// Check if this is actually a symlinked local package
|
|
233
|
-
const localPackagePath = await isSymlinkedLocalPackage(
|
|
234
|
-
npmPackageName,
|
|
235
|
-
nodeModulesRoot,
|
|
236
|
-
);
|
|
237
|
-
if (localPackagePath) {
|
|
238
|
-
// If it is local, follow it like a local import
|
|
239
|
-
importsToFollow.push(localPackagePath);
|
|
240
|
-
logger.debug(
|
|
241
|
-
`Found symlinked local package "${npmPackageName}" at ${localPackagePath}`,
|
|
242
|
-
);
|
|
243
|
-
} else {
|
|
244
|
-
packageImportsSet.add(npmPackageName);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
// Handle path aliases and local imports
|
|
248
|
-
const pathAliasImports = getPotentialPathAliasImportPaths(importPath, tsConfigInfo);
|
|
249
|
-
if (pathAliasImports.length) {
|
|
250
|
-
importsToFollow.push(...pathAliasImports);
|
|
251
|
-
}
|
|
252
|
-
// Also handle local imports
|
|
253
|
-
if (importPath.startsWith('.')) {
|
|
254
|
-
const resolvedPath = path.resolve(path.dirname(filePath), importPath);
|
|
255
|
-
importsToFollow.push(resolvedPath);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Visit children
|
|
261
|
-
const promises: Array<Promise<void>> = [];
|
|
262
|
-
ts.forEachChild(node, child => {
|
|
263
|
-
promises.push(visit(child));
|
|
264
|
-
});
|
|
265
|
-
await Promise.all(promises);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
await visit(sourceFile);
|
|
269
|
-
|
|
270
|
-
// Follow imports
|
|
271
|
-
for (const importPath of importsToFollow) {
|
|
272
|
-
// Try all possible file paths
|
|
273
|
-
const possiblePaths = [
|
|
274
|
-
importPath + '.ts',
|
|
275
|
-
importPath + '.js',
|
|
276
|
-
path.join(importPath, 'index.ts'),
|
|
277
|
-
path.join(importPath, 'index.js'),
|
|
278
|
-
importPath,
|
|
279
|
-
];
|
|
280
|
-
if (importPath.endsWith('.js')) {
|
|
281
|
-
possiblePaths.push(importPath.replace(/.js$/, '.ts'));
|
|
282
|
-
}
|
|
283
|
-
// Try each possible path
|
|
284
|
-
let found = false;
|
|
285
|
-
for (const possiblePath of possiblePaths) {
|
|
286
|
-
const possiblePathExists = await fs.pathExists(possiblePath);
|
|
287
|
-
if (possiblePathExists) {
|
|
288
|
-
await processFile(possiblePath);
|
|
289
|
-
found = true;
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// If none of the file paths worked, try the raw import path
|
|
295
|
-
// (it might be a directory)
|
|
296
|
-
const tryRawPath = !found && (await fs.pathExists(importPath));
|
|
297
|
-
if (tryRawPath) {
|
|
298
|
-
await processFile(importPath);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
} catch (e) {
|
|
302
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
303
|
-
logger.error(`Failed to process ${filePath}: ${message}`);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
await processFile(vendureConfigPath);
|
|
308
|
-
return {
|
|
309
|
-
localPluginLocations,
|
|
310
|
-
packageImports: Array.from(packageImportsSet),
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* If this is a class declaration that is decorated with the `VendurePlugin` decorator,
|
|
316
|
-
* we want to return that class name, as we have found a local Vendure plugin.
|
|
317
|
-
*/
|
|
318
|
-
function getVendurePluginClassName(node: ts.Node): string | undefined {
|
|
319
|
-
if (ts.isClassDeclaration(node)) {
|
|
320
|
-
const decorators = ts.canHaveDecorators(node) ? ts.getDecorators(node) : undefined;
|
|
321
|
-
if (decorators?.length) {
|
|
322
|
-
for (const decorator of decorators) {
|
|
323
|
-
const decoratorName = getDecoratorName(decorator);
|
|
324
|
-
if (decoratorName === 'VendurePlugin') {
|
|
325
|
-
const className = node.name?.text;
|
|
326
|
-
if (className) {
|
|
327
|
-
return className;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function getNpmPackageNameFromImport(importPath: string): string | undefined {
|
|
336
|
-
if (!importPath.startsWith('.') && !importPath.startsWith('/')) {
|
|
337
|
-
// Get the root package name (e.g. '@scope/package/subpath' -> '@scope/package')
|
|
338
|
-
const packageName = importPath.startsWith('@')
|
|
339
|
-
? importPath.split('/').slice(0, 2).join('/')
|
|
340
|
-
: importPath.split('/')[0];
|
|
341
|
-
return packageName;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function getPotentialPathAliasImportPaths(importPath: string, tsConfigInfo?: TsConfigPathsConfig) {
|
|
346
|
-
const importsToFollow: string[] = [];
|
|
347
|
-
if (!tsConfigInfo) {
|
|
348
|
-
return importsToFollow;
|
|
349
|
-
}
|
|
350
|
-
for (const [alias, patterns] of Object.entries(tsConfigInfo.paths)) {
|
|
351
|
-
const aliasPattern = alias.replace(/\*$/, '');
|
|
352
|
-
if (importPath.startsWith(aliasPattern)) {
|
|
353
|
-
const relativePart = importPath.slice(aliasPattern.length);
|
|
354
|
-
// Try each pattern
|
|
355
|
-
for (const pattern of patterns) {
|
|
356
|
-
const resolvedPattern = pattern.replace(/\*$/, '');
|
|
357
|
-
const resolvedPath = path.resolve(tsConfigInfo.baseUrl, resolvedPattern, relativePart);
|
|
358
|
-
importsToFollow.push(resolvedPath);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
return importsToFollow;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function getDecoratorName(decorator: ts.Decorator): string | undefined {
|
|
366
|
-
if (ts.isCallExpression(decorator.expression)) {
|
|
367
|
-
const expression = decorator.expression.expression;
|
|
368
|
-
// Handle both direct usage and imported usage
|
|
369
|
-
if (ts.isIdentifier(expression)) {
|
|
370
|
-
return expression.text;
|
|
371
|
-
}
|
|
372
|
-
// Handle property access like `Decorators.VendurePlugin`
|
|
373
|
-
if (ts.isPropertyAccessExpression(expression)) {
|
|
374
|
-
return expression.name.text;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
return undefined;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
interface FindPluginFilesOptions {
|
|
381
|
-
outputPath: string;
|
|
382
|
-
vendureConfigPath: string;
|
|
383
|
-
logger: Logger;
|
|
384
|
-
packageGlobs: string[];
|
|
385
|
-
nodeModulesRoot?: string;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
export async function findVendurePluginFiles({
|
|
389
|
-
outputPath,
|
|
390
|
-
vendureConfigPath,
|
|
391
|
-
logger,
|
|
392
|
-
nodeModulesRoot: providedNodeModulesRoot,
|
|
393
|
-
packageGlobs,
|
|
394
|
-
}: FindPluginFilesOptions): Promise<string[]> {
|
|
395
|
-
let nodeModulesRoot = providedNodeModulesRoot;
|
|
396
|
-
const readStart = Date.now();
|
|
397
|
-
if (!nodeModulesRoot) {
|
|
398
|
-
nodeModulesRoot = guessNodeModulesRoot(vendureConfigPath, logger);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const patterns = [
|
|
402
|
-
// Local compiled plugins in temp dir
|
|
403
|
-
path.join(outputPath, '**/*.js'),
|
|
404
|
-
// Node modules patterns
|
|
405
|
-
...packageGlobs.map(pattern => path.join(nodeModulesRoot, pattern)),
|
|
406
|
-
].map(p => p.replace(/\\/g, '/'));
|
|
407
|
-
|
|
408
|
-
logger.debug(`Finding Vendure plugins using patterns: ${patterns.join('\n')}`);
|
|
409
|
-
|
|
410
|
-
const globStart = Date.now();
|
|
411
|
-
const files = await glob(patterns, {
|
|
412
|
-
ignore: [
|
|
413
|
-
// Standard test & doc files
|
|
414
|
-
'**/node_modules/**/node_modules/**',
|
|
415
|
-
'**/*.spec.js',
|
|
416
|
-
'**/*.test.js',
|
|
417
|
-
],
|
|
418
|
-
onlyFiles: true,
|
|
419
|
-
absolute: true,
|
|
420
|
-
followSymbolicLinks: false,
|
|
421
|
-
stats: false,
|
|
422
|
-
});
|
|
423
|
-
logger.debug(`Glob found ${files.length} files in ${Date.now() - globStart}ms`);
|
|
424
|
-
|
|
425
|
-
// Read files in larger parallel batches
|
|
426
|
-
const batchSize = 100; // Increased batch size
|
|
427
|
-
const potentialPluginFiles: string[] = [];
|
|
428
|
-
|
|
429
|
-
for (let i = 0; i < files.length; i += batchSize) {
|
|
430
|
-
const batch = files.slice(i, i + batchSize);
|
|
431
|
-
const results = await Promise.all(
|
|
432
|
-
batch.map(async file => {
|
|
433
|
-
try {
|
|
434
|
-
// Try reading just first 3000 bytes first - most imports are at the top
|
|
435
|
-
const fileHandle = await open(file, 'r');
|
|
436
|
-
try {
|
|
437
|
-
const buffer = Buffer.alloc(3000);
|
|
438
|
-
const { bytesRead } = await fileHandle.read(buffer, 0, 3000, 0);
|
|
439
|
-
let content = buffer.toString('utf8', 0, bytesRead);
|
|
440
|
-
|
|
441
|
-
// Quick check for common indicators
|
|
442
|
-
if (content.includes('@vendure/core')) {
|
|
443
|
-
return file;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// If we find a promising indicator but no definitive match,
|
|
447
|
-
// read more of the file
|
|
448
|
-
if (content.includes('@vendure') || content.includes('VendurePlugin')) {
|
|
449
|
-
const largerBuffer = Buffer.alloc(5000);
|
|
450
|
-
const { bytesRead: moreBytes } = await fileHandle.read(largerBuffer, 0, 5000, 0);
|
|
451
|
-
content = largerBuffer.toString('utf8', 0, moreBytes);
|
|
452
|
-
if (content.includes('@vendure/core')) {
|
|
453
|
-
return file;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
} finally {
|
|
457
|
-
await fileHandle.close();
|
|
458
|
-
}
|
|
459
|
-
} catch (e: any) {
|
|
460
|
-
logger.warn(`Failed to read file ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
461
|
-
}
|
|
462
|
-
return null;
|
|
463
|
-
}),
|
|
464
|
-
);
|
|
465
|
-
|
|
466
|
-
const validResults = results.filter((f): f is string => f !== null);
|
|
467
|
-
potentialPluginFiles.push(...validResults);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
logger.info(
|
|
471
|
-
`Found ${potentialPluginFiles.length} potential plugin files in ${Date.now() - readStart}ms ` +
|
|
472
|
-
`(scanned ${files.length} files)`,
|
|
473
|
-
);
|
|
474
|
-
|
|
475
|
-
return potentialPluginFiles;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
function guessNodeModulesRoot(vendureConfigPath: string, logger: Logger): string {
|
|
479
|
-
let nodeModulesRoot: string;
|
|
480
|
-
// If the node_modules root path has not been explicitly
|
|
481
|
-
// specified, we will try to guess it by resolving the
|
|
482
|
-
// `@vendure/core` package.
|
|
483
|
-
try {
|
|
484
|
-
const coreUrl = import.meta.resolve('@vendure/core');
|
|
485
|
-
logger.debug(`Found core URL: ${coreUrl}`);
|
|
486
|
-
const corePath = fileURLToPath(coreUrl);
|
|
487
|
-
logger.debug(`Found core path: ${corePath}`);
|
|
488
|
-
nodeModulesRoot = path.join(path.dirname(corePath), '..', '..', '..');
|
|
489
|
-
} catch (e) {
|
|
490
|
-
logger.warn(`Failed to resolve @vendure/core: ${e instanceof Error ? e.message : String(e)}`);
|
|
491
|
-
nodeModulesRoot = path.dirname(vendureConfigPath);
|
|
492
|
-
}
|
|
493
|
-
return nodeModulesRoot;
|
|
494
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { GraphQLTypesLoader } from '@nestjs/graphql';
|
|
2
|
-
import {
|
|
3
|
-
getConfig,
|
|
4
|
-
getFinalVendureSchema,
|
|
5
|
-
resetConfig,
|
|
6
|
-
runPluginConfigurations,
|
|
7
|
-
setConfig,
|
|
8
|
-
VENDURE_ADMIN_API_TYPE_PATHS,
|
|
9
|
-
VendureConfig,
|
|
10
|
-
} from '@vendure/core';
|
|
11
|
-
import { buildSchema, GraphQLSchema } from 'graphql';
|
|
12
|
-
|
|
13
|
-
let schemaPromise: Promise<GraphQLSchema> | undefined;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @description
|
|
17
|
-
* This function generates a GraphQL schema from the Vendure config.
|
|
18
|
-
* It is used to generate the schema for the dashboard.
|
|
19
|
-
*/
|
|
20
|
-
export async function generateSchema({
|
|
21
|
-
vendureConfig,
|
|
22
|
-
}: {
|
|
23
|
-
vendureConfig: VendureConfig;
|
|
24
|
-
}): Promise<GraphQLSchema> {
|
|
25
|
-
if (!schemaPromise) {
|
|
26
|
-
/* eslint-disable-next-line @typescript-eslint/no-misused-promises */
|
|
27
|
-
schemaPromise = new Promise(async (resolve, reject) => {
|
|
28
|
-
resetConfig();
|
|
29
|
-
await setConfig(vendureConfig ?? {});
|
|
30
|
-
|
|
31
|
-
const runtimeConfig = await runPluginConfigurations(getConfig() as any);
|
|
32
|
-
const typesLoader = new GraphQLTypesLoader();
|
|
33
|
-
const finalSchema = await getFinalVendureSchema({
|
|
34
|
-
config: runtimeConfig,
|
|
35
|
-
typePaths: VENDURE_ADMIN_API_TYPE_PATHS,
|
|
36
|
-
typesLoader,
|
|
37
|
-
apiType: 'admin',
|
|
38
|
-
output: 'sdl',
|
|
39
|
-
});
|
|
40
|
-
const safeSchema = buildSchema(finalSchema);
|
|
41
|
-
resolve(safeSchema);
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
return schemaPromise;
|
|
45
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { CompilerOptions } from 'typescript';
|
|
4
|
-
|
|
5
|
-
import { Logger, TransformTsConfigPathMappingsFn } from '../types.js';
|
|
6
|
-
|
|
7
|
-
export interface TsConfigPathsConfig {
|
|
8
|
-
baseUrl: string;
|
|
9
|
-
paths: Record<string, string[]>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Finds and parses tsconfig files in the given directory and its parent directories.
|
|
14
|
-
*/
|
|
15
|
-
export async function findTsConfigPaths(
|
|
16
|
-
configPath: string,
|
|
17
|
-
logger: Logger,
|
|
18
|
-
phase: 'compiling' | 'loading',
|
|
19
|
-
transformTsConfigPathMappings: TransformTsConfigPathMappingsFn,
|
|
20
|
-
): Promise<TsConfigPathsConfig | undefined> {
|
|
21
|
-
let currentDir = path.dirname(configPath);
|
|
22
|
-
|
|
23
|
-
while (currentDir !== path.parse(currentDir).root) {
|
|
24
|
-
try {
|
|
25
|
-
const files = await fs.readdir(currentDir);
|
|
26
|
-
const tsConfigFiles = files.filter(file => /^tsconfig(\..*)?\.json$/.test(file));
|
|
27
|
-
|
|
28
|
-
for (const fileName of tsConfigFiles) {
|
|
29
|
-
const tsConfigFilePath = path.join(currentDir, fileName);
|
|
30
|
-
try {
|
|
31
|
-
const { paths, baseUrl } = await getCompilerOptionsFromFile(tsConfigFilePath);
|
|
32
|
-
if (paths) {
|
|
33
|
-
const tsConfigBaseUrl = path.resolve(currentDir, baseUrl || '.');
|
|
34
|
-
const pathMappings = getTransformedPathMappings(
|
|
35
|
-
paths,
|
|
36
|
-
phase,
|
|
37
|
-
transformTsConfigPathMappings,
|
|
38
|
-
);
|
|
39
|
-
return { baseUrl: tsConfigBaseUrl, paths: pathMappings };
|
|
40
|
-
}
|
|
41
|
-
} catch (e) {
|
|
42
|
-
logger.warn(
|
|
43
|
-
`Could not read or parse tsconfig file ${tsConfigFilePath}: ${e instanceof Error ? e.message : String(e)}`,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
} catch (e) {
|
|
48
|
-
logger.warn(
|
|
49
|
-
`Could not read directory ${currentDir}: ${e instanceof Error ? e.message : String(e)}`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
currentDir = path.dirname(currentDir);
|
|
53
|
-
}
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function getCompilerOptionsFromFile(tsConfigFilePath: string): Promise<CompilerOptions> {
|
|
58
|
-
const tsConfigContent = await fs.readFile(tsConfigFilePath, 'utf-8');
|
|
59
|
-
const tsConfig = JSON.parse(tsConfigContent);
|
|
60
|
-
return tsConfig.compilerOptions || {};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function getTransformedPathMappings(
|
|
64
|
-
paths: Required<CompilerOptions>['paths'],
|
|
65
|
-
phase: 'compiling' | 'loading',
|
|
66
|
-
transformTsConfigPathMappings: TransformTsConfigPathMappingsFn,
|
|
67
|
-
) {
|
|
68
|
-
const pathMappings: Record<string, string[]> = {};
|
|
69
|
-
|
|
70
|
-
for (const [alias, patterns] of Object.entries(paths)) {
|
|
71
|
-
const normalizedPatterns = patterns.map(pattern => pattern.replace(/\\/g, '/'));
|
|
72
|
-
pathMappings[alias] = transformTsConfigPathMappings({
|
|
73
|
-
phase,
|
|
74
|
-
alias,
|
|
75
|
-
patterns: normalizedPatterns,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return pathMappings;
|
|
79
|
-
}
|
package/vite/utils/ui-config.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ADMIN_API_PATH,
|
|
3
|
-
DEFAULT_AUTH_TOKEN_HEADER_KEY,
|
|
4
|
-
DEFAULT_CHANNEL_TOKEN_KEY,
|
|
5
|
-
} from '@vendure/common/lib/shared-constants';
|
|
6
|
-
import { VendureConfig } from '@vendure/core';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
defaultAvailableLanguages,
|
|
10
|
-
defaultAvailableLocales,
|
|
11
|
-
defaultLanguage,
|
|
12
|
-
defaultLocale,
|
|
13
|
-
} from '../constants.js';
|
|
14
|
-
import { ResolvedUiConfig, UiConfigPluginOptions } from '../vite-plugin-ui-config.js';
|
|
15
|
-
|
|
16
|
-
export function getUiConfig(config: VendureConfig, pluginOptions: UiConfigPluginOptions): ResolvedUiConfig {
|
|
17
|
-
const { authOptions, apiOptions } = config;
|
|
18
|
-
|
|
19
|
-
// Merge API configuration with defaults
|
|
20
|
-
const api = {
|
|
21
|
-
adminApiPath: pluginOptions.api?.adminApiPath ?? apiOptions.adminApiPath ?? ADMIN_API_PATH,
|
|
22
|
-
host: pluginOptions.api?.host ?? 'auto',
|
|
23
|
-
port: pluginOptions.api?.port ?? 'auto',
|
|
24
|
-
tokenMethod:
|
|
25
|
-
pluginOptions.api?.tokenMethod ?? (authOptions.tokenMethod === 'bearer' ? 'bearer' : 'cookie'),
|
|
26
|
-
authTokenHeaderKey:
|
|
27
|
-
pluginOptions.api?.authTokenHeaderKey ??
|
|
28
|
-
authOptions.authTokenHeaderKey ??
|
|
29
|
-
DEFAULT_AUTH_TOKEN_HEADER_KEY,
|
|
30
|
-
channelTokenKey:
|
|
31
|
-
pluginOptions.api?.channelTokenKey ?? apiOptions.channelTokenKey ?? DEFAULT_CHANNEL_TOKEN_KEY,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// Merge i18n configuration with defaults
|
|
35
|
-
const i18n = {
|
|
36
|
-
defaultLanguage: pluginOptions.i18n?.defaultLanguage ?? defaultLanguage,
|
|
37
|
-
defaultLocale: pluginOptions.i18n?.defaultLocale ?? defaultLocale,
|
|
38
|
-
availableLanguages:
|
|
39
|
-
pluginOptions.i18n?.availableLanguages && pluginOptions.i18n.availableLanguages.length > 0
|
|
40
|
-
? pluginOptions.i18n.availableLanguages
|
|
41
|
-
: defaultAvailableLanguages,
|
|
42
|
-
availableLocales:
|
|
43
|
-
pluginOptions.i18n?.availableLocales && pluginOptions.i18n.availableLocales.length > 0
|
|
44
|
-
? pluginOptions.i18n.availableLocales
|
|
45
|
-
: defaultAvailableLocales,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
api,
|
|
50
|
-
i18n,
|
|
51
|
-
};
|
|
52
|
-
}
|