@magentrix-corp/magentrix-cli 1.3.16 → 1.3.17
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/LICENSE +25 -25
- package/README.md +1166 -1166
- package/actions/autopublish.old.js +293 -293
- package/actions/config.js +182 -182
- package/actions/create.js +466 -466
- package/actions/help.js +164 -164
- package/actions/iris/buildStage.js +874 -874
- package/actions/iris/delete.js +256 -256
- package/actions/iris/dev.js +391 -391
- package/actions/iris/index.js +6 -6
- package/actions/iris/link.js +375 -375
- package/actions/iris/recover.js +268 -268
- package/actions/main.js +80 -80
- package/actions/publish.js +1420 -1420
- package/actions/pull.js +684 -684
- package/actions/setup.js +148 -148
- package/actions/status.js +17 -17
- package/actions/update.js +248 -248
- package/bin/magentrix.js +393 -393
- package/package.json +55 -55
- package/utils/assetPaths.js +158 -158
- package/utils/autopublishLock.js +77 -77
- package/utils/cacher.js +206 -206
- package/utils/cli/checkInstanceUrl.js +76 -74
- package/utils/cli/helpers/compare.js +282 -282
- package/utils/cli/helpers/ensureApiKey.js +63 -63
- package/utils/cli/helpers/ensureCredentials.js +68 -68
- package/utils/cli/helpers/ensureInstanceUrl.js +75 -75
- package/utils/cli/writeRecords.js +262 -262
- package/utils/compare.js +135 -135
- package/utils/compress.js +17 -17
- package/utils/config.js +527 -527
- package/utils/debug.js +144 -144
- package/utils/diagnostics/testPublishLogic.js +96 -96
- package/utils/diff.js +49 -49
- package/utils/downloadAssets.js +291 -291
- package/utils/filetag.js +115 -115
- package/utils/hash.js +14 -14
- package/utils/iris/backup.js +411 -411
- package/utils/iris/builder.js +541 -541
- package/utils/iris/config-reader.js +664 -664
- package/utils/iris/deleteHelper.js +150 -150
- package/utils/iris/errors.js +537 -537
- package/utils/iris/linker.js +601 -601
- package/utils/iris/lock.js +360 -360
- package/utils/iris/validation.js +360 -360
- package/utils/iris/validator.js +281 -281
- package/utils/iris/zipper.js +248 -248
- package/utils/logger.js +291 -291
- package/utils/magentrix/api/assets.js +220 -220
- package/utils/magentrix/api/auth.js +107 -107
- package/utils/magentrix/api/createEntity.js +61 -61
- package/utils/magentrix/api/deleteEntity.js +55 -55
- package/utils/magentrix/api/iris.js +251 -251
- package/utils/magentrix/api/meqlQuery.js +36 -36
- package/utils/magentrix/api/retrieveEntity.js +86 -86
- package/utils/magentrix/api/updateEntity.js +66 -66
- package/utils/magentrix/fetch.js +168 -168
- package/utils/merge.js +22 -22
- package/utils/permissionError.js +70 -70
- package/utils/preferences.js +40 -40
- package/utils/progress.js +469 -469
- package/utils/spinner.js +43 -43
- package/utils/template.js +52 -52
- package/utils/updateFileBase.js +121 -121
- package/utils/workspaces.js +108 -108
- package/vars/config.js +11 -11
- package/vars/global.js +50 -50
package/utils/iris/validator.js
CHANGED
|
@@ -1,281 +1,281 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Required file patterns for a valid Iris build.
|
|
6
|
-
*/
|
|
7
|
-
const REQUIRED_FILES = {
|
|
8
|
-
remoteEntry: {
|
|
9
|
-
pattern: /^remoteEntry\.js$/,
|
|
10
|
-
location: 'root',
|
|
11
|
-
description: 'remoteEntry.js (required at dist root)'
|
|
12
|
-
},
|
|
13
|
-
hostInit: {
|
|
14
|
-
pattern: /^hostInit.*\.js$/,
|
|
15
|
-
location: 'assets',
|
|
16
|
-
description: 'assets/hostInit*.js (required in assets folder)'
|
|
17
|
-
},
|
|
18
|
-
main: {
|
|
19
|
-
pattern: /^main.*\.js$/,
|
|
20
|
-
location: 'assets',
|
|
21
|
-
description: 'assets/main*.js (required in assets folder)'
|
|
22
|
-
},
|
|
23
|
-
index: {
|
|
24
|
-
pattern: /^index.*\.js$/,
|
|
25
|
-
location: 'assets',
|
|
26
|
-
description: 'assets/index*.js (required in assets folder)'
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Validate that a build output directory contains all required Iris files.
|
|
32
|
-
*
|
|
33
|
-
* @param {string} distPath - Path to the build output directory (e.g., ./dist)
|
|
34
|
-
* @returns {{
|
|
35
|
-
* valid: boolean,
|
|
36
|
-
* errors: string[],
|
|
37
|
-
* warnings: string[],
|
|
38
|
-
* files: {
|
|
39
|
-
* remoteEntry: string | null,
|
|
40
|
-
* hostInit: string | null,
|
|
41
|
-
* main: string | null,
|
|
42
|
-
* index: string | null
|
|
43
|
-
* },
|
|
44
|
-
* assetsPath: string | null
|
|
45
|
-
* }}
|
|
46
|
-
*/
|
|
47
|
-
export function validateIrisBuild(distPath) {
|
|
48
|
-
const result = {
|
|
49
|
-
valid: true,
|
|
50
|
-
errors: [],
|
|
51
|
-
warnings: [],
|
|
52
|
-
files: {
|
|
53
|
-
remoteEntry: null,
|
|
54
|
-
hostInit: null,
|
|
55
|
-
main: null,
|
|
56
|
-
index: null
|
|
57
|
-
},
|
|
58
|
-
assetsPath: null
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// Check if dist path exists
|
|
62
|
-
if (!existsSync(distPath)) {
|
|
63
|
-
result.valid = false;
|
|
64
|
-
result.errors.push(`Build output directory not found: ${distPath}`);
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Check if it's a directory
|
|
69
|
-
const distStat = statSync(distPath);
|
|
70
|
-
if (!distStat.isDirectory()) {
|
|
71
|
-
result.valid = false;
|
|
72
|
-
result.errors.push(`Build output path is not a directory: ${distPath}`);
|
|
73
|
-
return result;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Get root files
|
|
77
|
-
let rootFiles;
|
|
78
|
-
try {
|
|
79
|
-
rootFiles = readdirSync(distPath);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
result.valid = false;
|
|
82
|
-
result.errors.push(`Failed to read build directory: ${err.message}`);
|
|
83
|
-
return result;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Check for remoteEntry.js in root
|
|
87
|
-
const remoteEntryFile = rootFiles.find(f => REQUIRED_FILES.remoteEntry.pattern.test(f));
|
|
88
|
-
if (remoteEntryFile) {
|
|
89
|
-
result.files.remoteEntry = path.join(distPath, remoteEntryFile);
|
|
90
|
-
} else {
|
|
91
|
-
result.valid = false;
|
|
92
|
-
result.errors.push(REQUIRED_FILES.remoteEntry.description);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Check for assets directory
|
|
96
|
-
const assetsDir = rootFiles.find(f => f.toLowerCase() === 'assets');
|
|
97
|
-
if (!assetsDir) {
|
|
98
|
-
result.valid = false;
|
|
99
|
-
result.errors.push('assets/ directory not found in build output');
|
|
100
|
-
return result;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const assetsPath = path.join(distPath, assetsDir);
|
|
104
|
-
result.assetsPath = assetsPath;
|
|
105
|
-
|
|
106
|
-
// Check if assets is a directory
|
|
107
|
-
const assetsStat = statSync(assetsPath);
|
|
108
|
-
if (!assetsStat.isDirectory()) {
|
|
109
|
-
result.valid = false;
|
|
110
|
-
result.errors.push('assets is not a directory');
|
|
111
|
-
return result;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Get assets files
|
|
115
|
-
let assetsFiles;
|
|
116
|
-
try {
|
|
117
|
-
assetsFiles = readdirSync(assetsPath);
|
|
118
|
-
} catch (err) {
|
|
119
|
-
result.valid = false;
|
|
120
|
-
result.errors.push(`Failed to read assets directory: ${err.message}`);
|
|
121
|
-
return result;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Check for required files in assets
|
|
125
|
-
const hostInitFile = assetsFiles.find(f => REQUIRED_FILES.hostInit.pattern.test(f));
|
|
126
|
-
if (hostInitFile) {
|
|
127
|
-
result.files.hostInit = path.join(assetsPath, hostInitFile);
|
|
128
|
-
} else {
|
|
129
|
-
result.valid = false;
|
|
130
|
-
result.errors.push(REQUIRED_FILES.hostInit.description);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const mainFile = assetsFiles.find(f => REQUIRED_FILES.main.pattern.test(f));
|
|
134
|
-
if (mainFile) {
|
|
135
|
-
result.files.main = path.join(assetsPath, mainFile);
|
|
136
|
-
} else {
|
|
137
|
-
result.valid = false;
|
|
138
|
-
result.errors.push(REQUIRED_FILES.main.description);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const indexFile = assetsFiles.find(f => REQUIRED_FILES.index.pattern.test(f));
|
|
142
|
-
if (indexFile) {
|
|
143
|
-
result.files.index = path.join(assetsPath, indexFile);
|
|
144
|
-
} else {
|
|
145
|
-
result.valid = false;
|
|
146
|
-
result.errors.push(REQUIRED_FILES.index.description);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Warnings for potential issues
|
|
150
|
-
if (rootFiles.includes('index.html')) {
|
|
151
|
-
result.warnings.push('Found index.html in root - this file is typically not needed for Iris apps');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Format validation errors for display to the user.
|
|
159
|
-
*
|
|
160
|
-
* @param {ReturnType<typeof validateIrisBuild>} validation - Validation result
|
|
161
|
-
* @returns {string} - Formatted error message
|
|
162
|
-
*/
|
|
163
|
-
export function formatValidationErrors(validation) {
|
|
164
|
-
const lines = [
|
|
165
|
-
'Invalid Build Output',
|
|
166
|
-
'────────────────────────────────────────────────────',
|
|
167
|
-
'',
|
|
168
|
-
'The build output is missing required Iris files.',
|
|
169
|
-
'',
|
|
170
|
-
'Status:'
|
|
171
|
-
];
|
|
172
|
-
|
|
173
|
-
// Show status of each required file
|
|
174
|
-
const fileStatus = [
|
|
175
|
-
{
|
|
176
|
-
name: 'remoteEntry.js',
|
|
177
|
-
found: validation.files.remoteEntry !== null,
|
|
178
|
-
foundName: validation.files.remoteEntry ? path.basename(validation.files.remoteEntry) : null
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
name: 'assets/hostInit*.js',
|
|
182
|
-
found: validation.files.hostInit !== null,
|
|
183
|
-
foundName: validation.files.hostInit ? path.basename(validation.files.hostInit) : null
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
name: 'assets/main*.js',
|
|
187
|
-
found: validation.files.main !== null,
|
|
188
|
-
foundName: validation.files.main ? path.basename(validation.files.main) : null
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
name: 'assets/index*.js',
|
|
192
|
-
found: validation.files.index !== null,
|
|
193
|
-
foundName: validation.files.index ? path.basename(validation.files.index) : null
|
|
194
|
-
}
|
|
195
|
-
];
|
|
196
|
-
|
|
197
|
-
for (const file of fileStatus) {
|
|
198
|
-
if (file.found) {
|
|
199
|
-
lines.push(` ✓ ${file.name} (found: ${file.foundName})`);
|
|
200
|
-
} else {
|
|
201
|
-
lines.push(` ✗ ${file.name}`);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
lines.push('');
|
|
206
|
-
lines.push('Expected structure:');
|
|
207
|
-
lines.push(' dist/');
|
|
208
|
-
lines.push(' ├── remoteEntry.js');
|
|
209
|
-
lines.push(' └── assets/');
|
|
210
|
-
lines.push(' ├── hostInit-[hash].js');
|
|
211
|
-
lines.push(' ├── main-[hash].js');
|
|
212
|
-
lines.push(' └── index-[hash].js');
|
|
213
|
-
lines.push('');
|
|
214
|
-
lines.push('Make sure your Vue.js project is configured for Module Federation.');
|
|
215
|
-
|
|
216
|
-
if (validation.warnings.length > 0) {
|
|
217
|
-
lines.push('');
|
|
218
|
-
lines.push('Warnings:');
|
|
219
|
-
for (const warning of validation.warnings) {
|
|
220
|
-
lines.push(` ⚠ ${warning}`);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return lines.join('\n');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Get a summary of found files for successful validation.
|
|
229
|
-
*
|
|
230
|
-
* @param {ReturnType<typeof validateIrisBuild>} validation - Validation result
|
|
231
|
-
* @returns {string} - Summary of found files
|
|
232
|
-
*/
|
|
233
|
-
export function getValidationSummary(validation) {
|
|
234
|
-
const files = [];
|
|
235
|
-
|
|
236
|
-
if (validation.files.remoteEntry) {
|
|
237
|
-
files.push(` • ${path.basename(validation.files.remoteEntry)}`);
|
|
238
|
-
}
|
|
239
|
-
if (validation.files.hostInit) {
|
|
240
|
-
files.push(` • assets/${path.basename(validation.files.hostInit)}`);
|
|
241
|
-
}
|
|
242
|
-
if (validation.files.main) {
|
|
243
|
-
files.push(` • assets/${path.basename(validation.files.main)}`);
|
|
244
|
-
}
|
|
245
|
-
if (validation.files.index) {
|
|
246
|
-
files.push(` • assets/${path.basename(validation.files.index)}`);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return `Found ${files.length} required files:\n${files.join('\n')}`;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Validate an Iris app folder (already staged, not a dist folder).
|
|
254
|
-
* This is used to validate apps in src/iris-apps/<slug>/.
|
|
255
|
-
*
|
|
256
|
-
* @param {string} appPath - Path to the app folder
|
|
257
|
-
* @returns {{valid: boolean, errors: string[], slug: string | null}}
|
|
258
|
-
*/
|
|
259
|
-
export function validateIrisAppFolder(appPath) {
|
|
260
|
-
const result = {
|
|
261
|
-
valid: true,
|
|
262
|
-
errors: [],
|
|
263
|
-
slug: null
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
if (!existsSync(appPath)) {
|
|
267
|
-
result.valid = false;
|
|
268
|
-
result.errors.push(`App folder not found: ${appPath}`);
|
|
269
|
-
return result;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
result.slug = path.basename(appPath);
|
|
273
|
-
|
|
274
|
-
// Use the same validation as build output
|
|
275
|
-
const validation = validateIrisBuild(appPath);
|
|
276
|
-
|
|
277
|
-
result.valid = validation.valid;
|
|
278
|
-
result.errors = validation.errors;
|
|
279
|
-
|
|
280
|
-
return result;
|
|
281
|
-
}
|
|
1
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Required file patterns for a valid Iris build.
|
|
6
|
+
*/
|
|
7
|
+
const REQUIRED_FILES = {
|
|
8
|
+
remoteEntry: {
|
|
9
|
+
pattern: /^remoteEntry\.js$/,
|
|
10
|
+
location: 'root',
|
|
11
|
+
description: 'remoteEntry.js (required at dist root)'
|
|
12
|
+
},
|
|
13
|
+
hostInit: {
|
|
14
|
+
pattern: /^hostInit.*\.js$/,
|
|
15
|
+
location: 'assets',
|
|
16
|
+
description: 'assets/hostInit*.js (required in assets folder)'
|
|
17
|
+
},
|
|
18
|
+
main: {
|
|
19
|
+
pattern: /^main.*\.js$/,
|
|
20
|
+
location: 'assets',
|
|
21
|
+
description: 'assets/main*.js (required in assets folder)'
|
|
22
|
+
},
|
|
23
|
+
index: {
|
|
24
|
+
pattern: /^index.*\.js$/,
|
|
25
|
+
location: 'assets',
|
|
26
|
+
description: 'assets/index*.js (required in assets folder)'
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Validate that a build output directory contains all required Iris files.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} distPath - Path to the build output directory (e.g., ./dist)
|
|
34
|
+
* @returns {{
|
|
35
|
+
* valid: boolean,
|
|
36
|
+
* errors: string[],
|
|
37
|
+
* warnings: string[],
|
|
38
|
+
* files: {
|
|
39
|
+
* remoteEntry: string | null,
|
|
40
|
+
* hostInit: string | null,
|
|
41
|
+
* main: string | null,
|
|
42
|
+
* index: string | null
|
|
43
|
+
* },
|
|
44
|
+
* assetsPath: string | null
|
|
45
|
+
* }}
|
|
46
|
+
*/
|
|
47
|
+
export function validateIrisBuild(distPath) {
|
|
48
|
+
const result = {
|
|
49
|
+
valid: true,
|
|
50
|
+
errors: [],
|
|
51
|
+
warnings: [],
|
|
52
|
+
files: {
|
|
53
|
+
remoteEntry: null,
|
|
54
|
+
hostInit: null,
|
|
55
|
+
main: null,
|
|
56
|
+
index: null
|
|
57
|
+
},
|
|
58
|
+
assetsPath: null
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Check if dist path exists
|
|
62
|
+
if (!existsSync(distPath)) {
|
|
63
|
+
result.valid = false;
|
|
64
|
+
result.errors.push(`Build output directory not found: ${distPath}`);
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check if it's a directory
|
|
69
|
+
const distStat = statSync(distPath);
|
|
70
|
+
if (!distStat.isDirectory()) {
|
|
71
|
+
result.valid = false;
|
|
72
|
+
result.errors.push(`Build output path is not a directory: ${distPath}`);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get root files
|
|
77
|
+
let rootFiles;
|
|
78
|
+
try {
|
|
79
|
+
rootFiles = readdirSync(distPath);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
result.valid = false;
|
|
82
|
+
result.errors.push(`Failed to read build directory: ${err.message}`);
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Check for remoteEntry.js in root
|
|
87
|
+
const remoteEntryFile = rootFiles.find(f => REQUIRED_FILES.remoteEntry.pattern.test(f));
|
|
88
|
+
if (remoteEntryFile) {
|
|
89
|
+
result.files.remoteEntry = path.join(distPath, remoteEntryFile);
|
|
90
|
+
} else {
|
|
91
|
+
result.valid = false;
|
|
92
|
+
result.errors.push(REQUIRED_FILES.remoteEntry.description);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check for assets directory
|
|
96
|
+
const assetsDir = rootFiles.find(f => f.toLowerCase() === 'assets');
|
|
97
|
+
if (!assetsDir) {
|
|
98
|
+
result.valid = false;
|
|
99
|
+
result.errors.push('assets/ directory not found in build output');
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const assetsPath = path.join(distPath, assetsDir);
|
|
104
|
+
result.assetsPath = assetsPath;
|
|
105
|
+
|
|
106
|
+
// Check if assets is a directory
|
|
107
|
+
const assetsStat = statSync(assetsPath);
|
|
108
|
+
if (!assetsStat.isDirectory()) {
|
|
109
|
+
result.valid = false;
|
|
110
|
+
result.errors.push('assets is not a directory');
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Get assets files
|
|
115
|
+
let assetsFiles;
|
|
116
|
+
try {
|
|
117
|
+
assetsFiles = readdirSync(assetsPath);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
result.valid = false;
|
|
120
|
+
result.errors.push(`Failed to read assets directory: ${err.message}`);
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check for required files in assets
|
|
125
|
+
const hostInitFile = assetsFiles.find(f => REQUIRED_FILES.hostInit.pattern.test(f));
|
|
126
|
+
if (hostInitFile) {
|
|
127
|
+
result.files.hostInit = path.join(assetsPath, hostInitFile);
|
|
128
|
+
} else {
|
|
129
|
+
result.valid = false;
|
|
130
|
+
result.errors.push(REQUIRED_FILES.hostInit.description);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const mainFile = assetsFiles.find(f => REQUIRED_FILES.main.pattern.test(f));
|
|
134
|
+
if (mainFile) {
|
|
135
|
+
result.files.main = path.join(assetsPath, mainFile);
|
|
136
|
+
} else {
|
|
137
|
+
result.valid = false;
|
|
138
|
+
result.errors.push(REQUIRED_FILES.main.description);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const indexFile = assetsFiles.find(f => REQUIRED_FILES.index.pattern.test(f));
|
|
142
|
+
if (indexFile) {
|
|
143
|
+
result.files.index = path.join(assetsPath, indexFile);
|
|
144
|
+
} else {
|
|
145
|
+
result.valid = false;
|
|
146
|
+
result.errors.push(REQUIRED_FILES.index.description);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Warnings for potential issues
|
|
150
|
+
if (rootFiles.includes('index.html')) {
|
|
151
|
+
result.warnings.push('Found index.html in root - this file is typically not needed for Iris apps');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Format validation errors for display to the user.
|
|
159
|
+
*
|
|
160
|
+
* @param {ReturnType<typeof validateIrisBuild>} validation - Validation result
|
|
161
|
+
* @returns {string} - Formatted error message
|
|
162
|
+
*/
|
|
163
|
+
export function formatValidationErrors(validation) {
|
|
164
|
+
const lines = [
|
|
165
|
+
'Invalid Build Output',
|
|
166
|
+
'────────────────────────────────────────────────────',
|
|
167
|
+
'',
|
|
168
|
+
'The build output is missing required Iris files.',
|
|
169
|
+
'',
|
|
170
|
+
'Status:'
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
// Show status of each required file
|
|
174
|
+
const fileStatus = [
|
|
175
|
+
{
|
|
176
|
+
name: 'remoteEntry.js',
|
|
177
|
+
found: validation.files.remoteEntry !== null,
|
|
178
|
+
foundName: validation.files.remoteEntry ? path.basename(validation.files.remoteEntry) : null
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: 'assets/hostInit*.js',
|
|
182
|
+
found: validation.files.hostInit !== null,
|
|
183
|
+
foundName: validation.files.hostInit ? path.basename(validation.files.hostInit) : null
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'assets/main*.js',
|
|
187
|
+
found: validation.files.main !== null,
|
|
188
|
+
foundName: validation.files.main ? path.basename(validation.files.main) : null
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'assets/index*.js',
|
|
192
|
+
found: validation.files.index !== null,
|
|
193
|
+
foundName: validation.files.index ? path.basename(validation.files.index) : null
|
|
194
|
+
}
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
for (const file of fileStatus) {
|
|
198
|
+
if (file.found) {
|
|
199
|
+
lines.push(` ✓ ${file.name} (found: ${file.foundName})`);
|
|
200
|
+
} else {
|
|
201
|
+
lines.push(` ✗ ${file.name}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
lines.push('');
|
|
206
|
+
lines.push('Expected structure:');
|
|
207
|
+
lines.push(' dist/');
|
|
208
|
+
lines.push(' ├── remoteEntry.js');
|
|
209
|
+
lines.push(' └── assets/');
|
|
210
|
+
lines.push(' ├── hostInit-[hash].js');
|
|
211
|
+
lines.push(' ├── main-[hash].js');
|
|
212
|
+
lines.push(' └── index-[hash].js');
|
|
213
|
+
lines.push('');
|
|
214
|
+
lines.push('Make sure your Vue.js project is configured for Module Federation.');
|
|
215
|
+
|
|
216
|
+
if (validation.warnings.length > 0) {
|
|
217
|
+
lines.push('');
|
|
218
|
+
lines.push('Warnings:');
|
|
219
|
+
for (const warning of validation.warnings) {
|
|
220
|
+
lines.push(` ⚠ ${warning}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return lines.join('\n');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get a summary of found files for successful validation.
|
|
229
|
+
*
|
|
230
|
+
* @param {ReturnType<typeof validateIrisBuild>} validation - Validation result
|
|
231
|
+
* @returns {string} - Summary of found files
|
|
232
|
+
*/
|
|
233
|
+
export function getValidationSummary(validation) {
|
|
234
|
+
const files = [];
|
|
235
|
+
|
|
236
|
+
if (validation.files.remoteEntry) {
|
|
237
|
+
files.push(` • ${path.basename(validation.files.remoteEntry)}`);
|
|
238
|
+
}
|
|
239
|
+
if (validation.files.hostInit) {
|
|
240
|
+
files.push(` • assets/${path.basename(validation.files.hostInit)}`);
|
|
241
|
+
}
|
|
242
|
+
if (validation.files.main) {
|
|
243
|
+
files.push(` • assets/${path.basename(validation.files.main)}`);
|
|
244
|
+
}
|
|
245
|
+
if (validation.files.index) {
|
|
246
|
+
files.push(` • assets/${path.basename(validation.files.index)}`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return `Found ${files.length} required files:\n${files.join('\n')}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Validate an Iris app folder (already staged, not a dist folder).
|
|
254
|
+
* This is used to validate apps in src/iris-apps/<slug>/.
|
|
255
|
+
*
|
|
256
|
+
* @param {string} appPath - Path to the app folder
|
|
257
|
+
* @returns {{valid: boolean, errors: string[], slug: string | null}}
|
|
258
|
+
*/
|
|
259
|
+
export function validateIrisAppFolder(appPath) {
|
|
260
|
+
const result = {
|
|
261
|
+
valid: true,
|
|
262
|
+
errors: [],
|
|
263
|
+
slug: null
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
if (!existsSync(appPath)) {
|
|
267
|
+
result.valid = false;
|
|
268
|
+
result.errors.push(`App folder not found: ${appPath}`);
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
result.slug = path.basename(appPath);
|
|
273
|
+
|
|
274
|
+
// Use the same validation as build output
|
|
275
|
+
const validation = validateIrisBuild(appPath);
|
|
276
|
+
|
|
277
|
+
result.valid = validation.valid;
|
|
278
|
+
result.errors = validation.errors;
|
|
279
|
+
|
|
280
|
+
return result;
|
|
281
|
+
}
|