@qiu_qiu/vue-auto-component-framework 1.0.0
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/README.md +72 -0
- package/dist/core/AppCreator.d.ts +33 -0
- package/dist/core/AppCreator.d.ts.map +1 -0
- package/dist/core/AppCreator.js +100 -0
- package/dist/core/ComponentRegistry.d.ts +44 -0
- package/dist/core/ComponentRegistry.d.ts.map +1 -0
- package/dist/core/ComponentRegistry.js +110 -0
- package/dist/core/ComponentScanner.d.ts +50 -0
- package/dist/core/ComponentScanner.d.ts.map +1 -0
- package/dist/core/ComponentScanner.js +203 -0
- package/dist/core/ErrorHandler.d.ts +51 -0
- package/dist/core/ErrorHandler.d.ts.map +1 -0
- package/dist/core/ErrorHandler.js +124 -0
- package/dist/core/FileScanner.d.ts +26 -0
- package/dist/core/FileScanner.d.ts.map +1 -0
- package/dist/core/FileScanner.js +102 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/layout/LayoutManager.d.ts +56 -0
- package/dist/layout/LayoutManager.d.ts.map +1 -0
- package/dist/layout/LayoutManager.js +146 -0
- package/dist/layout/index.d.ts +4 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +2 -0
- package/dist/types/index.d.ts +140 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +78 -0
- package/package.json +47 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { FrameworkError, FrameworkErrorType } from '@/types';
|
|
2
|
+
/**
|
|
3
|
+
* Error handler utility class for creating and managing framework errors
|
|
4
|
+
*/
|
|
5
|
+
export class ErrorHandler {
|
|
6
|
+
/**
|
|
7
|
+
* Create a component scan error
|
|
8
|
+
*/
|
|
9
|
+
static createScanError(message, filePath, cause) {
|
|
10
|
+
return new FrameworkError(FrameworkErrorType.COMPONENT_SCAN_ERROR, message, { filePath }, cause);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Create a component registration error
|
|
14
|
+
*/
|
|
15
|
+
static createRegistrationError(message, componentName, filePath, cause) {
|
|
16
|
+
return new FrameworkError(FrameworkErrorType.COMPONENT_REGISTER_ERROR, message, { componentName, filePath }, cause);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a layout initialization error
|
|
20
|
+
*/
|
|
21
|
+
static createLayoutError(message, context, cause) {
|
|
22
|
+
return new FrameworkError(FrameworkErrorType.LAYOUT_INIT_ERROR, message, { context }, cause);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create an app creation error
|
|
26
|
+
*/
|
|
27
|
+
static createAppError(message, context, cause) {
|
|
28
|
+
return new FrameworkError(FrameworkErrorType.APP_CREATE_ERROR, message, { context }, cause);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Create a file not found error
|
|
32
|
+
*/
|
|
33
|
+
static createFileNotFoundError(filePath, cause) {
|
|
34
|
+
return new FrameworkError(FrameworkErrorType.FILE_NOT_FOUND, `File not found: ${filePath}`, { filePath }, cause);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create an invalid component error
|
|
38
|
+
*/
|
|
39
|
+
static createInvalidComponentError(componentName, filePath, reason, cause) {
|
|
40
|
+
const message = reason
|
|
41
|
+
? `Invalid component ${componentName}: ${reason}`
|
|
42
|
+
: `Invalid component: ${componentName}`;
|
|
43
|
+
return new FrameworkError(FrameworkErrorType.INVALID_COMPONENT, message, { componentName, filePath, context: { reason } }, cause);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a name conflict error
|
|
47
|
+
*/
|
|
48
|
+
static createNameConflictError(componentName, existingPath, newPath) {
|
|
49
|
+
return new FrameworkError(FrameworkErrorType.NAME_CONFLICT, `Component name conflict: ${componentName} already exists`, {
|
|
50
|
+
componentName,
|
|
51
|
+
context: {
|
|
52
|
+
existingPath,
|
|
53
|
+
newPath
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create an import error
|
|
59
|
+
*/
|
|
60
|
+
static createImportError(filePath, cause) {
|
|
61
|
+
return new FrameworkError(FrameworkErrorType.IMPORT_ERROR, `Failed to import component from ${filePath}`, { filePath }, cause);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Log error with appropriate level based on error type
|
|
65
|
+
*/
|
|
66
|
+
static logError(error, logger = console) {
|
|
67
|
+
const errorInfo = error.getDetailedInfo();
|
|
68
|
+
switch (error.type) {
|
|
69
|
+
case FrameworkErrorType.APP_CREATE_ERROR:
|
|
70
|
+
logger.error(errorInfo);
|
|
71
|
+
break;
|
|
72
|
+
case FrameworkErrorType.LAYOUT_INIT_ERROR:
|
|
73
|
+
logger.error(errorInfo);
|
|
74
|
+
break;
|
|
75
|
+
case FrameworkErrorType.COMPONENT_SCAN_ERROR:
|
|
76
|
+
case FrameworkErrorType.COMPONENT_REGISTER_ERROR:
|
|
77
|
+
case FrameworkErrorType.FILE_NOT_FOUND:
|
|
78
|
+
case FrameworkErrorType.INVALID_COMPONENT:
|
|
79
|
+
case FrameworkErrorType.NAME_CONFLICT:
|
|
80
|
+
case FrameworkErrorType.IMPORT_ERROR:
|
|
81
|
+
logger.warn(errorInfo);
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
logger.error(errorInfo);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if an error is recoverable (app can continue running)
|
|
89
|
+
*/
|
|
90
|
+
static isRecoverable(error) {
|
|
91
|
+
const recoverableTypes = [
|
|
92
|
+
FrameworkErrorType.COMPONENT_SCAN_ERROR,
|
|
93
|
+
FrameworkErrorType.COMPONENT_REGISTER_ERROR,
|
|
94
|
+
FrameworkErrorType.FILE_NOT_FOUND,
|
|
95
|
+
FrameworkErrorType.INVALID_COMPONENT,
|
|
96
|
+
FrameworkErrorType.NAME_CONFLICT,
|
|
97
|
+
FrameworkErrorType.IMPORT_ERROR
|
|
98
|
+
];
|
|
99
|
+
return recoverableTypes.includes(error.type);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Collect and format multiple errors for reporting
|
|
103
|
+
*/
|
|
104
|
+
static formatErrorSummary(errors) {
|
|
105
|
+
if (errors.length === 0) {
|
|
106
|
+
return 'No errors to report';
|
|
107
|
+
}
|
|
108
|
+
const summary = [
|
|
109
|
+
`Framework Error Summary (${errors.length} errors):`,
|
|
110
|
+
'='.repeat(50)
|
|
111
|
+
];
|
|
112
|
+
errors.forEach((error, index) => {
|
|
113
|
+
summary.push(`\n${index + 1}. ${error.type}`);
|
|
114
|
+
summary.push(` Message: ${error.message}`);
|
|
115
|
+
if (error.context.filePath) {
|
|
116
|
+
summary.push(` File: ${error.context.filePath}`);
|
|
117
|
+
}
|
|
118
|
+
if (error.context.componentName) {
|
|
119
|
+
summary.push(` Component: ${error.context.componentName}`);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return summary.join('\n');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FileScanner as IFileScanner, ScanResult } from '@/types';
|
|
2
|
+
/**
|
|
3
|
+
* File scanner implementation
|
|
4
|
+
* Handles scanning directories for component files
|
|
5
|
+
*/
|
|
6
|
+
export declare class FileScanner implements IFileScanner {
|
|
7
|
+
/**
|
|
8
|
+
* Scan directory for files with specified extensions
|
|
9
|
+
* Implements graceful error handling - missing directories don't fail the scan
|
|
10
|
+
*/
|
|
11
|
+
scanDirectory(path: string, extensions: string[]): Promise<ScanResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Recursively scan directory for files with specified extensions
|
|
14
|
+
* Continues scanning even when individual files/directories fail
|
|
15
|
+
*/
|
|
16
|
+
private _scanDirectoryRecursive;
|
|
17
|
+
/**
|
|
18
|
+
* Check if directory should be skipped during scanning
|
|
19
|
+
*/
|
|
20
|
+
private _shouldSkipDirectory;
|
|
21
|
+
/**
|
|
22
|
+
* Check if file has one of the valid extensions
|
|
23
|
+
*/
|
|
24
|
+
private _hasValidExtension;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=FileScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileScanner.d.ts","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,IAAI,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAGtE;;;GAGG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C;;;OAGG;IACG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAgC5E;;;OAGG;YACW,uBAAuB;IAgDrC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAG3B"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { readdir, stat, access } from 'fs/promises';
|
|
2
|
+
import { join, resolve } from 'path';
|
|
3
|
+
import { constants } from 'fs';
|
|
4
|
+
import { ErrorHandler } from './ErrorHandler';
|
|
5
|
+
/**
|
|
6
|
+
* File scanner implementation
|
|
7
|
+
* Handles scanning directories for component files
|
|
8
|
+
*/
|
|
9
|
+
export class FileScanner {
|
|
10
|
+
/**
|
|
11
|
+
* Scan directory for files with specified extensions
|
|
12
|
+
* Implements graceful error handling - missing directories don't fail the scan
|
|
13
|
+
*/
|
|
14
|
+
async scanDirectory(path, extensions) {
|
|
15
|
+
const files = [];
|
|
16
|
+
const errors = [];
|
|
17
|
+
try {
|
|
18
|
+
const resolvedPath = resolve(path);
|
|
19
|
+
// Check if directory exists and is accessible
|
|
20
|
+
try {
|
|
21
|
+
await access(resolvedPath, constants.R_OK);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
// Directory doesn't exist or isn't readable - this is not a critical error
|
|
25
|
+
const accessError = ErrorHandler.createFileNotFoundError(resolvedPath, error);
|
|
26
|
+
errors.push(accessError);
|
|
27
|
+
console.info(`Components directory not found or not accessible: ${resolvedPath}`);
|
|
28
|
+
return { files, errors };
|
|
29
|
+
}
|
|
30
|
+
await this._scanDirectoryRecursive(resolvedPath, extensions, files, errors);
|
|
31
|
+
return { files, errors };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
// Critical scanning error
|
|
35
|
+
const scanError = ErrorHandler.createScanError(`Critical error during directory scan: ${error.message}`, path, error);
|
|
36
|
+
errors.push(scanError);
|
|
37
|
+
return { files, errors };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Recursively scan directory for files with specified extensions
|
|
42
|
+
* Continues scanning even when individual files/directories fail
|
|
43
|
+
*/
|
|
44
|
+
async _scanDirectoryRecursive(dirPath, extensions, files, errors) {
|
|
45
|
+
try {
|
|
46
|
+
const entries = await readdir(dirPath);
|
|
47
|
+
for (const entry of entries) {
|
|
48
|
+
const fullPath = join(dirPath, entry);
|
|
49
|
+
try {
|
|
50
|
+
const stats = await stat(fullPath);
|
|
51
|
+
if (stats.isDirectory()) {
|
|
52
|
+
// Skip node_modules and other common directories that shouldn't contain components
|
|
53
|
+
if (this._shouldSkipDirectory(entry)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Recursively scan subdirectories
|
|
57
|
+
await this._scanDirectoryRecursive(fullPath, extensions, files, errors);
|
|
58
|
+
}
|
|
59
|
+
else if (stats.isFile() && this._hasValidExtension(fullPath, extensions)) {
|
|
60
|
+
files.push(fullPath);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
// Log individual file/directory errors but continue scanning
|
|
65
|
+
const fileError = ErrorHandler.createScanError(`Failed to process file/directory: ${error.message}`, fullPath, error);
|
|
66
|
+
errors.push(fileError);
|
|
67
|
+
// Continue with next entry - don't let one bad file stop the whole scan
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
// Directory access error - log but don't stop the scan
|
|
73
|
+
const dirError = ErrorHandler.createScanError(`Failed to read directory: ${error.message}`, dirPath, error);
|
|
74
|
+
errors.push(dirError);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Check if directory should be skipped during scanning
|
|
79
|
+
*/
|
|
80
|
+
_shouldSkipDirectory(dirName) {
|
|
81
|
+
const skipDirs = [
|
|
82
|
+
'node_modules',
|
|
83
|
+
'.git',
|
|
84
|
+
'.svn',
|
|
85
|
+
'.hg',
|
|
86
|
+
'dist',
|
|
87
|
+
'build',
|
|
88
|
+
'coverage',
|
|
89
|
+
'.nyc_output',
|
|
90
|
+
'.cache',
|
|
91
|
+
'tmp',
|
|
92
|
+
'temp'
|
|
93
|
+
];
|
|
94
|
+
return skipDirs.includes(dirName) || dirName.startsWith('.');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check if file has one of the valid extensions
|
|
98
|
+
*/
|
|
99
|
+
_hasValidExtension(filePath, extensions) {
|
|
100
|
+
return extensions.some(ext => filePath.endsWith(ext));
|
|
101
|
+
}
|
|
102
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Component } from 'vue';
|
|
2
|
+
import type { FrameworkOptions } from '@/types';
|
|
3
|
+
export type { FrameworkOptions, LayoutConfig, LayoutSlots, ComponentInfo, ScanResult } from '@/types';
|
|
4
|
+
export { FrameworkError, FrameworkErrorType } from '@/types';
|
|
5
|
+
export { ErrorHandler } from '@/core/ErrorHandler';
|
|
6
|
+
export { ComponentRegistry } from '@/core/ComponentRegistry';
|
|
7
|
+
export { FileScanner } from '@/core/FileScanner';
|
|
8
|
+
export { ComponentScanner } from '@/core/ComponentScanner';
|
|
9
|
+
export { AppCreator } from '@/core/AppCreator';
|
|
10
|
+
export { default as DefaultLayout } from '@/layout/DefaultLayout.vue';
|
|
11
|
+
export { LayoutManager } from '@/layout/LayoutManager';
|
|
12
|
+
/**
|
|
13
|
+
* Create Vue app with framework features
|
|
14
|
+
* Compatible with Vue's native createApp API with enhanced error handling
|
|
15
|
+
*/
|
|
16
|
+
export declare function createApp(rootComponent?: Component, options?: FrameworkOptions): Promise<import("vue").App<any>>;
|
|
17
|
+
declare const _default: {
|
|
18
|
+
createApp: typeof createApp;
|
|
19
|
+
};
|
|
20
|
+
export default _default;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAI/C,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,aAAa,EACb,UAAU,EACX,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAG9C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAEtD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,OAAO,GAAE,gBAAqB,mCAkBxF;;;;AAGD,wBAEC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AppCreator } from '@/core/AppCreator';
|
|
2
|
+
export { FrameworkError, FrameworkErrorType } from '@/types';
|
|
3
|
+
export { ErrorHandler } from '@/core/ErrorHandler';
|
|
4
|
+
// Export core classes
|
|
5
|
+
export { ComponentRegistry } from '@/core/ComponentRegistry';
|
|
6
|
+
export { FileScanner } from '@/core/FileScanner';
|
|
7
|
+
export { ComponentScanner } from '@/core/ComponentScanner';
|
|
8
|
+
export { AppCreator } from '@/core/AppCreator';
|
|
9
|
+
// Export layout components
|
|
10
|
+
export { default as DefaultLayout } from '@/layout/DefaultLayout.vue';
|
|
11
|
+
export { LayoutManager } from '@/layout/LayoutManager';
|
|
12
|
+
/**
|
|
13
|
+
* Create Vue app with framework features
|
|
14
|
+
* Compatible with Vue's native createApp API with enhanced error handling
|
|
15
|
+
*/
|
|
16
|
+
export async function createApp(rootComponent, options = {}) {
|
|
17
|
+
try {
|
|
18
|
+
const appCreator = new AppCreator();
|
|
19
|
+
return await appCreator.createApp(rootComponent, options);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
// If AppCreator throws a FrameworkError, preserve it
|
|
23
|
+
if (error instanceof Error && error.name === 'FrameworkError') {
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
// Otherwise, wrap in a framework error
|
|
27
|
+
const { ErrorHandler } = await import('@/core/ErrorHandler');
|
|
28
|
+
throw ErrorHandler.createAppError('Failed to create application', { rootComponent: rootComponent?.name || 'anonymous' }, error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Default export for convenience
|
|
32
|
+
export default {
|
|
33
|
+
createApp
|
|
34
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { App, Component } from 'vue';
|
|
2
|
+
import type { LayoutConfig } from '@/types';
|
|
3
|
+
/**
|
|
4
|
+
* Layout manager handles layout configuration and registration
|
|
5
|
+
*/
|
|
6
|
+
export declare class LayoutManager {
|
|
7
|
+
private defaultConfig;
|
|
8
|
+
private currentConfig;
|
|
9
|
+
private customLayouts;
|
|
10
|
+
constructor(initialConfig?: LayoutConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Merge default config with custom config, allowing overrides
|
|
13
|
+
*/
|
|
14
|
+
private mergeConfig;
|
|
15
|
+
/**
|
|
16
|
+
* Get current layout configuration
|
|
17
|
+
*/
|
|
18
|
+
getConfig(): Required<LayoutConfig>;
|
|
19
|
+
/**
|
|
20
|
+
* Update layout configuration with override mechanism
|
|
21
|
+
*/
|
|
22
|
+
updateConfig(newConfig: LayoutConfig): void;
|
|
23
|
+
/**
|
|
24
|
+
* Reset configuration to default values
|
|
25
|
+
*/
|
|
26
|
+
resetConfig(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Register a custom layout component
|
|
29
|
+
*/
|
|
30
|
+
registerLayout(name: string, component: Component): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get a registered layout component
|
|
33
|
+
*/
|
|
34
|
+
getLayout(name: string): Component | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Get all registered custom layouts
|
|
37
|
+
*/
|
|
38
|
+
getAllLayouts(): Map<string, Component>;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a layout is registered
|
|
41
|
+
*/
|
|
42
|
+
hasLayout(name: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Initialize layout system in Vue app
|
|
45
|
+
*/
|
|
46
|
+
initializeLayouts(app: App): void;
|
|
47
|
+
/**
|
|
48
|
+
* Create a layout configuration with validation
|
|
49
|
+
*/
|
|
50
|
+
static createConfig(config?: LayoutConfig): Required<LayoutConfig>;
|
|
51
|
+
/**
|
|
52
|
+
* Validate layout configuration
|
|
53
|
+
*/
|
|
54
|
+
static validateConfig(config: LayoutConfig): boolean;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=LayoutManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LayoutManager.d.ts","sourceRoot":"","sources":["../../src/layout/LayoutManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAI3C;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,aAAa,CAKpB;IAED,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,aAAa,CAAoC;gBAE7C,aAAa,CAAC,EAAE,YAAY;IAIxC;;OAEG;IACH,OAAO,CAAC,WAAW;IAgBnB;;OAEG;IACH,SAAS,IAAI,QAAQ,CAAC,YAAY,CAAC;IAInC;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI;IAI3C;;OAEG;IACH,WAAW,IAAI,IAAI;IAInB;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI;IAoBxD;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI9C;;OAEG;IACH,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;IAIvC;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIhC;;OAEG;IACH,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAgDjC;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,GAAE,YAAiB,GAAG,QAAQ,CAAC,YAAY,CAAC;IAKtE;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO;CAwBrD"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { FrameworkError, FrameworkErrorType } from '@/types';
|
|
2
|
+
import DefaultLayout from './DefaultLayout.vue';
|
|
3
|
+
/**
|
|
4
|
+
* Layout manager handles layout configuration and registration
|
|
5
|
+
*/
|
|
6
|
+
export class LayoutManager {
|
|
7
|
+
constructor(initialConfig) {
|
|
8
|
+
this.defaultConfig = {
|
|
9
|
+
header: true,
|
|
10
|
+
sidebar: true,
|
|
11
|
+
footer: true,
|
|
12
|
+
responsive: true
|
|
13
|
+
};
|
|
14
|
+
this.customLayouts = new Map();
|
|
15
|
+
this.currentConfig = this.mergeConfig(this.defaultConfig, initialConfig);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Merge default config with custom config, allowing overrides
|
|
19
|
+
*/
|
|
20
|
+
mergeConfig(defaultConfig, customConfig) {
|
|
21
|
+
if (!customConfig) {
|
|
22
|
+
return { ...defaultConfig };
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
header: customConfig.header !== undefined ? customConfig.header : defaultConfig.header,
|
|
26
|
+
sidebar: customConfig.sidebar !== undefined ? customConfig.sidebar : defaultConfig.sidebar,
|
|
27
|
+
footer: customConfig.footer !== undefined ? customConfig.footer : defaultConfig.footer,
|
|
28
|
+
responsive: customConfig.responsive !== undefined ? customConfig.responsive : defaultConfig.responsive
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get current layout configuration
|
|
33
|
+
*/
|
|
34
|
+
getConfig() {
|
|
35
|
+
return { ...this.currentConfig };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Update layout configuration with override mechanism
|
|
39
|
+
*/
|
|
40
|
+
updateConfig(newConfig) {
|
|
41
|
+
this.currentConfig = this.mergeConfig(this.currentConfig, newConfig);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Reset configuration to default values
|
|
45
|
+
*/
|
|
46
|
+
resetConfig() {
|
|
47
|
+
this.currentConfig = { ...this.defaultConfig };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Register a custom layout component
|
|
51
|
+
*/
|
|
52
|
+
registerLayout(name, component) {
|
|
53
|
+
if (!name || typeof name !== 'string') {
|
|
54
|
+
throw new FrameworkError(FrameworkErrorType.LAYOUT_INIT_ERROR, 'Layout name must be a non-empty string', { context: { layoutName: name } });
|
|
55
|
+
}
|
|
56
|
+
if (!component) {
|
|
57
|
+
throw new FrameworkError(FrameworkErrorType.LAYOUT_INIT_ERROR, 'Layout component cannot be null or undefined', { context: { layoutName: name } });
|
|
58
|
+
}
|
|
59
|
+
this.customLayouts.set(name, component);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get a registered layout component
|
|
63
|
+
*/
|
|
64
|
+
getLayout(name) {
|
|
65
|
+
return this.customLayouts.get(name);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get all registered custom layouts
|
|
69
|
+
*/
|
|
70
|
+
getAllLayouts() {
|
|
71
|
+
return new Map(this.customLayouts);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if a layout is registered
|
|
75
|
+
*/
|
|
76
|
+
hasLayout(name) {
|
|
77
|
+
return this.customLayouts.has(name);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Initialize layout system in Vue app
|
|
81
|
+
*/
|
|
82
|
+
initializeLayouts(app) {
|
|
83
|
+
try {
|
|
84
|
+
// Register default layout with current configuration
|
|
85
|
+
const DefaultLayoutWithConfig = {
|
|
86
|
+
...DefaultLayout,
|
|
87
|
+
props: {
|
|
88
|
+
...DefaultLayout.props,
|
|
89
|
+
config: {
|
|
90
|
+
type: Object,
|
|
91
|
+
default: () => this.currentConfig
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
app.component('DefaultLayout', DefaultLayoutWithConfig);
|
|
96
|
+
// Register all custom layouts
|
|
97
|
+
for (const [name, component] of this.customLayouts) {
|
|
98
|
+
try {
|
|
99
|
+
app.component(name, component);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
throw new FrameworkError(FrameworkErrorType.LAYOUT_INIT_ERROR, `Failed to register custom layout: ${name}`, { context: { layoutName: name } }, error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Provide layout configuration globally
|
|
106
|
+
app.provide('layoutConfig', this.currentConfig);
|
|
107
|
+
app.provide('layoutManager', this);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error instanceof FrameworkError) {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
throw new FrameworkError(FrameworkErrorType.LAYOUT_INIT_ERROR, 'Failed to initialize layout system', {}, error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Create a layout configuration with validation
|
|
118
|
+
*/
|
|
119
|
+
static createConfig(config = {}) {
|
|
120
|
+
const manager = new LayoutManager(config);
|
|
121
|
+
return manager.getConfig();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Validate layout configuration
|
|
125
|
+
*/
|
|
126
|
+
static validateConfig(config) {
|
|
127
|
+
if (typeof config !== 'object' || config === null) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
const validKeys = ['header', 'sidebar', 'footer', 'responsive'];
|
|
131
|
+
const configKeys = Object.keys(config);
|
|
132
|
+
// Check for invalid keys
|
|
133
|
+
for (const key of configKeys) {
|
|
134
|
+
if (!validKeys.includes(key)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Check for valid boolean values
|
|
139
|
+
for (const [key, value] of Object.entries(config)) {
|
|
140
|
+
if (value !== undefined && typeof value !== 'boolean') {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { App, Component, Plugin } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Framework configuration options
|
|
4
|
+
*/
|
|
5
|
+
export interface FrameworkOptions {
|
|
6
|
+
/** Path to components directory, defaults to '@/components' */
|
|
7
|
+
componentsPath?: string;
|
|
8
|
+
/** Layout configuration */
|
|
9
|
+
layoutConfig?: LayoutConfig;
|
|
10
|
+
/** Additional Vue plugins to install */
|
|
11
|
+
plugins?: Plugin[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Layout configuration interface
|
|
15
|
+
*/
|
|
16
|
+
export interface LayoutConfig {
|
|
17
|
+
/** Enable header section */
|
|
18
|
+
header?: boolean;
|
|
19
|
+
/** Enable sidebar section */
|
|
20
|
+
sidebar?: boolean;
|
|
21
|
+
/** Enable footer section */
|
|
22
|
+
footer?: boolean;
|
|
23
|
+
/** Enable responsive design */
|
|
24
|
+
responsive?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Layout slots interface
|
|
28
|
+
*/
|
|
29
|
+
export interface LayoutSlots {
|
|
30
|
+
/** Header slot */
|
|
31
|
+
header?: any;
|
|
32
|
+
/** Sidebar slot */
|
|
33
|
+
sidebar?: any;
|
|
34
|
+
/** Main content slot (required) */
|
|
35
|
+
main: any;
|
|
36
|
+
/** Footer slot */
|
|
37
|
+
footer?: any;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Component information interface
|
|
41
|
+
*/
|
|
42
|
+
export interface ComponentInfo {
|
|
43
|
+
/** Component name */
|
|
44
|
+
name: string;
|
|
45
|
+
/** Vue component */
|
|
46
|
+
component: Component;
|
|
47
|
+
/** File path */
|
|
48
|
+
path: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* File scan result interface
|
|
52
|
+
*/
|
|
53
|
+
export interface ScanResult {
|
|
54
|
+
/** Array of found file paths */
|
|
55
|
+
files: string[];
|
|
56
|
+
/** Array of errors encountered during scanning */
|
|
57
|
+
errors: Error[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Framework error types
|
|
61
|
+
*/
|
|
62
|
+
export declare enum FrameworkErrorType {
|
|
63
|
+
COMPONENT_SCAN_ERROR = "COMPONENT_SCAN_ERROR",
|
|
64
|
+
COMPONENT_REGISTER_ERROR = "COMPONENT_REGISTER_ERROR",
|
|
65
|
+
LAYOUT_INIT_ERROR = "LAYOUT_INIT_ERROR",
|
|
66
|
+
APP_CREATE_ERROR = "APP_CREATE_ERROR",
|
|
67
|
+
FILE_NOT_FOUND = "FILE_NOT_FOUND",
|
|
68
|
+
INVALID_COMPONENT = "INVALID_COMPONENT",
|
|
69
|
+
NAME_CONFLICT = "NAME_CONFLICT",
|
|
70
|
+
IMPORT_ERROR = "IMPORT_ERROR"
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Error context interface for detailed error information
|
|
74
|
+
*/
|
|
75
|
+
export interface ErrorContext {
|
|
76
|
+
/** File path where error occurred */
|
|
77
|
+
filePath?: string;
|
|
78
|
+
/** Component name involved in error */
|
|
79
|
+
componentName?: string;
|
|
80
|
+
/** Additional context data */
|
|
81
|
+
context?: Record<string, any>;
|
|
82
|
+
/** Timestamp when error occurred */
|
|
83
|
+
timestamp?: Date;
|
|
84
|
+
/** Stack trace from original error */
|
|
85
|
+
originalStack?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Framework error class with detailed error information
|
|
89
|
+
*/
|
|
90
|
+
export declare class FrameworkError extends Error {
|
|
91
|
+
readonly type: FrameworkErrorType;
|
|
92
|
+
readonly cause?: Error | undefined;
|
|
93
|
+
readonly timestamp: Date;
|
|
94
|
+
readonly context: ErrorContext;
|
|
95
|
+
constructor(type: FrameworkErrorType, message: string, context?: ErrorContext, cause?: Error | undefined);
|
|
96
|
+
/**
|
|
97
|
+
* Generate detailed error information for debugging
|
|
98
|
+
*/
|
|
99
|
+
getDetailedInfo(): string;
|
|
100
|
+
/**
|
|
101
|
+
* Convert error to JSON for logging
|
|
102
|
+
*/
|
|
103
|
+
toJSON(): Record<string, any>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Component scanner interface
|
|
107
|
+
*/
|
|
108
|
+
export interface ComponentScanner {
|
|
109
|
+
/** Scan components in the specified base path */
|
|
110
|
+
scanComponents(basePath: string): Promise<ComponentInfo[]>;
|
|
111
|
+
/** Register components in the Vue app */
|
|
112
|
+
registerComponents(app: App, components: ComponentInfo[]): void;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Component registry interface
|
|
116
|
+
*/
|
|
117
|
+
export interface ComponentRegistry {
|
|
118
|
+
/** Register a component */
|
|
119
|
+
register(name: string, component: Component, filePath?: string): void;
|
|
120
|
+
/** Get a component by name */
|
|
121
|
+
get(name: string): Component | undefined;
|
|
122
|
+
/** Get all registered components */
|
|
123
|
+
getAll(): Map<string, Component>;
|
|
124
|
+
/** Check if a component is registered */
|
|
125
|
+
has(name: string): boolean;
|
|
126
|
+
/** Get the file path for a registered component */
|
|
127
|
+
getPath(name: string): string | undefined;
|
|
128
|
+
/** Get all component names */
|
|
129
|
+
getNames(): string[];
|
|
130
|
+
/** Clear all registered components */
|
|
131
|
+
clear(): void;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* File scanner interface
|
|
135
|
+
*/
|
|
136
|
+
export interface FileScanner {
|
|
137
|
+
/** Scan directory for files with specified extensions */
|
|
138
|
+
scanDirectory(path: string, extensions: string[]): Promise<ScanResult>;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=index.d.ts.map
|