@qelos/plugins-cli 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/services/micro-frontends.mjs +129 -0
- package/services/plugins.mjs +23 -1
package/package.json
CHANGED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { logger } from './logger.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert a string to kebab-case
|
|
7
|
+
* @param {string} str - String to convert
|
|
8
|
+
* @returns {string} Kebab-cased string
|
|
9
|
+
*/
|
|
10
|
+
function toKebabCase(str) {
|
|
11
|
+
return str
|
|
12
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
13
|
+
.replace(/[\s_]+/g, '-')
|
|
14
|
+
.toLowerCase();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extract micro-frontend structures to separate HTML files
|
|
19
|
+
* @param {Array} microFrontends - Array of micro-frontend objects
|
|
20
|
+
* @param {string} pluginPath - Base path for the plugin directory
|
|
21
|
+
* @returns {Array} Updated micro-frontends with $ref instead of structure
|
|
22
|
+
*/
|
|
23
|
+
export function extractMicroFrontendStructures(microFrontends, pluginPath) {
|
|
24
|
+
if (!microFrontends || microFrontends.length === 0) {
|
|
25
|
+
return microFrontends;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const microFrontendsDir = path.join(pluginPath, 'micro-frontends');
|
|
29
|
+
|
|
30
|
+
// Create micro-frontends directory if it doesn't exist
|
|
31
|
+
if (!fs.existsSync(microFrontendsDir)) {
|
|
32
|
+
fs.mkdirSync(microFrontendsDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return microFrontends.map((mf) => {
|
|
36
|
+
// Skip if no structure or structure is already a reference
|
|
37
|
+
if (!mf.structure || typeof mf.structure === 'object') {
|
|
38
|
+
return mf;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Generate filename from route name or micro-frontend name
|
|
42
|
+
const fileName = mf.route?.name
|
|
43
|
+
? toKebabCase(mf.route.name)
|
|
44
|
+
: toKebabCase(mf.name);
|
|
45
|
+
|
|
46
|
+
const htmlFileName = `${fileName}.html`;
|
|
47
|
+
const htmlFilePath = path.join(microFrontendsDir, htmlFileName);
|
|
48
|
+
const relativeRef = `./micro-frontends/${htmlFileName}`;
|
|
49
|
+
|
|
50
|
+
// Write structure to HTML file
|
|
51
|
+
fs.writeFileSync(htmlFilePath, mf.structure, 'utf-8');
|
|
52
|
+
logger.debug(`Extracted structure to: ${relativeRef}`);
|
|
53
|
+
|
|
54
|
+
// Return micro-frontend with $ref instead of structure
|
|
55
|
+
return {
|
|
56
|
+
...mf,
|
|
57
|
+
structure: { $ref: relativeRef }
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Load content from a $ref reference
|
|
64
|
+
* @param {string} ref - Reference path (relative, absolute, or URL)
|
|
65
|
+
* @param {string} basePath - Base path for resolving relative references
|
|
66
|
+
* @returns {Promise<string>} Loaded content
|
|
67
|
+
*/
|
|
68
|
+
async function loadReference(ref, basePath) {
|
|
69
|
+
// Handle HTTP/HTTPS URLs
|
|
70
|
+
if (ref.startsWith('http://') || ref.startsWith('https://')) {
|
|
71
|
+
logger.debug(`Loading structure from URL: ${ref}`);
|
|
72
|
+
try {
|
|
73
|
+
const response = await fetch(ref);
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
76
|
+
}
|
|
77
|
+
return await response.text();
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new Error(`Failed to load from URL ${ref}: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Handle absolute and relative paths
|
|
84
|
+
const filePath = path.isAbsolute(ref)
|
|
85
|
+
? ref
|
|
86
|
+
: path.resolve(basePath, ref);
|
|
87
|
+
|
|
88
|
+
logger.debug(`Loading structure from file: ${filePath}`);
|
|
89
|
+
|
|
90
|
+
if (!fs.existsSync(filePath)) {
|
|
91
|
+
throw new Error(`Referenced file does not exist: ${filePath}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Resolve micro-frontend structures from $ref references
|
|
99
|
+
* @param {Array} microFrontends - Array of micro-frontend objects
|
|
100
|
+
* @param {string} pluginPath - Base path for resolving relative references
|
|
101
|
+
* @returns {Promise<Array>} Updated micro-frontends with resolved structures
|
|
102
|
+
*/
|
|
103
|
+
export async function resolveMicroFrontendStructures(microFrontends, pluginPath) {
|
|
104
|
+
if (!microFrontends || microFrontends.length === 0) {
|
|
105
|
+
return microFrontends;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return await Promise.all(microFrontends.map(async (mf) => {
|
|
109
|
+
// Skip if no structure or structure is not a reference object
|
|
110
|
+
if (!mf.structure || typeof mf.structure !== 'object' || !mf.structure.$ref) {
|
|
111
|
+
return mf;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const ref = mf.structure.$ref;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const content = await loadReference(ref, pluginPath);
|
|
118
|
+
|
|
119
|
+
// Return micro-frontend with resolved structure
|
|
120
|
+
return {
|
|
121
|
+
...mf,
|
|
122
|
+
structure: content
|
|
123
|
+
};
|
|
124
|
+
} catch (error) {
|
|
125
|
+
logger.error(`Failed to resolve $ref for ${mf.name}: ${error.message}`);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}));
|
|
129
|
+
}
|
package/services/plugins.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { join } from 'node:path';
|
|
3
4
|
import { logger } from './logger.mjs';
|
|
5
|
+
import { extractMicroFrontendStructures, resolveMicroFrontendStructures } from './micro-frontends.mjs';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Push plugins from local directory to remote
|
|
@@ -38,6 +40,19 @@ export async function pushPlugins(sdk, path) {
|
|
|
38
40
|
|
|
39
41
|
logger.step(`Pushing plugin: ${apiPath}`);
|
|
40
42
|
|
|
43
|
+
// Resolve micro-frontend structures from $ref references
|
|
44
|
+
if (pluginData.microFrontends && pluginData.microFrontends.length > 0) {
|
|
45
|
+
try {
|
|
46
|
+
pluginData.microFrontends = await resolveMicroFrontendStructures(
|
|
47
|
+
pluginData.microFrontends,
|
|
48
|
+
path
|
|
49
|
+
);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
logger.error(`Failed to resolve micro-frontend structures for ${apiPath}`, error);
|
|
52
|
+
throw new Error(`Failed to resolve structures for ${apiPath}: ${error.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
const existingPlugin = existingPlugins.find(
|
|
42
57
|
plugin => plugin.apiPath === apiPath
|
|
43
58
|
);
|
|
@@ -126,6 +141,7 @@ export async function pullPlugins(sdk, targetPath) {
|
|
|
126
141
|
await Promise.all(plugins.map(async (plugin) => {
|
|
127
142
|
const fileName = `${plugin.apiPath}.plugin.json`;
|
|
128
143
|
const filePath = join(targetPath, fileName);
|
|
144
|
+
const pluginDir = join(targetPath, plugin.apiPath);
|
|
129
145
|
|
|
130
146
|
// Fetch full plugin details
|
|
131
147
|
const fullPlugin = await sdk.managePlugins.getById(plugin._id);
|
|
@@ -135,6 +151,12 @@ export async function pullPlugins(sdk, targetPath) {
|
|
|
135
151
|
return rest;
|
|
136
152
|
}
|
|
137
153
|
|
|
154
|
+
// Extract micro-frontend structures to separate files
|
|
155
|
+
const processedMicroFrontends = extractMicroFrontendStructures(
|
|
156
|
+
(fullPlugin.microFrontends || []).map(removeIdFromObject),
|
|
157
|
+
targetPath
|
|
158
|
+
);
|
|
159
|
+
|
|
138
160
|
const relevantFields = {
|
|
139
161
|
name: fullPlugin.name,
|
|
140
162
|
description: fullPlugin.description,
|
|
@@ -145,7 +167,7 @@ export async function pullPlugins(sdk, targetPath) {
|
|
|
145
167
|
authAcquire: fullPlugin.authAcquire,
|
|
146
168
|
proxyUrl: fullPlugin.proxyUrl,
|
|
147
169
|
subscribedEvents: (fullPlugin.subscribedEvents || []).map(removeIdFromObject),
|
|
148
|
-
microFrontends:
|
|
170
|
+
microFrontends: processedMicroFrontends,
|
|
149
171
|
injectables: (fullPlugin.injectables || []).map(removeIdFromObject),
|
|
150
172
|
navBarGroups: (fullPlugin.navBarGroups || []).map(removeIdFromObject),
|
|
151
173
|
cruds: (fullPlugin.cruds || []).map(removeIdFromObject),
|