@codenotch/codenotch.cli 1.0.33 → 1.0.35
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/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/project/new.js +227 -1
- package/dist/commands/project/new.js.map +1 -1
- package/dist/commands/validation/ValidationUtils.d.ts +28 -0
- package/dist/commands/validation/ValidationUtils.js +182 -0
- package/dist/commands/validation/ValidationUtils.js.map +1 -0
- package/dist/commands/validation/files/AppManifestValidator.d.ts +6 -0
- package/dist/commands/validation/files/AppManifestValidator.js +93 -0
- package/dist/commands/validation/files/AppManifestValidator.js.map +1 -0
- package/dist/commands/validation/files/BpmnValidator.d.ts +5 -0
- package/dist/commands/validation/files/BpmnValidator.js +32 -0
- package/dist/commands/validation/files/BpmnValidator.js.map +1 -0
- package/dist/commands/validation/files/DbSchemaValidator.d.ts +5 -0
- package/dist/commands/validation/files/DbSchemaValidator.js +16 -0
- package/dist/commands/validation/files/DbSchemaValidator.js.map +1 -0
- package/dist/commands/validation/files/DocumentValidator.d.ts +5 -0
- package/dist/commands/validation/files/DocumentValidator.js +12 -0
- package/dist/commands/validation/files/DocumentValidator.js.map +1 -0
- package/dist/commands/validation/files/I18nValidator.d.ts +5 -0
- package/dist/commands/validation/files/I18nValidator.js +13 -0
- package/dist/commands/validation/files/I18nValidator.js.map +1 -0
- package/dist/commands/validation/files/JsonValidator.d.ts +5 -0
- package/dist/commands/validation/files/JsonValidator.js +13 -0
- package/dist/commands/validation/files/JsonValidator.js.map +1 -0
- package/dist/commands/validation/files/ManifestCacheValidator.d.ts +5 -0
- package/dist/commands/validation/files/ManifestCacheValidator.js +121 -0
- package/dist/commands/validation/files/ManifestCacheValidator.js.map +1 -0
- package/dist/commands/validation/files/ManifestValidator.d.ts +5 -0
- package/dist/commands/validation/files/ManifestValidator.js +14 -0
- package/dist/commands/validation/files/ManifestValidator.js.map +1 -0
- package/dist/commands/validation/files/ScriptValidator.d.ts +12 -0
- package/dist/commands/validation/files/ScriptValidator.js +128 -0
- package/dist/commands/validation/files/ScriptValidator.js.map +1 -0
- package/dist/commands/validation/files/TableValidator.d.ts +5 -0
- package/dist/commands/validation/files/TableValidator.js +19 -0
- package/dist/commands/validation/files/TableValidator.js.map +1 -0
- package/dist/commands/validation/validate.d.ts +2 -0
- package/dist/commands/validation/validate.js +245 -0
- package/dist/commands/validation/validate.js.map +1 -0
- package/dist/utils/BuildUtils.d.ts +23 -4
- package/dist/utils/BuildUtils.js +46 -16
- package/dist/utils/BuildUtils.js.map +1 -1
- package/dist/utils/FileUtils.d.ts +13 -0
- package/dist/utils/FileUtils.js +30 -0
- package/dist/utils/FileUtils.js.map +1 -1
- package/dist/utils/I18nUtils.js +0 -2
- package/dist/utils/I18nUtils.js.map +1 -1
- package/package.json +14 -6
- package/.github/copilot-instructions.md +0 -3
- package/bin/cli.js +0 -3
- package/docs/ARCHITECTURE.md +0 -179
- package/docs/TODO.md +0 -18
- package/src/bin/cli.ts +0 -4
- package/src/commands/index.ts +0 -13
- package/src/commands/project/compile.ts +0 -20
- package/src/commands/project/deploy.ts +0 -11
- package/src/commands/project/index.ts +0 -28
- package/src/commands/project/inspect.ts +0 -12
- package/src/commands/project/new.ts +0 -11
- package/src/commands/project/open.ts +0 -21
- package/src/commands/project/package.ts +0 -20
- package/src/commands/project/refresh.ts +0 -13
- package/src/commands/project/remove.ts +0 -12
- package/src/commands/project/shared.ts +0 -9
- package/src/commands/project/start.ts +0 -24
- package/src/commands/project/test.ts +0 -15
- package/src/commands/react/build.ts +0 -12
- package/src/commands/react/index.ts +0 -12
- package/src/commands/react/serve.ts +0 -13
- package/src/commands/runtime/clear.ts +0 -11
- package/src/commands/runtime/index.ts +0 -24
- package/src/commands/runtime/info.ts +0 -47
- package/src/commands/runtime/latest.ts +0 -18
- package/src/commands/runtime/portal.ts +0 -20
- package/src/commands/runtime/start.ts +0 -16
- package/src/commands/runtime/stop.ts +0 -13
- package/src/commands/runtime/update.ts +0 -12
- package/src/commands/system/index.ts +0 -9
- package/src/commands/system/info.ts +0 -23
- package/src/commands/system/read.ts +0 -25
- package/src/index.ts +0 -22
- package/src/models/Codenotch.ts +0 -361
- package/src/models/DbModels.ts +0 -428
- package/src/models/OpenApiModels.ts +0 -145
- package/src/utils/BuildUtils.ts +0 -739
- package/src/utils/ConsoleUtils.ts +0 -22
- package/src/utils/FileUtils.ts +0 -266
- package/src/utils/GitHubAuthUtils.ts +0 -83
- package/src/utils/I18nUtils.ts +0 -58
- package/src/utils/OpenAPIUtils.ts +0 -285
- package/src/utils/OsUtils.ts +0 -32
- package/src/utils/ProjectCompilationUtils.ts +0 -1002
- package/src/utils/ProjectUtils.ts +0 -151
- package/src/utils/RuntimeUtils.ts +0 -743
- package/src/utils/ServeUtils.ts +0 -175
- package/src/utils/ShellUtils.ts +0 -26
- package/src/utils/StringUtils.ts +0 -80
- package/tsconfig.json +0 -35
package/src/utils/BuildUtils.ts
DELETED
|
@@ -1,739 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readSync } from "fs";
|
|
2
|
-
import StringUtils from "./StringUtils";
|
|
3
|
-
import { ApplicationManifest, IScenarioProjectManifest, IWorkspaceCache, ProjectManifest } from "../models/Codenotch";
|
|
4
|
-
import FileUtils from "./FileUtils";
|
|
5
|
-
import chalk from "chalk";
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import fse from 'fs-extra';
|
|
8
|
-
import I18nUtils from "./I18nUtils";
|
|
9
|
-
import fetch from "node-fetch";
|
|
10
|
-
import ShellUtils from "./ShellUtils";
|
|
11
|
-
import { platform } from "os";
|
|
12
|
-
import ConsoleUtils from "./ConsoleUtils";
|
|
13
|
-
|
|
14
|
-
interface IWorkspace {
|
|
15
|
-
manifest: ProjectManifest;
|
|
16
|
-
path: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface IBuildOptions {
|
|
20
|
-
cluster?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default abstract class BuildUtils {
|
|
24
|
-
|
|
25
|
-
static findWorkspaceFromFile(childPath: string) {
|
|
26
|
-
let parts = childPath.split(FileUtils.slash());
|
|
27
|
-
parts = parts.slice(0, parts.length - 1); // Remove file name
|
|
28
|
-
let workspacePath: string | undefined = undefined;
|
|
29
|
-
while (parts.length > 0) {
|
|
30
|
-
let checkPath = parts.join(FileUtils.slash());
|
|
31
|
-
parts.pop();
|
|
32
|
-
let checkManifestPath = StringUtils.normalizePath(`${checkPath}\\manifest.json`);
|
|
33
|
-
if (existsSync(checkManifestPath)) {
|
|
34
|
-
workspacePath = checkPath;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return workspacePath;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* cn react build <target_file>
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
static async buildApp(appFilePath: string, clusterUrl?: string) {
|
|
45
|
-
//appFilePath = '/home/fabian/Documents/Scenario/test-with-jsx/apps/AppWithFC.tsx';
|
|
46
|
-
//clusterUrl = 'https://fabric.echino.com:19081/lemollqa/scenario';
|
|
47
|
-
|
|
48
|
-
if(`${appFilePath??''}`.trim() === ''){
|
|
49
|
-
console.log(chalk.red(`Error: No target file provided for build command.`));
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let isRelative = !appFilePath.startsWith('/') && !appFilePath.match(/^[a-zA-Z]:\\/);
|
|
54
|
-
if (isRelative) {
|
|
55
|
-
let currentPath = process.cwd();
|
|
56
|
-
appFilePath = StringUtils.normalizePath(`${currentPath}/${appFilePath}`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// Check arguments
|
|
61
|
-
if (existsSync(appFilePath ?? '') === false) {
|
|
62
|
-
console.log(chalk.red(`Error: File "${appFilePath}" not found`));
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let workspacePath = this.findWorkspaceFromFile(appFilePath) ?? '';
|
|
67
|
-
if (workspacePath === '' || existsSync(workspacePath ?? '') === false) {
|
|
68
|
-
console.log(chalk.red(`Error: Could not find workspace manifest for file "${appFilePath}".`));
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// Tenant name
|
|
75
|
-
let tenantName = await this.fetchTenantName(clusterUrl);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// Load workspace
|
|
80
|
-
console.log("Loading workspace manifest...");
|
|
81
|
-
let workspace: IWorkspace = {
|
|
82
|
-
manifest: this.getFullManifestAt(workspacePath),
|
|
83
|
-
path: workspacePath
|
|
84
|
-
};
|
|
85
|
-
ConsoleUtils.check(`Workspace manifest loaded successfully\n`);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// Get app manifest
|
|
90
|
-
console.log(`Reading app manifest... (${appFilePath})`);
|
|
91
|
-
let appFilename = StringUtils.getFilenameFromUri(appFilePath);
|
|
92
|
-
let appFileParentPath = StringUtils.getFolder(appFilePath);
|
|
93
|
-
let appManifestPath = StringUtils.normalizePath(`${appFileParentPath}/${appFilename.replace(/\.[^/.]+$/, '.manifest.json')}`);
|
|
94
|
-
let appManifestContent = fs.readFileSync(appManifestPath, 'utf-8');
|
|
95
|
-
if (appManifestContent === undefined) {
|
|
96
|
-
console.log(chalk.red(`Error: App manifest file not found at "${appManifestPath}"\n`));
|
|
97
|
-
process.exit(1);
|
|
98
|
-
}
|
|
99
|
-
let appManifest: ApplicationManifest = JSON.parse(appManifestContent);
|
|
100
|
-
let appName = `${appManifest.auml?.name ?? ''}`.trim();
|
|
101
|
-
if (appName === '') {
|
|
102
|
-
console.log(chalk.red(`Error: App name not found in manifest at "${appManifestPath}"\n`));
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
ConsoleUtils.check(`App manifest loaded successfully (App name: "${appName}").\n`);
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// Define paths
|
|
109
|
-
let outDir = StringUtils.normalizePath(`${workspacePath}/.codenotch/${appName}-source`);
|
|
110
|
-
let distDir = StringUtils.normalizePath(`${workspacePath}/.codenotch/${appName}-dist`);
|
|
111
|
-
let fileName = StringUtils.firstUpper(StringUtils.getNameWithoutExtention(appFilename));
|
|
112
|
-
let outFilePath = StringUtils.normalizePath(`${appFilePath.replace(workspacePath, outDir + '/src')}`);
|
|
113
|
-
let relativeOutFilePath = StringUtils.toRelativePath(outFilePath, outDir).replaceAll('\\', '/');
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Clean previous builds
|
|
117
|
-
if (existsSync(outDir) || existsSync(distDir)) {
|
|
118
|
-
console.log("Cleaning previous builds...");
|
|
119
|
-
FileUtils.delete(outDir);
|
|
120
|
-
FileUtils.delete(distDir);
|
|
121
|
-
ConsoleUtils.check(`Output directory cleaned (${outDir})\n`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
console.log("Creating build files...");
|
|
126
|
-
// package.json
|
|
127
|
-
let pgkJson = this.createPkgJson(workspacePath, appName);
|
|
128
|
-
FileUtils.writeFileSync(outDir + '/package.json', JSON.stringify(pgkJson, null, 4));
|
|
129
|
-
ConsoleUtils.check(`package.json created successfully`);
|
|
130
|
-
|
|
131
|
-
// index.html
|
|
132
|
-
let indexHtml = this.createIndexHtml(appManifest, appName);
|
|
133
|
-
FileUtils.writeFileSync(outDir + '/index.html', indexHtml);
|
|
134
|
-
ConsoleUtils.check(`index.html created successfully`);
|
|
135
|
-
|
|
136
|
-
// index.jsx
|
|
137
|
-
let indexJsx = this.createIndexJsx(relativeOutFilePath, fileName);
|
|
138
|
-
FileUtils.writeFileSync(outDir + '/index.jsx', indexJsx);
|
|
139
|
-
ConsoleUtils.check(`index.jsx created successfully`);
|
|
140
|
-
|
|
141
|
-
// vite.config.js
|
|
142
|
-
let viteConfig = this.createViteConfig(appName);
|
|
143
|
-
FileUtils.writeFileSync(outDir + '/vite.config.js', viteConfig);
|
|
144
|
-
ConsoleUtils.check(`vite.config.js created successfully`);
|
|
145
|
-
|
|
146
|
-
// empty-module.js
|
|
147
|
-
let emptyModule = this.createEmptyModule();
|
|
148
|
-
FileUtils.writeFileSync(outDir + '/empty-module.js', emptyModule);
|
|
149
|
-
ConsoleUtils.check(`empty-module.js created successfully`);
|
|
150
|
-
|
|
151
|
-
// tsconfig.json
|
|
152
|
-
let tsconfig = this.createTsConfig();
|
|
153
|
-
FileUtils.writeFileSync(outDir + '/tsconfig.json', tsconfig);
|
|
154
|
-
ConsoleUtils.check(`tsconfig.json created successfully`);
|
|
155
|
-
|
|
156
|
-
let npmRcContent = fs.existsSync(StringUtils.normalizePath(`${workspacePath}/.npmrc`)) ?
|
|
157
|
-
fs.readFileSync(StringUtils.normalizePath(`${workspacePath}/.npmrc`), 'utf-8') :
|
|
158
|
-
'';
|
|
159
|
-
if(npmRcContent.trim() !== ''){
|
|
160
|
-
FileUtils.writeFileSync(outDir + '/.npmrc', npmRcContent);
|
|
161
|
-
ConsoleUtils.check(`.npmrc copied successfully`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// Find files to copy
|
|
166
|
-
console.log("\n");
|
|
167
|
-
console.log("Reading files...");
|
|
168
|
-
let includedExts = ['.css', '.scss', '.tsx', '.jsx', '.ts', '.js'];
|
|
169
|
-
let includedFiles: string[] = [];
|
|
170
|
-
for (let file of FileUtils.getAllFilesFromPath(workspacePath)) {
|
|
171
|
-
if (includedExts.some(ext => file.toLowerCase().endsWith(ext))) {
|
|
172
|
-
includedFiles.push(file);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (includedFiles.length === 0) {
|
|
176
|
-
console.log(chalk.red(`Error: No files found in "${workspacePath}" to include in the build`));
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
for (let includedFile of includedFiles) {
|
|
180
|
-
let targetPath = StringUtils.normalizePath(`${includedFile.replace(workspacePath, outDir + '/src')}`);
|
|
181
|
-
fse.copySync(includedFile, targetPath);
|
|
182
|
-
}
|
|
183
|
-
ConsoleUtils.check(`${includedFiles.length} files copied successfully\n`);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// execute npm i in the outDir
|
|
188
|
-
await ShellUtils.exec(outDir, 'npm install', 'Installing dependencies', true);
|
|
189
|
-
|
|
190
|
-
// Install and use Node.js 20 with nvm (platform-specific)
|
|
191
|
-
if (platform() === 'win32') {
|
|
192
|
-
await ShellUtils.exec(outDir, 'nvm install 20 && nvm use 20 && npm run build', 'Setting up Node.js 20 and building project', true);
|
|
193
|
-
} else {
|
|
194
|
-
await ShellUtils.exec(outDir, 'bash -c ". ~/.nvm/nvm.sh && nvm install 20 && nvm use 20 && npm run build"', 'Setting up Node.js 20 and building project', true);
|
|
195
|
-
}
|
|
196
|
-
ConsoleUtils.check(`Nvm and build executed successfully\n`);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// create .env file
|
|
200
|
-
console.log("Creating .env file...");
|
|
201
|
-
let envVariables: any = await this.getCodenotchEnvVariables(workspace, {
|
|
202
|
-
appName: appName,
|
|
203
|
-
app: appManifest,
|
|
204
|
-
tenantName: tenantName,
|
|
205
|
-
clusterUrl: clusterUrl
|
|
206
|
-
});
|
|
207
|
-
let envContent = Object.keys(envVariables).map(c => `${c}=${envVariables[c]}`).join('\n');
|
|
208
|
-
FileUtils.writeFileSync(distDir + '/.env', envContent);
|
|
209
|
-
ConsoleUtils.check(`.env file created successfully\n`);
|
|
210
|
-
|
|
211
|
-
// create auml.json file
|
|
212
|
-
console.log("Creating auml.json file...");
|
|
213
|
-
let aumlJson = JSON.stringify(this.getAumlVariables(workspace, tenantName, clusterUrl), null, 4);
|
|
214
|
-
FileUtils.writeFileSync(distDir + '/auml.json', aumlJson);
|
|
215
|
-
ConsoleUtils.check(`auml.json file created successfully\n`);
|
|
216
|
-
|
|
217
|
-
let bundlePath = StringUtils.normalizePath(`${distDir}`);
|
|
218
|
-
console.log('');
|
|
219
|
-
console.log(chalk.green(`Build completed!\n`));
|
|
220
|
-
console.log(`Bundle available at "${bundlePath}"\n`);
|
|
221
|
-
|
|
222
|
-
let serveCommand = `cn react serve '${bundlePath}'`;
|
|
223
|
-
console.log(`You can serve the build using the following command:\n`);
|
|
224
|
-
console.log(chalk.green(`${serveCommand}`) + ConsoleUtils.proposeCommand('Do you want to serve the build?', serveCommand));
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
static async buildApp2(appFilePath: string): Promise<string> {
|
|
228
|
-
|
|
229
|
-
// Joé:
|
|
230
|
-
// Temporary minimal method to build React app to package and deploy the project, not sure if should replaced the current build or not
|
|
231
|
-
// Should work in CI/CD
|
|
232
|
-
// Doesn't create .env or auml.json, assume we are using the correct Node version
|
|
233
|
-
// Create/delete files, assume it's working in copy of the project
|
|
234
|
-
// In this method, caller is responsible for having Node 20 installed and ready
|
|
235
|
-
|
|
236
|
-
if(`${appFilePath??''}`.trim() === ''){
|
|
237
|
-
throw new Error(`No target file provided for build command.`);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
let isRelative = !appFilePath.startsWith('/') && !appFilePath.match(/^[a-zA-Z]:\\/);
|
|
241
|
-
if (isRelative) {
|
|
242
|
-
let currentPath = process.cwd();
|
|
243
|
-
appFilePath = StringUtils.normalizePath(`${currentPath}/${appFilePath}`);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Check arguments
|
|
247
|
-
if (existsSync(appFilePath ?? '') === false) {
|
|
248
|
-
throw new Error(`File "${appFilePath}" not found`);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
let workspacePath = this.findWorkspaceFromFile(appFilePath) ?? '';
|
|
252
|
-
if (workspacePath === '' || existsSync(workspacePath ?? '') === false) {
|
|
253
|
-
throw new Error(`Could not find workspace manifest for file "${appFilePath}".`);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Get app manifest
|
|
257
|
-
let appFilename = StringUtils.getFilenameFromUri(appFilePath);
|
|
258
|
-
let appFileParentPath = StringUtils.getFolder(appFilePath);
|
|
259
|
-
let appManifestPath = StringUtils.normalizePath(`${appFileParentPath}/${appFilename.replace(/\.[^/.]+$/, '.manifest.json')}`);
|
|
260
|
-
let appManifestContent = fs.readFileSync(appManifestPath, 'utf-8');
|
|
261
|
-
if (appManifestContent === undefined) {
|
|
262
|
-
throw new Error(`App manifest file not found at "${appManifestPath}"`);
|
|
263
|
-
}
|
|
264
|
-
let appManifest: ApplicationManifest = JSON.parse(appManifestContent);
|
|
265
|
-
let appName = `${appManifest.auml?.name ?? ''}`.trim();
|
|
266
|
-
if (appName === '') {
|
|
267
|
-
throw new Error(`App name not found in manifest at "${appManifestPath}"`);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Define paths
|
|
271
|
-
// We mirror the user's workspace layout directly under outDir (no extra "src/" wrapper),
|
|
272
|
-
// so any tool config that uses project-root-relative paths (e.g. tailwind's `content`,
|
|
273
|
-
// postcss, eslint, ...) resolves exactly as it does in the user's project.
|
|
274
|
-
let outDir = StringUtils.normalizePath(`${workspacePath}/.codenotch/${appName}-build`);
|
|
275
|
-
let distDir = StringUtils.normalizePath(`${workspacePath}/.codenotch/${appName}-dist`);
|
|
276
|
-
let fileName = StringUtils.firstUpper(StringUtils.getNameWithoutExtention(appFilename));
|
|
277
|
-
let outFilePath = StringUtils.normalizePath(`${appFilePath.replace(workspacePath, outDir)}`);
|
|
278
|
-
let relativeOutFilePath = StringUtils.toRelativePath(outFilePath, outDir).replaceAll('\\', '/');
|
|
279
|
-
|
|
280
|
-
// package.json
|
|
281
|
-
let pgkJson = this.createPkgJson(workspacePath, appName);
|
|
282
|
-
FileUtils.writeFileSync(outDir + '/package.json', JSON.stringify(pgkJson, null, 4));
|
|
283
|
-
|
|
284
|
-
// index.html
|
|
285
|
-
let indexHtml = this.createIndexHtml(appManifest, appName);
|
|
286
|
-
FileUtils.writeFileSync(outDir + '/index.html', indexHtml);
|
|
287
|
-
|
|
288
|
-
// index.jsx
|
|
289
|
-
let indexJsx = this.createIndexJsxDeployment(relativeOutFilePath, fileName);
|
|
290
|
-
FileUtils.writeFileSync(outDir + '/index.jsx', indexJsx);
|
|
291
|
-
|
|
292
|
-
// vite.config.mjs (.mjs so it always loads as ESM, regardless of package.json "type")
|
|
293
|
-
let viteConfig = this.createViteConfig(appName);
|
|
294
|
-
FileUtils.writeFileSync(outDir + '/vite.config.mjs', viteConfig);
|
|
295
|
-
|
|
296
|
-
// empty-module.js , needed to mock some modules crypto-browserify -> can we avoid this ?
|
|
297
|
-
let emptyModule = this.createEmptyModule();
|
|
298
|
-
FileUtils.writeFileSync(outDir + '/empty-module.js', emptyModule);
|
|
299
|
-
|
|
300
|
-
// tsconfig.json — layout is flat (mirrors the workspace), so typecheck the source trees
|
|
301
|
-
let tsconfig = this.createTsConfig(["**/*.ts", "**/*.tsx"]);
|
|
302
|
-
FileUtils.writeFileSync(outDir + '/tsconfig.json', tsconfig);
|
|
303
|
-
|
|
304
|
-
let npmRcContent = fs.existsSync(StringUtils.normalizePath(`${workspacePath}/.npmrc`)) ?
|
|
305
|
-
fs.readFileSync(StringUtils.normalizePath(`${workspacePath}/.npmrc`), 'utf-8') :
|
|
306
|
-
'';
|
|
307
|
-
if(npmRcContent.trim() !== ''){
|
|
308
|
-
FileUtils.writeFileSync(outDir + '/.npmrc', npmRcContent);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Find files to copy
|
|
312
|
-
//TODO what if we have 2 apps in the /apps folder ? if we build one it will copy the file from the other as they are not separated in different folders
|
|
313
|
-
let includedExts = ['.css', '.scss', '.tsx', '.jsx', '.ts', '.js', '.cjs', '.mjs'];
|
|
314
|
-
let includedFiles: string[] = [];
|
|
315
|
-
for (let file of FileUtils.getAllFilesFromPath(workspacePath)) {
|
|
316
|
-
// Skip generated/dependency trees so we don't copy the build output back into itself.
|
|
317
|
-
let normalized = file.replaceAll('\\', '/');
|
|
318
|
-
if (normalized.includes('/.codenotch/') || normalized.includes('/node_modules/')) {
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
if (includedExts.some(ext => file.toLowerCase().endsWith(ext))) {
|
|
322
|
-
includedFiles.push(file);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
if (includedFiles.length === 0) {
|
|
326
|
-
throw new Error(`No files found in "${workspacePath}" to include in the build`);
|
|
327
|
-
}
|
|
328
|
-
for (let includedFile of includedFiles) {
|
|
329
|
-
// Mirror the workspace layout under outDir (no "src/" wrapper) so root config files
|
|
330
|
-
// land at the build root and config-relative paths keep working.
|
|
331
|
-
let targetPath = StringUtils.normalizePath(`${includedFile.replace(workspacePath, outDir)}`);
|
|
332
|
-
fse.copySync(includedFile, targetPath);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
try
|
|
336
|
-
{
|
|
337
|
-
await ShellUtils.exec(outDir, 'npm install', undefined, true);
|
|
338
|
-
await ShellUtils.exec(outDir, 'npm run build', undefined, true);
|
|
339
|
-
|
|
340
|
-
// Copy the app manifest to the dist folder
|
|
341
|
-
const newAppManifestPath = StringUtils.normalizePath(`${distDir}/app.manifest.json`);
|
|
342
|
-
fse.copyFileSync(appManifestPath, newAppManifestPath);
|
|
343
|
-
|
|
344
|
-
let bundlePath = StringUtils.normalizePath(`${distDir}`);
|
|
345
|
-
return bundlePath;
|
|
346
|
-
}
|
|
347
|
-
finally
|
|
348
|
-
{
|
|
349
|
-
// Delete the build folder
|
|
350
|
-
fse.removeSync(outDir);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
private static createIndexJsx(relativeOutFilePath: string, fileName: string): string {
|
|
355
|
-
return `
|
|
356
|
-
import React from 'react';
|
|
357
|
-
import ReactDOM from 'react-dom';
|
|
358
|
-
import ${fileName} from './${relativeOutFilePath}';
|
|
359
|
-
import { init } from 'codenotch-react';
|
|
360
|
-
|
|
361
|
-
fetch('/api/env')
|
|
362
|
-
.then(response => response.json())
|
|
363
|
-
.then(data => {
|
|
364
|
-
init(data);
|
|
365
|
-
ReactDOM.render(<${fileName} />, document.getElementById('root'));
|
|
366
|
-
})
|
|
367
|
-
.catch(error => {
|
|
368
|
-
console.error('Error fetching environment variables:', error);
|
|
369
|
-
init(null);
|
|
370
|
-
ReactDOM.render(<${fileName} />, document.getElementById('root'));
|
|
371
|
-
});
|
|
372
|
-
`.trim();
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* When served from the runtime env variables are not available, the variables are injected into the html file instead
|
|
377
|
-
*/
|
|
378
|
-
private static createIndexJsxDeployment(relativeOutFilePath: string, fileName: string): string {
|
|
379
|
-
return `
|
|
380
|
-
import React from 'react';
|
|
381
|
-
import ReactDOM from 'react-dom';
|
|
382
|
-
import ${fileName} from './${relativeOutFilePath}';
|
|
383
|
-
import { init } from 'codenotch-react';
|
|
384
|
-
|
|
385
|
-
// variables are injected into the html by the runtime, we can access them on the window object
|
|
386
|
-
const data = {
|
|
387
|
-
clusterUrl: tenant.clusterUrl,
|
|
388
|
-
serviceName: serviceName,
|
|
389
|
-
theme: 'dark',
|
|
390
|
-
language: languages[0] ?? 'en',
|
|
391
|
-
appManifest: appManifest,
|
|
392
|
-
tenantName: tenant.name,
|
|
393
|
-
appName: appName
|
|
394
|
-
};
|
|
395
|
-
init(data);
|
|
396
|
-
ReactDOM.render(<${fileName} />, document.getElementById('root'));
|
|
397
|
-
|
|
398
|
-
`.trim();
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
private static async fetchTenantName(clusterUrl?: string): Promise<string | undefined> {
|
|
403
|
-
let tenantName: string | undefined = undefined;
|
|
404
|
-
if (clusterUrl !== undefined) {
|
|
405
|
-
console.log('Fetching tenant name from cluster URL...');
|
|
406
|
-
tenantName = await this.getTenantName(clusterUrl);
|
|
407
|
-
if (tenantName) {
|
|
408
|
-
ConsoleUtils.check(`Tenant name "${tenantName}" fetched successfully\n`);
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
console.log(chalk.yellow(`Warning: Unable to fetch tenant name from cluster URL "${clusterUrl}".\n`));
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
console.log(chalk.yellow(`Warning: No cluster URL provided.\n`));
|
|
416
|
-
}
|
|
417
|
-
return tenantName;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
static async getCodenotchEnvVariables(workpace: IWorkspace, options: {
|
|
421
|
-
baseUrl?: string,
|
|
422
|
-
accessToken?: string,
|
|
423
|
-
appName?: string,
|
|
424
|
-
app?: ApplicationManifest,
|
|
425
|
-
tenantName?: string,
|
|
426
|
-
clusterUrl?: string
|
|
427
|
-
}) {
|
|
428
|
-
|
|
429
|
-
let result: any = {
|
|
430
|
-
clusterUrl: options.clusterUrl,
|
|
431
|
-
serviceName: workpace.manifest.serviceName,
|
|
432
|
-
theme: 'dark',
|
|
433
|
-
language: workpace.manifest?.languages?.[0] ?? 'en'
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
result.projectManifest = JSON.stringify(workpace.manifest);
|
|
437
|
-
|
|
438
|
-
if (options.app) {
|
|
439
|
-
result.appManifest = JSON.stringify(options.app);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
if (options.tenantName) {
|
|
443
|
-
result.tenantName = options.tenantName;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
let tenantName = options.tenantName;
|
|
448
|
-
|
|
449
|
-
if (tenantName) result.tenantName = tenantName;
|
|
450
|
-
if (options.appName) result.appName = options.appName;
|
|
451
|
-
if (options.accessToken) result.accessToken = options.accessToken;
|
|
452
|
-
if (options.baseUrl) result.baseUrl = options.baseUrl;
|
|
453
|
-
|
|
454
|
-
if (workpace) {
|
|
455
|
-
|
|
456
|
-
let allI18nValues = await I18nUtils.getAllI18nFiles(workpace.path);
|
|
457
|
-
for(let allI18nValue of allI18nValues){
|
|
458
|
-
for(let langValue of allI18nValue.values){
|
|
459
|
-
result[`i18n.${allI18nValue.key}.${langValue.lang}`] = JSON.stringify(langValue.value);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return result;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
static async getTenantName(cluster: string): Promise<string | undefined> {
|
|
470
|
-
try {
|
|
471
|
-
|
|
472
|
-
let obj: any = await (await fetch(`${cluster}/portal/tenant`)).json();
|
|
473
|
-
|
|
474
|
-
if (obj && obj.name && typeof obj.name === 'string') {
|
|
475
|
-
return obj.name;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return undefined;
|
|
479
|
-
}
|
|
480
|
-
catch (e) {
|
|
481
|
-
console.error("Error while fetching tenant name:", e);
|
|
482
|
-
return undefined;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
private static createTsConfig(include: string[] = ["src"]) {
|
|
487
|
-
let tsconfig = JSON.stringify({
|
|
488
|
-
"compilerOptions": {
|
|
489
|
-
"target": "ESNext",
|
|
490
|
-
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
491
|
-
"allowJs": true,
|
|
492
|
-
"skipLibCheck": true,
|
|
493
|
-
"esModuleInterop": true,
|
|
494
|
-
"allowSyntheticDefaultImports": true,
|
|
495
|
-
"strict": true,
|
|
496
|
-
"forceConsistentCasingInFileNames": true,
|
|
497
|
-
"module": "ESNext",
|
|
498
|
-
"moduleResolution": "Node",
|
|
499
|
-
"resolveJsonModule": true,
|
|
500
|
-
"isolatedModules": true,
|
|
501
|
-
"noEmit": true, // On demande à tsc de ne PAS générer de fichiers
|
|
502
|
-
"jsx": "react" // "react" correspond au mode classic pour React 16
|
|
503
|
-
},
|
|
504
|
-
"include": include
|
|
505
|
-
}, null, 4);
|
|
506
|
-
|
|
507
|
-
return tsconfig;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
private static createEmptyModule() {
|
|
511
|
-
let emptyModule = `
|
|
512
|
-
const deepMock = new Proxy(() => null, {
|
|
513
|
-
get: (target, prop) => {
|
|
514
|
-
console.warn('Empty module proxy accessed property: ', prop);
|
|
515
|
-
if (prop === '__esModule') return true;
|
|
516
|
-
return deepMock;
|
|
517
|
-
}
|
|
518
|
-
});
|
|
519
|
-
export default deepMock;
|
|
520
|
-
export class ComponentDescription {
|
|
521
|
-
constructor() {
|
|
522
|
-
this.tag = '';
|
|
523
|
-
this.props = {};
|
|
524
|
-
this.parentInheritedProps = {};
|
|
525
|
-
this.children = [];
|
|
526
|
-
this.storedData = {};
|
|
527
|
-
}
|
|
528
|
-
};
|
|
529
|
-
export const DeclarationState = {
|
|
530
|
-
IDLE : "idle",
|
|
531
|
-
LOADING : "loading",
|
|
532
|
-
SUCCESS : "success",
|
|
533
|
-
ERROR : "error"
|
|
534
|
-
};
|
|
535
|
-
export const DspVarType = {
|
|
536
|
-
STRING : "string",
|
|
537
|
-
BOOLEAN : "boolean",
|
|
538
|
-
NUMBER : "number",
|
|
539
|
-
INTEGER : "integer",
|
|
540
|
-
COLOR : "color",
|
|
541
|
-
THICKNESS : "thickness",
|
|
542
|
-
SIZE : "size",
|
|
543
|
-
BORDER : "border",
|
|
544
|
-
OBJECT : "object",
|
|
545
|
-
ARRAY : "array",
|
|
546
|
-
FUNCTION : "function",
|
|
547
|
-
ACTION : "action",
|
|
548
|
-
REACT_NODE : "reactNode",
|
|
549
|
-
RENDERER : "renderer"
|
|
550
|
-
};`.trim();
|
|
551
|
-
return emptyModule;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
private static createViteConfig(appName: string) {
|
|
555
|
-
let debugOptions = `
|
|
556
|
-
sourcemap: true,
|
|
557
|
-
terserOptions: {
|
|
558
|
-
mangle: false,
|
|
559
|
-
keep_fnames: true,
|
|
560
|
-
keep_classnames: true,
|
|
561
|
-
}`;
|
|
562
|
-
let viteConfig = `
|
|
563
|
-
import { defineConfig } from 'vite'
|
|
564
|
-
import react from '@vitejs/plugin-react'
|
|
565
|
-
import path from 'path';
|
|
566
|
-
export default defineConfig({
|
|
567
|
-
plugins: [
|
|
568
|
-
react({ jsxRuntime: 'classic' }),
|
|
569
|
-
],
|
|
570
|
-
base: './',
|
|
571
|
-
build: {
|
|
572
|
-
outDir: '../${appName}-dist',
|
|
573
|
-
emptyOutDir: true,
|
|
574
|
-
${debugOptions}
|
|
575
|
-
},
|
|
576
|
-
resolve: {
|
|
577
|
-
alias: [
|
|
578
|
-
{ find: 'crypto-browserify', replacement: './empty-module.js' },
|
|
579
|
-
{ find: /^@echino\\/codenotch\\.ui\\.monaco(\\/.*)?$/, replacement: path.resolve(__dirname, './empty-module.js') },
|
|
580
|
-
{ find: /^@echino\\/echino\\.ui\\.sdk(\\/.*)?$/, replacement: path.resolve(__dirname, './empty-module.js') },
|
|
581
|
-
],
|
|
582
|
-
},
|
|
583
|
-
})`.trim();
|
|
584
|
-
|
|
585
|
-
return viteConfig;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
private static createIndexHtml(appManifest: ApplicationManifest, appName: string): string {
|
|
589
|
-
let indexHtml = `<!DOCTYPE html>
|
|
590
|
-
<html lang="fr">
|
|
591
|
-
<head>
|
|
592
|
-
<meta charset="${appManifest.html?.charset ?? 'UTF-8'}" />
|
|
593
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
594
|
-
<title>${appManifest.html?.title ?? appName}</title>
|
|
595
|
-
<meta name="description" content="${appManifest.html?.description ?? ''}" />
|
|
596
|
-
<meta name="author" content="${appManifest.html?.author ?? ''}" />
|
|
597
|
-
<meta name="keywords" content="${appManifest.html?.keywords ?? ''}" />
|
|
598
|
-
<script src="https://kit.fontawesome.com/cd9ce0b05e.js" crossorigin="anonymous" data-auto-replace-svg="nest"></script>
|
|
599
|
-
</head>
|
|
600
|
-
<body>
|
|
601
|
-
<div id="root"></div>
|
|
602
|
-
<script type="module" src="/index.jsx"></script>
|
|
603
|
-
</body>
|
|
604
|
-
</html>`;
|
|
605
|
-
return indexHtml;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
private static createPkgJson(workspacePath: string, appName: string) {
|
|
609
|
-
let currentPkg = JSON.parse((fs.readFileSync(StringUtils.normalizePath(`${workspacePath}/package.json`), 'utf-8'))!);
|
|
610
|
-
ConsoleUtils.check(`package.json read successfully`);
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
let pgkJson: any = {
|
|
614
|
-
"name": appName,
|
|
615
|
-
"private": true,
|
|
616
|
-
"version": "1.0.0",
|
|
617
|
-
// Inherit the module system from the user's package.json (default: CommonJS).
|
|
618
|
-
// This lets user-provided tool configs (postcss.config.js, tailwind.config.js, ...)
|
|
619
|
-
// use whichever style they wrote. Our own build config is emitted as vite.config.mjs
|
|
620
|
-
// so it always loads as ESM regardless of this field.
|
|
621
|
-
"type": currentPkg.type ?? "commonjs",
|
|
622
|
-
"scripts": {
|
|
623
|
-
"dev": "vite",
|
|
624
|
-
"build": "tsc && vite build",
|
|
625
|
-
"preview": "vite preview"
|
|
626
|
-
},
|
|
627
|
-
"dependencies": currentPkg.dependencies ?? {},
|
|
628
|
-
"devDependencies": currentPkg.devDependencies ?? {}
|
|
629
|
-
};
|
|
630
|
-
let requiredDeps = ['react', 'react-dom'];
|
|
631
|
-
for (let requiredDep of requiredDeps) {
|
|
632
|
-
if (pgkJson.dependencies[requiredDep] === undefined) {
|
|
633
|
-
throw new Error(`Dependency ${requiredDep} is required to run the React preview. Please add it to your package.json dependencies and try again.`);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
if (pgkJson.devDependencies['vite'] === undefined) {
|
|
637
|
-
pgkJson.devDependencies['vite'] = "^7.3.1";
|
|
638
|
-
}
|
|
639
|
-
else {
|
|
640
|
-
ConsoleUtils.checkWarning(`Warning: Using custom Vite version: ${pgkJson.devDependencies['vite']}`);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
if (pgkJson.devDependencies['sass-embedded'] === undefined) {
|
|
644
|
-
pgkJson.devDependencies['sass-embedded'] = "^1.97.3";
|
|
645
|
-
}
|
|
646
|
-
else {
|
|
647
|
-
ConsoleUtils.checkWarning(`Warning: Using custom sass-embedded version: ${pgkJson.devDependencies['sass-embedded']}`);
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
return pgkJson;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
private static getFullManifestAt(folderPath: string): ProjectManifest {
|
|
655
|
-
let manifest = this.getManifestAt(folderPath);
|
|
656
|
-
let manifestCache = this.getManifestCacheAt(folderPath);
|
|
657
|
-
let result: ProjectManifest = {
|
|
658
|
-
projectName: manifest.projectName,
|
|
659
|
-
serviceName: manifest.serviceName,
|
|
660
|
-
version: manifest.version,
|
|
661
|
-
index: manifest.index,
|
|
662
|
-
dependencies: manifest.dependencies,
|
|
663
|
-
reactApplications: manifestCache.reactApplications,
|
|
664
|
-
packages: manifest.packages,
|
|
665
|
-
languages: manifest.languages,
|
|
666
|
-
roles: manifest.roles,
|
|
667
|
-
postInstallationProcesses: manifest.postInstallationProcesses,
|
|
668
|
-
apis: manifestCache.apis,
|
|
669
|
-
applications: manifestCache.applications,
|
|
670
|
-
emails: manifestCache.emails,
|
|
671
|
-
documentDataSources: manifestCache.documentDataSources,
|
|
672
|
-
expressComponents: manifestCache.expressComponents,
|
|
673
|
-
htmls: manifestCache.htmls,
|
|
674
|
-
pdfs: manifestCache.pdfs,
|
|
675
|
-
processes: manifestCache.processes,
|
|
676
|
-
scripts: manifestCache.scripts,
|
|
677
|
-
tableDataSources: manifestCache.tableDataSources,
|
|
678
|
-
};
|
|
679
|
-
return result;
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
private static getManifestAt(folderPath: string) {
|
|
683
|
-
let filePath = StringUtils.normalizePath(`${folderPath}/manifest.json`);
|
|
684
|
-
if (existsSync(filePath) === false) {
|
|
685
|
-
throw new Error(`Manifest file not found at path "${filePath}"`);
|
|
686
|
-
}
|
|
687
|
-
let json = readFileSync(filePath, 'utf-8');
|
|
688
|
-
return JSON.parse(json) as IScenarioProjectManifest;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
private static getManifestCacheAt(folderPath: string) {
|
|
692
|
-
let filePath = StringUtils.normalizePath(`${folderPath}/manifest.cache.json`);
|
|
693
|
-
if (existsSync(filePath) === false) {
|
|
694
|
-
throw new Error(`Manifest cache file not found at path "${filePath}"`);
|
|
695
|
-
}
|
|
696
|
-
let json = readFileSync(filePath, 'utf-8');
|
|
697
|
-
return JSON.parse(json) as IWorkspaceCache;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
static getAumlVariables(workpace: IWorkspace, tenantName: string | undefined, clusterUrl: string | undefined) {
|
|
702
|
-
let workspaceManifest = workpace?.manifest;
|
|
703
|
-
|
|
704
|
-
let result = {
|
|
705
|
-
serviceName: workspaceManifest?.serviceName ?? 'DEV',
|
|
706
|
-
tenant: {
|
|
707
|
-
displayName: tenantName,
|
|
708
|
-
name: tenantName,
|
|
709
|
-
clusterUrl: clusterUrl
|
|
710
|
-
},
|
|
711
|
-
languages: workspaceManifest?.languages ?? ['en'],
|
|
712
|
-
appManifest: workpace.manifest,
|
|
713
|
-
packageVersions: workspaceManifest?.packages ?? {}
|
|
714
|
-
};
|
|
715
|
-
return result;
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
static async getGlobalAumlVariableDefinitions(workpace: IWorkspace, tenantName: string | undefined, clusterUrl: string | undefined): Promise<string> {
|
|
719
|
-
let workspaceManifest = workpace?.manifest;
|
|
720
|
-
|
|
721
|
-
return `window.serviceName = "${workspaceManifest?.serviceName ?? 'DEV'}";
|
|
722
|
-
window.tenant = ${JSON.stringify({
|
|
723
|
-
displayName: tenantName,
|
|
724
|
-
name: tenantName,
|
|
725
|
-
clusterUrl: clusterUrl
|
|
726
|
-
}, null, 4)};
|
|
727
|
-
window.languages = ${JSON.stringify(workspaceManifest?.languages ?? ['en'], null, 4)};
|
|
728
|
-
window.user = ${JSON.stringify({
|
|
729
|
-
id: '',
|
|
730
|
-
roles: [],
|
|
731
|
-
groups: [],
|
|
732
|
-
email: '',
|
|
733
|
-
firstName: '',
|
|
734
|
-
lastName: ''
|
|
735
|
-
}, null, 4)};
|
|
736
|
-
window.appManifest = ${JSON.stringify(workpace.manifest, null, 4)};
|
|
737
|
-
window.packageVersions = ${JSON.stringify(workpace.manifest.packages ?? {}, null, 4)}`;
|
|
738
|
-
}
|
|
739
|
-
}
|