@uipath/packager-tool-webapp 1.204.0-preview.255 → 1.205.0-preview.256
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/action-schema/index.js +198 -85
- package/dist/constants.d.ts +13 -0
- package/dist/constants.js +1023 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +231 -118
- package/dist/models/webapp-manifest.d.ts +8 -0
- package/dist/strategies/coded-app-strategy.d.ts +35 -0
- package/dist/utils/bundle-path.d.ts +10 -0
- package/dist/webapp-tool-factory.d.ts +3 -2
- package/dist/webapp-tool.d.ts +7 -1
- package/package.json +5 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type { WebAppManifest } from "./models/webapp-manifest.js";
|
|
2
2
|
export { WEBAPP_MANIFEST_FILE_NAME, WebAppVariantType, } from "./models/webapp-manifest.js";
|
|
3
|
+
export { ensureWebAppProjectId } from "./utils/manifest-loader.js";
|
|
3
4
|
export { WebAppTool } from "./webapp-tool.js";
|
|
4
5
|
export { WebAppToolFactory } from "./webapp-tool-factory.js";
|
package/dist/index.js
CHANGED
|
@@ -5,15 +5,93 @@ var WebAppVariantType;
|
|
|
5
5
|
WebAppVariantType2["JS"] = "JS";
|
|
6
6
|
})(WebAppVariantType ||= {});
|
|
7
7
|
var WEBAPP_MANIFEST_FILE_NAME = "webAppManifest.json";
|
|
8
|
+
// src/utils/manifest-loader.ts
|
|
9
|
+
import { Path } from "@uipath/solutionpackager-tool-core";
|
|
10
|
+
async function loadWebAppManifest(fileSystem, projectPath) {
|
|
11
|
+
const manifestPath = Path.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
12
|
+
const exists = await fileSystem.exists(manifestPath);
|
|
13
|
+
if (!exists) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const content = await fileSystem.readFile(manifestPath);
|
|
17
|
+
if (!content) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const text = new TextDecoder().decode(content);
|
|
22
|
+
const manifest = JSON.parse(text);
|
|
23
|
+
return manifest;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
throw new Error(`Failed to parse ${WEBAPP_MANIFEST_FILE_NAME}: ${error instanceof Error ? error.message : String(error)}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function ensureWebAppProjectId(fileSystem, projectPath) {
|
|
29
|
+
const manifest = await loadWebAppManifest(fileSystem, projectPath);
|
|
30
|
+
if (manifest && typeof manifest.projectId === "string" && manifest.projectId.length > 0) {
|
|
31
|
+
return manifest.projectId;
|
|
32
|
+
}
|
|
33
|
+
const id = crypto.randomUUID();
|
|
34
|
+
if (manifest) {
|
|
35
|
+
const updated = { ...manifest, projectId: id };
|
|
36
|
+
const manifestPath = Path.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
37
|
+
await fileSystem.writeFile(manifestPath, `${JSON.stringify(updated, null, 2)}
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
return id;
|
|
41
|
+
}
|
|
8
42
|
// src/webapp-tool.ts
|
|
9
43
|
import {
|
|
10
|
-
Path as
|
|
44
|
+
Path as Path6,
|
|
11
45
|
ProjectTool,
|
|
12
46
|
TemporaryStorageService,
|
|
13
47
|
ToolErrorCodes,
|
|
14
48
|
ToolResult
|
|
15
49
|
} from "@uipath/solutionpackager-tool-core";
|
|
16
50
|
|
|
51
|
+
// src/utils/bundle-path.ts
|
|
52
|
+
import { Path as Path2 } from "@uipath/solutionpackager-tool-core";
|
|
53
|
+
function normalizeBundlePath(path) {
|
|
54
|
+
return path.replace(/\\/g, "/");
|
|
55
|
+
}
|
|
56
|
+
function isBundleRelativePath(path) {
|
|
57
|
+
const normalized = normalizeBundlePath(path);
|
|
58
|
+
const segments = normalized.split("/");
|
|
59
|
+
return !normalized.startsWith("/") && !/^[a-zA-Z]:/.test(normalized) && !segments.includes("..") && segments.some((segment) => segment !== "" && segment !== ".");
|
|
60
|
+
}
|
|
61
|
+
async function isCanonicalBundleChild(fileSystem, projectPath, bundlePath) {
|
|
62
|
+
const project = normalizeBundlePath(await fileSystem.realpath(projectPath)).replace(/\/+$/, "") || "/";
|
|
63
|
+
let bundle = project;
|
|
64
|
+
for (const segment of normalizeBundlePath(bundlePath).split("/")) {
|
|
65
|
+
if (!segment || segment === ".")
|
|
66
|
+
continue;
|
|
67
|
+
bundle = normalizeBundlePath(await fileSystem.realpath(Path2.join(bundle, segment))).replace(/\/+$/, "") || "/";
|
|
68
|
+
}
|
|
69
|
+
return bundle !== project && bundle.startsWith(project === "/" ? "/" : `${project}/`);
|
|
70
|
+
}
|
|
71
|
+
function isHtmlEntryPointPath(path) {
|
|
72
|
+
return typeof path === "string" && isBundleRelativePath(path) && /\.html?$/i.test(path);
|
|
73
|
+
}
|
|
74
|
+
async function resolveHtmlEntryPoint(fileSystem, folder, declaredPath) {
|
|
75
|
+
if (!isHtmlEntryPointPath(declaredPath))
|
|
76
|
+
return null;
|
|
77
|
+
const segments = normalizeBundlePath(declaredPath).split("/").filter((part) => part !== "" && part !== ".");
|
|
78
|
+
if (!(await fileSystem.stat(Path2.join(folder, ...segments)))?.isFile())
|
|
79
|
+
return null;
|
|
80
|
+
const actual = [];
|
|
81
|
+
for (const segment of segments) {
|
|
82
|
+
const entries = await fileSystem.readdir(Path2.join(folder, ...actual));
|
|
83
|
+
if (entries.includes(segment)) {
|
|
84
|
+
actual.push(segment);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const matches = entries.filter((entry) => entry.toLowerCase() === segment.toLowerCase());
|
|
88
|
+
if (matches.length !== 1)
|
|
89
|
+
return null;
|
|
90
|
+
actual.push(matches[0]);
|
|
91
|
+
}
|
|
92
|
+
return actual.join("/");
|
|
93
|
+
}
|
|
94
|
+
|
|
17
95
|
// src/constants.ts
|
|
18
96
|
var PROJECT_JSON_FILE = "project.json";
|
|
19
97
|
var DEFAULT_BUNDLE_PATH = "source/dist";
|
|
@@ -22,12 +100,23 @@ var CONTENT_APP_FOLDER_NAME = "app";
|
|
|
22
100
|
var TARGET_RUNTIME = "Coded";
|
|
23
101
|
var TARGET_JS_RUNTIME = "JS";
|
|
24
102
|
var DEFAULT_ENTRY_POINT_TYPE = "api";
|
|
103
|
+
var HTML_ENTRY_POINT_CANDIDATES = [
|
|
104
|
+
"index.html",
|
|
105
|
+
"main.html",
|
|
106
|
+
"app.html"
|
|
107
|
+
];
|
|
25
108
|
var ERROR_MESSAGES = {
|
|
26
109
|
MANIFEST_NOT_FOUND: (file) => `WebApp manifest not found: ${file}. This file is required for WebApp projects.`,
|
|
27
110
|
PROJECT_JSON_FOUND: "project.json found in WebApp project. The WebApp tool only supports Coded web apps without project.json.",
|
|
28
111
|
MANIFEST_LOAD_FAILED: (file) => `Failed to load or parse ${file}`,
|
|
29
112
|
BUNDLE_NOT_FOUND: (path) => `Compiled bundle not found at ${path}. Ensure the project is built before packing.`,
|
|
30
113
|
BUNDLE_NOT_DIRECTORY: (path) => `Bundle path ${path} exists but is not a directory.`,
|
|
114
|
+
BUNDLE_OUTSIDE_PROJECT: (path) => `Bundle path ${path} resolves to the project root or outside the project. Use a child build output folder inside the project.`,
|
|
115
|
+
BUNDLE_NO_ENTRY_POINT: (path) => `Bundle at ${path} has no HTML entry point (${HTML_ENTRY_POINT_CANDIDATES.join(", ")}). Build the app before packing, or point config.bundlePath in webAppManifest.json at its build output.`,
|
|
116
|
+
MAIN_FILE_INVALID_TYPE: "Invalid webAppManifest.json: config.mainFile must be a string naming an HTML file, or be omitted.",
|
|
117
|
+
MAIN_FILE_NOT_IN_BUNDLE: (path, mainFile) => `${WEBAPP_MANIFEST_FILE_NAME} asks for "${mainFile}" as the app's main file, but the bundle at ${path} does not hold it. Name an HTML file inside the bundle in config.mainFile, or remove it to use the first of ${HTML_ENTRY_POINT_CANDIDATES.join(", ")} the bundle holds.`,
|
|
118
|
+
MAIN_FILE_LOST: (path, mainFile) => `Bundle at ${path} held "${mainFile}" when the pack started, but the copy taken for the package has not. Something changed the folder mid-pack — usually a build or watch process. Stop it and pack again.`,
|
|
119
|
+
BUNDLE_ENTRY_POINT_LOST: (path) => `Bundle at ${path} had an HTML entry point (${HTML_ENTRY_POINT_CANDIDATES.join(", ")}) when the pack started, but the copy taken for the package has none. Something changed the folder mid-pack — usually a build or watch process. Stop it and pack again.`,
|
|
31
120
|
APP_FOLDER_NOT_FOUND: (path) => `.app folder not found at ${path}. Ensure the project contains a .app folder.`,
|
|
32
121
|
APP_FOLDER_NOT_DIRECTORY: (path) => `.app path ${path} exists but is not a directory.`,
|
|
33
122
|
BUILD_NOT_SUPPORTED: "Build execution (isCompiled=false) is not yet supported. Please build the project manually and set isCompiled=true.",
|
|
@@ -43,19 +132,19 @@ var ERROR_MESSAGES = {
|
|
|
43
132
|
import {
|
|
44
133
|
NugetConstants,
|
|
45
134
|
NugetPackager,
|
|
46
|
-
Path as
|
|
135
|
+
Path as Path4,
|
|
47
136
|
ProjectTypes,
|
|
48
137
|
TargetFramework
|
|
49
138
|
} from "@uipath/solutionpackager-tool-core";
|
|
50
139
|
|
|
51
140
|
// src/utils/fs-helpers.ts
|
|
52
|
-
import { Path } from "@uipath/solutionpackager-tool-core";
|
|
141
|
+
import { Path as Path3 } from "@uipath/solutionpackager-tool-core";
|
|
53
142
|
async function copyDirectoryAsync(fileSystem, sourcePath, destinationPath) {
|
|
54
143
|
await fileSystem.mkdir(destinationPath);
|
|
55
144
|
const entries = await fileSystem.readdir(sourcePath);
|
|
56
145
|
for (const entry of entries) {
|
|
57
|
-
const sourceEntry =
|
|
58
|
-
const destEntry =
|
|
146
|
+
const sourceEntry = Path3.join(sourcePath, entry);
|
|
147
|
+
const destEntry = Path3.join(destinationPath, entry);
|
|
59
148
|
const stat = await fileSystem.stat(sourceEntry);
|
|
60
149
|
if (stat?.isDirectory()) {
|
|
61
150
|
await copyDirectoryAsync(fileSystem, sourceEntry, destEntry);
|
|
@@ -68,41 +157,6 @@ async function copyDirectoryAsync(fileSystem, sourcePath, destinationPath) {
|
|
|
68
157
|
}
|
|
69
158
|
}
|
|
70
159
|
|
|
71
|
-
// src/utils/manifest-loader.ts
|
|
72
|
-
import { Path as Path2 } from "@uipath/solutionpackager-tool-core";
|
|
73
|
-
async function loadWebAppManifest(fileSystem, projectPath) {
|
|
74
|
-
const manifestPath = Path2.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
75
|
-
const exists = await fileSystem.exists(manifestPath);
|
|
76
|
-
if (!exists) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
const content = await fileSystem.readFile(manifestPath);
|
|
80
|
-
if (!content) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
try {
|
|
84
|
-
const text = new TextDecoder().decode(content);
|
|
85
|
-
const manifest = JSON.parse(text);
|
|
86
|
-
return manifest;
|
|
87
|
-
} catch (error) {
|
|
88
|
-
throw new Error(`Failed to parse ${WEBAPP_MANIFEST_FILE_NAME}: ${error instanceof Error ? error.message : String(error)}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
async function ensureWebAppProjectId(fileSystem, projectPath) {
|
|
92
|
-
const manifest = await loadWebAppManifest(fileSystem, projectPath);
|
|
93
|
-
if (manifest && typeof manifest.projectId === "string" && manifest.projectId.length > 0) {
|
|
94
|
-
return manifest.projectId;
|
|
95
|
-
}
|
|
96
|
-
const id = crypto.randomUUID();
|
|
97
|
-
if (manifest) {
|
|
98
|
-
const updated = { ...manifest, projectId: id };
|
|
99
|
-
const manifestPath = Path2.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
100
|
-
await fileSystem.writeFile(manifestPath, `${JSON.stringify(updated, null, 2)}
|
|
101
|
-
`);
|
|
102
|
-
}
|
|
103
|
-
return id;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
160
|
// src/strategies/coded-app-strategy.ts
|
|
107
161
|
class CodedAppStrategy {
|
|
108
162
|
fileSystem;
|
|
@@ -118,10 +172,9 @@ class CodedAppStrategy {
|
|
|
118
172
|
}
|
|
119
173
|
const isCompiled = typed.config?.isCompiled ?? true;
|
|
120
174
|
if (isCompiled) {
|
|
121
|
-
const fullBundlePath =
|
|
122
|
-
const
|
|
123
|
-
if (
|
|
124
|
-
const message = ERROR_MESSAGES.BUNDLE_NOT_FOUND(fullBundlePath);
|
|
175
|
+
const fullBundlePath = Path4.join(projectPath, bundlePath);
|
|
176
|
+
const message = await this.describeBundleProblemAsync(fullBundlePath, typed.config?.mainFile);
|
|
177
|
+
if (message) {
|
|
125
178
|
const warnable = logger;
|
|
126
179
|
if (warnable?.warn) {
|
|
127
180
|
warnable.warn(message);
|
|
@@ -139,7 +192,11 @@ class CodedAppStrategy {
|
|
|
139
192
|
bundlePath = DEFAULT_BUNDLE_PATH;
|
|
140
193
|
}
|
|
141
194
|
const isCompiled = manifest.config?.isCompiled ?? true;
|
|
142
|
-
const
|
|
195
|
+
const declaredMainFile = manifest.config?.mainFile;
|
|
196
|
+
const fullBundlePath = Path4.join(projectPath, bundlePath);
|
|
197
|
+
if (isBundleRelativePath(bundlePath) && !await isCanonicalBundleChild(this.fileSystem, projectPath, bundlePath)) {
|
|
198
|
+
throw new Error(ERROR_MESSAGES.BUNDLE_OUTSIDE_PROJECT(bundlePath));
|
|
199
|
+
}
|
|
143
200
|
if (isCompiled) {
|
|
144
201
|
logger?.progress("Validating compiled bundle...");
|
|
145
202
|
const bundleExists = await this.fileSystem.exists(fullBundlePath);
|
|
@@ -150,21 +207,25 @@ class CodedAppStrategy {
|
|
|
150
207
|
if (!bundleStat?.isDirectory()) {
|
|
151
208
|
throw new Error(ERROR_MESSAGES.BUNDLE_NOT_DIRECTORY(fullBundlePath));
|
|
152
209
|
}
|
|
210
|
+
const problem = await this.describeBundleEntryProblemAsync(fullBundlePath, declaredMainFile);
|
|
211
|
+
if (problem) {
|
|
212
|
+
throw new Error(problem);
|
|
213
|
+
}
|
|
153
214
|
} else {
|
|
154
215
|
logger?.info("Build mode (isCompiled=false) is not yet implemented in v1.");
|
|
155
216
|
throw new Error(ERROR_MESSAGES.BUILD_NOT_SUPPORTED);
|
|
156
217
|
}
|
|
157
|
-
const localBuildFolder =
|
|
158
|
-
const contentFolder =
|
|
159
|
-
await this.fileSystem.mkdir(contentFolder);
|
|
218
|
+
const localBuildFolder = Path4.join(outputPath, `${NugetConstants.OutputFolderName}-${crypto.randomUUID()}`);
|
|
219
|
+
const contentFolder = Path4.join(localBuildFolder, NugetConstants.ContentFolderName);
|
|
160
220
|
try {
|
|
221
|
+
await this.fileSystem.mkdir(contentFolder);
|
|
161
222
|
logger?.progress("Copying bundle to content folder...");
|
|
162
223
|
await copyDirectoryAsync(this.fileSystem, fullBundlePath, contentFolder);
|
|
163
224
|
logger?.progress("Preparing metadata files...");
|
|
164
|
-
await this.prepareMetadataFiles(localBuildFolder, contentFolder, packageInfo, manifest, projectPath);
|
|
225
|
+
await this.prepareMetadataFiles(localBuildFolder, contentFolder, packageInfo, manifest, projectPath, fullBundlePath);
|
|
165
226
|
logger?.progress("Creating NuGet package...");
|
|
166
227
|
const nupkgFileName = `${packageInfo.id}.${packageInfo.version}.nupkg`;
|
|
167
|
-
const nupkgPath =
|
|
228
|
+
const nupkgPath = Path4.join(outputPath, nupkgFileName);
|
|
168
229
|
const packager = new NugetPackager(this.fileSystem);
|
|
169
230
|
const result = await packager.packAsync(localBuildFolder, packageInfo, nupkgPath);
|
|
170
231
|
logger?.info(`Package created successfully: ${result.outputPath}`);
|
|
@@ -177,21 +238,13 @@ class CodedAppStrategy {
|
|
|
177
238
|
}
|
|
178
239
|
}
|
|
179
240
|
}
|
|
180
|
-
async prepareMetadataFiles(_localBuildFolder, contentFolder, _packageInfo,
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const possibleEntries = ["index.html", "main.html", "app.html"];
|
|
186
|
-
for (const entry of possibleEntries) {
|
|
187
|
-
const entryPath = Path3.join(contentFolder, entry);
|
|
188
|
-
if (await this.fileSystem.exists(entryPath)) {
|
|
189
|
-
mainFile = entry;
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
241
|
+
async prepareMetadataFiles(_localBuildFolder, contentFolder, _packageInfo, manifest, projectPath, sourceBundlePath) {
|
|
242
|
+
const declaredMainFile = manifest.config?.mainFile;
|
|
243
|
+
const mainFile = await this.resolveMainFileAsync(contentFolder, declaredMainFile);
|
|
244
|
+
if (!mainFile) {
|
|
245
|
+
throw new Error(declaredMainFile ? ERROR_MESSAGES.MAIN_FILE_LOST(sourceBundlePath, declaredMainFile) : ERROR_MESSAGES.BUNDLE_ENTRY_POINT_LOST(sourceBundlePath));
|
|
193
246
|
}
|
|
194
|
-
const operatePath =
|
|
247
|
+
const operatePath = Path4.join(contentFolder, NugetConstants.OperateFileName);
|
|
195
248
|
const operateModel = {
|
|
196
249
|
projectId: await ensureWebAppProjectId(this.fileSystem, projectPath),
|
|
197
250
|
main: mainFile,
|
|
@@ -205,17 +258,13 @@ class CodedAppStrategy {
|
|
|
205
258
|
};
|
|
206
259
|
const operateJson = JSON.stringify(operateModel, null, 2);
|
|
207
260
|
await this.fileSystem.writeFile(operatePath, operateJson);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
const uipathJsonSourcePath = Path3.join(projectPath, "uipath.json");
|
|
218
|
-
const uipathJsonDestPath = Path3.join(contentFolder, "uipath.json");
|
|
261
|
+
await this.fileSystem.writeFile(Path4.join(contentFolder, WEBAPP_MANIFEST_FILE_NAME), JSON.stringify({
|
|
262
|
+
...manifest,
|
|
263
|
+
config: { ...manifest.config, mainFile },
|
|
264
|
+
projectId: operateModel.projectId
|
|
265
|
+
}, null, 2));
|
|
266
|
+
const uipathJsonSourcePath = Path4.join(projectPath, "uipath.json");
|
|
267
|
+
const uipathJsonDestPath = Path4.join(contentFolder, "uipath.json");
|
|
219
268
|
const uipathJsonExists = await this.fileSystem.exists(uipathJsonSourcePath);
|
|
220
269
|
if (uipathJsonExists) {
|
|
221
270
|
const uipathJsonContent = await this.fileSystem.readFile(uipathJsonSourcePath, "utf-8");
|
|
@@ -223,8 +272,8 @@ class CodedAppStrategy {
|
|
|
223
272
|
await this.fileSystem.writeFile(uipathJsonDestPath, uipathJsonContent);
|
|
224
273
|
}
|
|
225
274
|
}
|
|
226
|
-
const actionSchemaSourcePath =
|
|
227
|
-
const actionSchemaDestPath =
|
|
275
|
+
const actionSchemaSourcePath = Path4.join(projectPath, "action-schema.json");
|
|
276
|
+
const actionSchemaDestPath = Path4.join(contentFolder, "action-schema.json");
|
|
228
277
|
const actionSchemaExists = await this.fileSystem.exists(actionSchemaSourcePath);
|
|
229
278
|
if (actionSchemaExists) {
|
|
230
279
|
const actionSchemaContent = await this.fileSystem.readFile(actionSchemaSourcePath, "utf-8");
|
|
@@ -232,7 +281,7 @@ class CodedAppStrategy {
|
|
|
232
281
|
await this.fileSystem.writeFile(actionSchemaDestPath, actionSchemaContent);
|
|
233
282
|
}
|
|
234
283
|
}
|
|
235
|
-
const bindingsPath =
|
|
284
|
+
const bindingsPath = Path4.join(contentFolder, "bindings.json");
|
|
236
285
|
const bindingsExists = await this.fileSystem.exists(bindingsPath);
|
|
237
286
|
if (!bindingsExists) {
|
|
238
287
|
const bindingsJson = JSON.stringify({
|
|
@@ -241,12 +290,12 @@ class CodedAppStrategy {
|
|
|
241
290
|
}, null, 2);
|
|
242
291
|
await this.fileSystem.writeFile(bindingsPath, bindingsJson);
|
|
243
292
|
}
|
|
244
|
-
const bindingsV2Path =
|
|
293
|
+
const bindingsV2Path = Path4.join(contentFolder, "bindings_v2.json");
|
|
245
294
|
const bindingsCandidatePaths = [
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
295
|
+
Path4.join(projectPath, "source", "bindings_v2.json"),
|
|
296
|
+
Path4.join(projectPath, "source", "bindings.json"),
|
|
297
|
+
Path4.join(projectPath, "bindings.json"),
|
|
298
|
+
Path4.join(projectPath, "bindings_v2.json")
|
|
250
299
|
];
|
|
251
300
|
let bindingsV2Json = null;
|
|
252
301
|
for (const candidate of bindingsCandidatePaths) {
|
|
@@ -266,14 +315,14 @@ class CodedAppStrategy {
|
|
|
266
315
|
}, null, 2);
|
|
267
316
|
}
|
|
268
317
|
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
269
|
-
const entryPointsPath =
|
|
270
|
-
const projectEntryPointsPath =
|
|
318
|
+
const entryPointsPath = Path4.join(contentFolder, "entry-points.json");
|
|
319
|
+
const projectEntryPointsPath = Path4.join(projectPath, "entry-points.json");
|
|
271
320
|
let entryPointsContent;
|
|
272
321
|
const projectEntryPointsExists = await this.fileSystem.exists(projectEntryPointsPath);
|
|
273
322
|
if (projectEntryPointsExists) {
|
|
274
323
|
const entryPointsData = await this.fileSystem.readFile(projectEntryPointsPath, "utf-8");
|
|
275
324
|
if (entryPointsData) {
|
|
276
|
-
entryPointsContent = entryPointsData;
|
|
325
|
+
entryPointsContent = this.alignEntryPoint(entryPointsData, mainFile);
|
|
277
326
|
} else {
|
|
278
327
|
entryPointsContent = this.createDefaultEntryPoints(mainFile);
|
|
279
328
|
}
|
|
@@ -281,18 +330,68 @@ class CodedAppStrategy {
|
|
|
281
330
|
entryPointsContent = this.createDefaultEntryPoints(mainFile);
|
|
282
331
|
}
|
|
283
332
|
await this.fileSystem.writeFile(entryPointsPath, entryPointsContent);
|
|
284
|
-
const packageDescriptorPath =
|
|
333
|
+
const packageDescriptorPath = Path4.join(contentFolder, NugetConstants.PackageDescriptorFileName);
|
|
285
334
|
const packageDescriptor = {
|
|
286
335
|
$schema: "https://cloud.uipath.com/draft/2024-12/package-descriptor",
|
|
287
336
|
files: {
|
|
288
|
-
[NugetConstants.OperateFileName]:
|
|
289
|
-
"entry-points.json":
|
|
290
|
-
"bindings.json":
|
|
337
|
+
[NugetConstants.OperateFileName]: Path4.join(NugetConstants.ContentFolderName, NugetConstants.OperateFileName),
|
|
338
|
+
"entry-points.json": Path4.join(NugetConstants.ContentFolderName, "entry-points.json"),
|
|
339
|
+
"bindings.json": Path4.join(NugetConstants.ContentFolderName, "bindings_v2.json")
|
|
291
340
|
}
|
|
292
341
|
};
|
|
293
342
|
const packageDescriptorJson = JSON.stringify(packageDescriptor, null, 2);
|
|
294
343
|
await this.fileSystem.writeFile(packageDescriptorPath, packageDescriptorJson);
|
|
295
344
|
}
|
|
345
|
+
async describeBundleProblemAsync(fullBundlePath, declaredMainFile) {
|
|
346
|
+
const bundleStat = await this.fileSystem.stat(fullBundlePath);
|
|
347
|
+
if (!bundleStat) {
|
|
348
|
+
return ERROR_MESSAGES.BUNDLE_NOT_FOUND(fullBundlePath);
|
|
349
|
+
}
|
|
350
|
+
if (!bundleStat.isDirectory()) {
|
|
351
|
+
return ERROR_MESSAGES.BUNDLE_NOT_DIRECTORY(fullBundlePath);
|
|
352
|
+
}
|
|
353
|
+
return this.describeBundleEntryProblemAsync(fullBundlePath, declaredMainFile);
|
|
354
|
+
}
|
|
355
|
+
async describeBundleEntryProblemAsync(fullBundlePath, declaredMainFile) {
|
|
356
|
+
if (declaredMainFile !== undefined && typeof declaredMainFile !== "string") {
|
|
357
|
+
return ERROR_MESSAGES.MAIN_FILE_INVALID_TYPE;
|
|
358
|
+
}
|
|
359
|
+
if (await this.resolveMainFileAsync(fullBundlePath, declaredMainFile)) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
return declaredMainFile !== undefined ? ERROR_MESSAGES.MAIN_FILE_NOT_IN_BUNDLE(fullBundlePath, declaredMainFile) : ERROR_MESSAGES.BUNDLE_NO_ENTRY_POINT(fullBundlePath);
|
|
363
|
+
}
|
|
364
|
+
async resolveMainFileAsync(folder, declaredMainFile) {
|
|
365
|
+
if (declaredMainFile === undefined) {
|
|
366
|
+
return this.findEntryPointAsync(folder);
|
|
367
|
+
}
|
|
368
|
+
return resolveHtmlEntryPoint(this.fileSystem, folder, declaredMainFile);
|
|
369
|
+
}
|
|
370
|
+
async findEntryPointAsync(folder) {
|
|
371
|
+
for (const candidate of HTML_ENTRY_POINT_CANDIDATES) {
|
|
372
|
+
const resolved = await resolveHtmlEntryPoint(this.fileSystem, folder, candidate);
|
|
373
|
+
if (resolved !== null)
|
|
374
|
+
return resolved;
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
alignEntryPoint(content, mainFile) {
|
|
379
|
+
const document = JSON.parse(content);
|
|
380
|
+
if (typeof document !== "object" || document === null || !("entryPoints" in document) || !Array.isArray(document.entryPoints)) {
|
|
381
|
+
throw new Error("Invalid entry-points.json: expected an entryPoints array.");
|
|
382
|
+
}
|
|
383
|
+
const primary = document.entryPoints[0];
|
|
384
|
+
if (typeof primary !== "object" || primary === null || Array.isArray(primary)) {
|
|
385
|
+
throw new Error("Invalid entry-points.json: expected a primary entry object.");
|
|
386
|
+
}
|
|
387
|
+
return JSON.stringify({
|
|
388
|
+
...document,
|
|
389
|
+
entryPoints: [
|
|
390
|
+
{ ...primary, filePath: mainFile },
|
|
391
|
+
...document.entryPoints.slice(1)
|
|
392
|
+
]
|
|
393
|
+
}, null, 2);
|
|
394
|
+
}
|
|
296
395
|
createDefaultEntryPoints(mainFile) {
|
|
297
396
|
const uniqueId = this.generateUniqueId();
|
|
298
397
|
const entryPoints = {
|
|
@@ -339,7 +438,7 @@ class CodedAppStrategy {
|
|
|
339
438
|
import {
|
|
340
439
|
NugetConstants as NugetConstants2,
|
|
341
440
|
NugetPackager as NugetPackager2,
|
|
342
|
-
Path as
|
|
441
|
+
Path as Path5,
|
|
343
442
|
ProjectTypes as ProjectTypes2,
|
|
344
443
|
TargetFramework as TargetFramework2
|
|
345
444
|
} from "@uipath/solutionpackager-tool-core";
|
|
@@ -350,7 +449,7 @@ class JsAppsStrategy {
|
|
|
350
449
|
}
|
|
351
450
|
async validateAsync(args) {
|
|
352
451
|
const { projectPath, logger } = args;
|
|
353
|
-
const appFolder =
|
|
452
|
+
const appFolder = Path5.join(projectPath, APP_FOLDER_NAME);
|
|
354
453
|
const exists = await this.fileSystem.exists(appFolder);
|
|
355
454
|
if (!exists) {
|
|
356
455
|
const message = ERROR_MESSAGES.APP_FOLDER_NOT_FOUND(appFolder);
|
|
@@ -374,7 +473,7 @@ class JsAppsStrategy {
|
|
|
374
473
|
async packageAsync(args) {
|
|
375
474
|
const { projectPath, manifest, outputPath, packageInfo, logger } = args;
|
|
376
475
|
logger?.info(`Packaging JS variant: ${packageInfo.id}@${packageInfo.version}`);
|
|
377
|
-
const appFolder =
|
|
476
|
+
const appFolder = Path5.join(projectPath, APP_FOLDER_NAME);
|
|
378
477
|
logger?.progress("Validating .app folder...");
|
|
379
478
|
const appFolderExists = await this.fileSystem.exists(appFolder);
|
|
380
479
|
if (!appFolderExists) {
|
|
@@ -384,9 +483,9 @@ class JsAppsStrategy {
|
|
|
384
483
|
if (!appFolderStat?.isDirectory()) {
|
|
385
484
|
throw new Error(ERROR_MESSAGES.APP_FOLDER_NOT_DIRECTORY(appFolder));
|
|
386
485
|
}
|
|
387
|
-
const localBuildFolder =
|
|
388
|
-
const contentFolder =
|
|
389
|
-
const contentAppFolder =
|
|
486
|
+
const localBuildFolder = Path5.join(outputPath, NugetConstants2.OutputFolderName);
|
|
487
|
+
const contentFolder = Path5.join(localBuildFolder, NugetConstants2.ContentFolderName);
|
|
488
|
+
const contentAppFolder = Path5.join(contentFolder, CONTENT_APP_FOLDER_NAME);
|
|
390
489
|
await this.fileSystem.mkdir(contentFolder);
|
|
391
490
|
try {
|
|
392
491
|
logger?.progress("Copying .app folder into content/app...");
|
|
@@ -395,7 +494,7 @@ class JsAppsStrategy {
|
|
|
395
494
|
await this.prepareMetadataFiles(contentFolder, contentAppFolder, packageInfo, manifest, projectPath);
|
|
396
495
|
logger?.progress("Creating NuGet package...");
|
|
397
496
|
const nupkgFileName = `${packageInfo.id}.${packageInfo.version}.nupkg`;
|
|
398
|
-
const nupkgPath =
|
|
497
|
+
const nupkgPath = Path5.join(outputPath, nupkgFileName);
|
|
399
498
|
const packager = new NugetPackager2(this.fileSystem);
|
|
400
499
|
const result = await packager.packAsync(localBuildFolder, packageInfo, nupkgPath);
|
|
401
500
|
logger?.info(`Package created successfully: ${result.outputPath}`);
|
|
@@ -411,7 +510,7 @@ class JsAppsStrategy {
|
|
|
411
510
|
async prepareMetadataFiles(contentFolder, _contentAppFolder, _packageInfo, _manifest, projectPath) {
|
|
412
511
|
const mainFile = "index.html";
|
|
413
512
|
const mainRelativeToContent = `${CONTENT_APP_FOLDER_NAME}/${mainFile}`;
|
|
414
|
-
const operatePath =
|
|
513
|
+
const operatePath = Path5.join(contentFolder, NugetConstants2.OperateFileName);
|
|
415
514
|
const operateModel = {
|
|
416
515
|
projectId: await ensureWebAppProjectId(this.fileSystem, projectPath),
|
|
417
516
|
main: mainRelativeToContent,
|
|
@@ -425,8 +524,8 @@ class JsAppsStrategy {
|
|
|
425
524
|
};
|
|
426
525
|
const operateJson = JSON.stringify(operateModel, null, 2);
|
|
427
526
|
await this.fileSystem.writeFile(operatePath, operateJson);
|
|
428
|
-
const manifestSourcePath =
|
|
429
|
-
const manifestDestPath =
|
|
527
|
+
const manifestSourcePath = Path5.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
528
|
+
const manifestDestPath = Path5.join(contentFolder, WEBAPP_MANIFEST_FILE_NAME);
|
|
430
529
|
const manifestExists = await this.fileSystem.exists(manifestSourcePath);
|
|
431
530
|
if (manifestExists) {
|
|
432
531
|
const manifestContent = await this.fileSystem.readFile(manifestSourcePath);
|
|
@@ -434,8 +533,8 @@ class JsAppsStrategy {
|
|
|
434
533
|
await this.fileSystem.writeFile(manifestDestPath, manifestContent);
|
|
435
534
|
}
|
|
436
535
|
}
|
|
437
|
-
const uipathJsonSourcePath =
|
|
438
|
-
const uipathJsonDestPath =
|
|
536
|
+
const uipathJsonSourcePath = Path5.join(projectPath, "uipath.json");
|
|
537
|
+
const uipathJsonDestPath = Path5.join(contentFolder, "uipath.json");
|
|
439
538
|
const uipathJsonExists = await this.fileSystem.exists(uipathJsonSourcePath);
|
|
440
539
|
if (uipathJsonExists) {
|
|
441
540
|
const uipathJsonContent = await this.fileSystem.readFile(uipathJsonSourcePath);
|
|
@@ -443,20 +542,20 @@ class JsAppsStrategy {
|
|
|
443
542
|
await this.fileSystem.writeFile(uipathJsonDestPath, uipathJsonContent);
|
|
444
543
|
}
|
|
445
544
|
}
|
|
446
|
-
const bindingsPath =
|
|
545
|
+
const bindingsPath = Path5.join(contentFolder, "bindings.json");
|
|
447
546
|
const bindingsExists = await this.fileSystem.exists(bindingsPath);
|
|
448
547
|
if (!bindingsExists) {
|
|
449
548
|
const bindingsJson = JSON.stringify({ version: "1.0", resources: [] }, null, 2);
|
|
450
549
|
await this.fileSystem.writeFile(bindingsPath, bindingsJson);
|
|
451
550
|
}
|
|
452
|
-
const bindingsV2Path =
|
|
551
|
+
const bindingsV2Path = Path5.join(contentFolder, "bindings_v2.json");
|
|
453
552
|
const bindingsV2Exists = await this.fileSystem.exists(bindingsV2Path);
|
|
454
553
|
if (!bindingsV2Exists) {
|
|
455
554
|
const bindingsV2Json = JSON.stringify({ version: "2.0", resources: [] }, null, 2);
|
|
456
555
|
await this.fileSystem.writeFile(bindingsV2Path, bindingsV2Json);
|
|
457
556
|
}
|
|
458
|
-
const entryPointsPath =
|
|
459
|
-
const projectEntryPointsPath =
|
|
557
|
+
const entryPointsPath = Path5.join(contentFolder, "entry-points.json");
|
|
558
|
+
const projectEntryPointsPath = Path5.join(projectPath, "entry-points.json");
|
|
460
559
|
let entryPointsContent;
|
|
461
560
|
const projectEntryPointsExists = await this.fileSystem.exists(projectEntryPointsPath);
|
|
462
561
|
if (projectEntryPointsExists) {
|
|
@@ -470,12 +569,12 @@ class JsAppsStrategy {
|
|
|
470
569
|
entryPointsContent = this.createDefaultEntryPoints(mainRelativeToContent);
|
|
471
570
|
}
|
|
472
571
|
await this.fileSystem.writeFile(entryPointsPath, entryPointsContent);
|
|
473
|
-
const packageDescriptorPath =
|
|
572
|
+
const packageDescriptorPath = Path5.join(contentFolder, NugetConstants2.PackageDescriptorFileName);
|
|
474
573
|
const packageDescriptor = {
|
|
475
574
|
files: {
|
|
476
|
-
[NugetConstants2.OperateFileName]:
|
|
477
|
-
"entry-points.json":
|
|
478
|
-
"bindings.json":
|
|
575
|
+
[NugetConstants2.OperateFileName]: Path5.join(NugetConstants2.ContentFolderName, NugetConstants2.OperateFileName),
|
|
576
|
+
"entry-points.json": Path5.join(NugetConstants2.ContentFolderName, "entry-points.json"),
|
|
577
|
+
"bindings.json": Path5.join(NugetConstants2.ContentFolderName, "bindings_v2.json")
|
|
479
578
|
}
|
|
480
579
|
};
|
|
481
580
|
const packageDescriptorJson = JSON.stringify(packageDescriptor, null, 2);
|
|
@@ -605,7 +704,7 @@ class WebAppTool extends ProjectTool {
|
|
|
605
704
|
let manifest;
|
|
606
705
|
let strategy;
|
|
607
706
|
try {
|
|
608
|
-
const prepared = await this.getManifestAndStrategy(options.projectPath);
|
|
707
|
+
const prepared = await this.getManifestAndStrategy(options.projectPath, options.codedBundle);
|
|
609
708
|
manifest = prepared.manifest;
|
|
610
709
|
strategy = prepared.strategy;
|
|
611
710
|
} catch (error) {
|
|
@@ -635,20 +734,33 @@ class WebAppTool extends ProjectTool {
|
|
|
635
734
|
await this._temporaryStorage.cleanup();
|
|
636
735
|
} catch {}
|
|
637
736
|
}
|
|
638
|
-
async getManifestAndStrategy(projectPath) {
|
|
639
|
-
const manifestPath =
|
|
737
|
+
async getManifestAndStrategy(projectPath, codedBundle) {
|
|
738
|
+
const manifestPath = Path6.join(projectPath, WEBAPP_MANIFEST_FILE_NAME);
|
|
640
739
|
const manifestExists = await this.fileSystem.exists(manifestPath);
|
|
641
|
-
if (!manifestExists) {
|
|
740
|
+
if (!manifestExists && !codedBundle) {
|
|
642
741
|
throw new Error(ERROR_MESSAGES.MANIFEST_NOT_FOUND(WEBAPP_MANIFEST_FILE_NAME));
|
|
643
742
|
}
|
|
644
|
-
const projectJsonPath =
|
|
743
|
+
const projectJsonPath = Path6.join(projectPath, PROJECT_JSON_FILE);
|
|
645
744
|
if (await this.fileSystem.exists(projectJsonPath)) {
|
|
646
745
|
throw new Error(ERROR_MESSAGES.PROJECT_JSON_FOUND);
|
|
647
746
|
}
|
|
648
|
-
|
|
747
|
+
let manifest = manifestExists ? await loadWebAppManifest(this.fileSystem, projectPath) : {
|
|
748
|
+
type: "Coded" /* Coded */,
|
|
749
|
+
solutionResourceSubType: "Coded" /* Coded */,
|
|
750
|
+
config: { isCompiled: true }
|
|
751
|
+
};
|
|
649
752
|
if (!manifest) {
|
|
650
753
|
throw new Error(ERROR_MESSAGES.MANIFEST_LOAD_FAILED(WEBAPP_MANIFEST_FILE_NAME));
|
|
651
754
|
}
|
|
755
|
+
if (codedBundle) {
|
|
756
|
+
if (manifest.type !== "Coded" /* Coded */) {
|
|
757
|
+
throw new Error("A coded bundle requires a Coded webAppManifest.json.");
|
|
758
|
+
}
|
|
759
|
+
manifest = {
|
|
760
|
+
...manifest,
|
|
761
|
+
config: { ...manifest.config, ...codedBundle }
|
|
762
|
+
};
|
|
763
|
+
}
|
|
652
764
|
const strategy = VariantStrategyFactory.createStrategy(manifest, this.fileSystem);
|
|
653
765
|
return { manifest, strategy };
|
|
654
766
|
}
|
|
@@ -688,7 +800,8 @@ export {
|
|
|
688
800
|
WEBAPP_MANIFEST_FILE_NAME,
|
|
689
801
|
WebAppTool,
|
|
690
802
|
WebAppToolFactory,
|
|
691
|
-
WebAppVariantType
|
|
803
|
+
WebAppVariantType,
|
|
804
|
+
ensureWebAppProjectId
|
|
692
805
|
};
|
|
693
806
|
|
|
694
|
-
//# debugId=
|
|
807
|
+
//# debugId=AFDD418216D2D37664756E2164756E21
|
|
@@ -17,6 +17,14 @@ export interface CodedAppConfig {
|
|
|
17
17
|
isCompiled?: boolean;
|
|
18
18
|
/** Compiled bundle folder location (default: dist/) */
|
|
19
19
|
bundlePath?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The file inside the bundle that `operate.json` names as `main`. Omit it
|
|
22
|
+
* to let pack take the first of the default HTML candidates
|
|
23
|
+
* (index.html, main.html, app.html) the bundle holds. Set, it may be any HTML file in the bundle, and pack
|
|
24
|
+
* refuses the project when the bundle does not hold it — a `main` the
|
|
25
|
+
* package does not carry produces an app that cannot boot.
|
|
26
|
+
*/
|
|
27
|
+
mainFile?: string;
|
|
20
28
|
/** Optional build command for future scenarios */
|
|
21
29
|
buildCommand?: string;
|
|
22
30
|
isActionApp?: boolean;
|
|
@@ -26,6 +26,41 @@ export declare class CodedAppStrategy implements VariantStrategy {
|
|
|
26
26
|
* Prepare metadata files (operate.json, package-descriptor.json, bindings.json, bindings_v2.json, entry-points.json)
|
|
27
27
|
*/
|
|
28
28
|
private prepareMetadataFiles;
|
|
29
|
+
/**
|
|
30
|
+
* Why this bundle folder cannot be packed, or `null` when it can. Shared
|
|
31
|
+
* by `validateAsync` and the pack-time guard so the two never disagree
|
|
32
|
+
* about what counts as a usable bundle.
|
|
33
|
+
*/
|
|
34
|
+
private describeBundleProblemAsync;
|
|
35
|
+
/**
|
|
36
|
+
* Why this bundle's entry point cannot be used, or `null` when it can. A
|
|
37
|
+
* `config.mainFile` the bundle does not hold is refused by name: falling
|
|
38
|
+
* back to `index.html` there would pack an app that boots a file the user
|
|
39
|
+
* did not ask for.
|
|
40
|
+
*/
|
|
41
|
+
private describeBundleEntryProblemAsync;
|
|
42
|
+
/**
|
|
43
|
+
* The file `operate.json` names as `main`, or `null` when the folder does
|
|
44
|
+
* not hold it. A declared `config.mainFile` wins and may be any HTML file in
|
|
45
|
+
* the bundle, not only one of the three defaults; without one, the first
|
|
46
|
+
* default candidate present is used.
|
|
47
|
+
*/
|
|
48
|
+
private resolveMainFileAsync;
|
|
49
|
+
/**
|
|
50
|
+
* The first HTML entry point present in a folder, or `null` when it holds
|
|
51
|
+
* none. One list, shared by the pack-time guard and the `operate.json`
|
|
52
|
+
* `main` lookup, so the file pack insists on is the file it then names.
|
|
53
|
+
*
|
|
54
|
+
* `stat().isFile()`, not `exists()`: `exists()` is true for a directory
|
|
55
|
+
* too, so a folder named `index.html` would satisfy the guard and then be
|
|
56
|
+
* named as `operate.json`'s `main`, which cannot boot.
|
|
57
|
+
*/
|
|
58
|
+
private findEntryPointAsync;
|
|
59
|
+
/**
|
|
60
|
+
* Keep authored schemas and entry metadata; only the primary entry follows
|
|
61
|
+
* the HTML file selected for operate.json. The project file stays untouched.
|
|
62
|
+
*/
|
|
63
|
+
private alignEntryPoint;
|
|
29
64
|
/**
|
|
30
65
|
* Create default entry-points.json structure
|
|
31
66
|
*/
|