@uipath/packager-tool-case 1.201.0 → 1.202.0-preview.136
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/case-bpmn-compiler.d.ts +25 -0
- package/dist/case-tool.d.ts +46 -3
- package/dist/index-x6xpvwgg.js +63712 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +76 -3
- package/dist/node-1de529jm.js +39 -0
- package/dist/node.d.ts +6 -0
- package/dist/node.js +26 -0
- package/package.json +8 -3
- package/src/case-bpmn-compiler.ts +48 -0
- package/src/case-tool.ts +164 -3
- package/src/index.ts +4 -0
- package/src/node.ts +35 -0
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -18,9 +18,23 @@ import {
|
|
|
18
18
|
ToolErrorCodes,
|
|
19
19
|
ToolResult
|
|
20
20
|
} from "@uipath/solutionpackager-tool-core";
|
|
21
|
+
|
|
22
|
+
// src/case-bpmn-compiler.ts
|
|
23
|
+
var COMPILER_KEY = Symbol.for("@uipath/packager-tool-case/caseBpmnCompiler");
|
|
24
|
+
var _global = globalThis;
|
|
25
|
+
function registerCaseBpmnCompiler(caseBpmnCompiler) {
|
|
26
|
+
_global[COMPILER_KEY] = caseBpmnCompiler;
|
|
27
|
+
}
|
|
28
|
+
function getCaseBpmnCompiler() {
|
|
29
|
+
return _global[COMPILER_KEY];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/case-tool.ts
|
|
21
33
|
var CaseConstants = {
|
|
22
34
|
EntryPointsFileName: "entry-points.json",
|
|
23
|
-
BindingsV2FileName: "bindings_v2.json"
|
|
35
|
+
BindingsV2FileName: "bindings_v2.json",
|
|
36
|
+
CasePlanFileName: "caseplan.json",
|
|
37
|
+
CompiledBpmnFileName: "caseplan.json.bpmn"
|
|
24
38
|
};
|
|
25
39
|
|
|
26
40
|
class CaseTool extends ProjectTool {
|
|
@@ -44,6 +58,11 @@ class CaseTool extends ProjectTool {
|
|
|
44
58
|
try {
|
|
45
59
|
this.logger.progress("Copying files...");
|
|
46
60
|
await this.copyFiles(options.projectPath, contentFolder);
|
|
61
|
+
this.logger.progress("Compiling case plan to BPMN...");
|
|
62
|
+
const compileResult = await this.compileCasePlan(options.projectPath, contentFolder);
|
|
63
|
+
if (!compileResult.isSuccess) {
|
|
64
|
+
return compileResult;
|
|
65
|
+
}
|
|
47
66
|
this.logger.progress("Creating operate.json file...");
|
|
48
67
|
await this.createOperateFile(options, contentFolder);
|
|
49
68
|
this.logger.progress("Creating package-descriptor.json file...");
|
|
@@ -100,6 +119,59 @@ class CaseTool extends ProjectTool {
|
|
|
100
119
|
}
|
|
101
120
|
}
|
|
102
121
|
}
|
|
122
|
+
async compileCasePlan(projectPath, contentFolder) {
|
|
123
|
+
const compile = getCaseBpmnCompiler();
|
|
124
|
+
const casePlanPath = Path.join(projectPath, CaseConstants.CasePlanFileName);
|
|
125
|
+
if (!compile || !await this.fileSystem.exists(casePlanPath)) {
|
|
126
|
+
return this.checkEntryPointBpmnPresent(contentFolder);
|
|
127
|
+
}
|
|
128
|
+
const casePlan = await this.fileSystem.readFile(casePlanPath);
|
|
129
|
+
if (!casePlan || casePlan.length === 0) {
|
|
130
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `'${CaseConstants.CasePlanFileName}' in ${projectPath} is empty, so there is nothing to compile into '${CaseConstants.CompiledBpmnFileName}'. Author the case plan, or re-scaffold the project with 'uip maestro case init'.`);
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const bpmnXml = await compile(new TextDecoder().decode(casePlan));
|
|
134
|
+
await this.fileSystem.writeFile(Path.join(contentFolder, CaseConstants.CompiledBpmnFileName), bpmnXml);
|
|
135
|
+
return await this.checkEntryPointBpmnPresent(contentFolder);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
138
|
+
this.logger.error(message);
|
|
139
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `Failed to compile '${CaseConstants.CasePlanFileName}' into '${CaseConstants.CompiledBpmnFileName}': ${message}. Run 'uip maestro case validate ${projectPath}' to find the problem in the case plan, then pack again.`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async checkEntryPointBpmnPresent(contentFolder) {
|
|
143
|
+
const referenced = await this.readEntryPointBpmnFiles(contentFolder);
|
|
144
|
+
if (referenced === null) {
|
|
145
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `'${CaseConstants.EntryPointsFileName}' could not be read as JSON, so pack cannot check that the BPMN it declares is in the package. Fix or re-scaffold '${CaseConstants.EntryPointsFileName}', then pack again.`);
|
|
146
|
+
}
|
|
147
|
+
if (referenced.length === 0) {
|
|
148
|
+
return ToolResult.success();
|
|
149
|
+
}
|
|
150
|
+
const contentFiles = await this.fileSystem.readdir(contentFolder);
|
|
151
|
+
const missing = referenced.filter((file) => !contentFiles.includes(file));
|
|
152
|
+
if (missing.length === 0) {
|
|
153
|
+
return ToolResult.success();
|
|
154
|
+
}
|
|
155
|
+
const fix = missing.includes(CaseConstants.CompiledBpmnFileName) ? `Author '${CaseConstants.CasePlanFileName}' so pack can compile it (see 'uip maestro case init'), then pack again.` : `Add the missing file to the project, or point '${CaseConstants.EntryPointsFileName}' at the BPMN the project does ship, then pack again.`;
|
|
156
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `'${CaseConstants.EntryPointsFileName}' points at ${missing.map((f) => `'content/${f}'`).join(", ")}, which the package does not contain, so it would deploy and activate and then fault every job. ${fix}`);
|
|
157
|
+
}
|
|
158
|
+
async readEntryPointBpmnFiles(contentFolder) {
|
|
159
|
+
const entryPointsPath = Path.join(contentFolder, CaseConstants.EntryPointsFileName);
|
|
160
|
+
if (!await this.fileSystem.exists(entryPointsPath)) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
const raw = await this.fileSystem.readFile(entryPointsPath);
|
|
164
|
+
if (!raw || raw.length === 0) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const parsed = JSON.parse(new TextDecoder().decode(raw));
|
|
169
|
+
const names = (parsed.entryPoints ?? []).map((entry) => entry.filePath ?? "").map((filePath) => filePath.split("#")[0]).map((filePath) => filePath.split("/").pop() ?? "").filter((name) => name.endsWith(".bpmn"));
|
|
170
|
+
return [...new Set(names)];
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
103
175
|
async createOperateFile(options, contentFolder) {
|
|
104
176
|
await ensureContentOperateFile(this.fileSystem, {
|
|
105
177
|
contentFolder,
|
|
@@ -141,7 +213,8 @@ class CaseToolFactory {
|
|
|
141
213
|
// src/index.ts
|
|
142
214
|
toolsFactoryRepository.registerProjectToolFactory(new CaseToolFactory);
|
|
143
215
|
export {
|
|
144
|
-
CaseToolFactory
|
|
216
|
+
CaseToolFactory,
|
|
217
|
+
registerCaseBpmnCompiler
|
|
145
218
|
};
|
|
146
219
|
|
|
147
|
-
//# debugId=
|
|
220
|
+
//# debugId=0879235A557F09E364756E2164756E21
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
12
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
20
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (canCache)
|
|
31
|
+
cache.set(mod, to);
|
|
32
|
+
return to;
|
|
33
|
+
};
|
|
34
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
35
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
36
|
+
|
|
37
|
+
export { __toESM, __commonJS, __require };
|
|
38
|
+
|
|
39
|
+
//# debugId=4A15A0D6FCDB684764756E2164756E21
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register the Node `caseplan.json` -> BPMN compiler. Call it wherever the
|
|
3
|
+
* Case project tool factory is registered on Node — without it a Case project
|
|
4
|
+
* can only be packed from an already-compiled `.bpmn`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerNodeCaseBpmnCompiler(): void;
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require,
|
|
3
|
+
__toESM
|
|
4
|
+
} from "./node-1de529jm.js";
|
|
5
|
+
|
|
6
|
+
// src/case-bpmn-compiler.ts
|
|
7
|
+
var COMPILER_KEY = Symbol.for("@uipath/packager-tool-case/caseBpmnCompiler");
|
|
8
|
+
var _global = globalThis;
|
|
9
|
+
function registerCaseBpmnCompiler(caseBpmnCompiler) {
|
|
10
|
+
_global[COMPILER_KEY] = caseBpmnCompiler;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/node.ts
|
|
14
|
+
var compileCasePlan = async (casePlanJson) => {
|
|
15
|
+
const { serializeCaseDiskJsonToBpmnAndRulesJson } = await import("./index-x6xpvwgg.js").then((m)=>__toESM(m.default,1));
|
|
16
|
+
const { bpmnXml } = await serializeCaseDiskJsonToBpmnAndRulesJson(casePlanJson);
|
|
17
|
+
return bpmnXml;
|
|
18
|
+
};
|
|
19
|
+
function registerNodeCaseBpmnCompiler() {
|
|
20
|
+
registerCaseBpmnCompiler(compileCasePlan);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
registerNodeCaseBpmnCompiler
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
//# debugId=0A08F635657DD68164756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/packager-tool-case",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.202.0-preview.136",
|
|
4
4
|
"description": "UiPath Case Management tool implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"source": "./src/index.ts",
|
|
9
9
|
"default": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./node": {
|
|
12
|
+
"source": "./src/node.ts",
|
|
13
|
+
"types": "./dist/node.d.ts",
|
|
14
|
+
"default": "./dist/node.js"
|
|
10
15
|
}
|
|
11
16
|
},
|
|
12
17
|
"repository": {
|
|
@@ -25,7 +30,7 @@
|
|
|
25
30
|
"author": "",
|
|
26
31
|
"license": "ISC",
|
|
27
32
|
"peerDependencies": {
|
|
28
|
-
"@uipath/solutionpackager-tool-core": "1.
|
|
33
|
+
"@uipath/solutionpackager-tool-core": "1.202.0"
|
|
29
34
|
},
|
|
30
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "f6270de2c7c04f4c43b2f5187b0c3d3c314c2610"
|
|
31
36
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry for the `caseplan.json` -> BPMN compiler.
|
|
3
|
+
*
|
|
4
|
+
* The compiler lives in `@uipath/case-schema`, a 2.5 MB CommonJS bundle that
|
|
5
|
+
* `require`s `child_process`, `tls` and `http2`. This package builds for the
|
|
6
|
+
* browser (StudioWeb loads it as a micro-frontend), so it cannot import that
|
|
7
|
+
* dependency directly. Instead it declares the interface and whoever runs on
|
|
8
|
+
* Node registers the real thing — `@uipath/packager-tool-case/node` provides
|
|
9
|
+
* that implementation, and the CLI tools that register the Case factory call
|
|
10
|
+
* it alongside.
|
|
11
|
+
*
|
|
12
|
+
* Nothing registered means no compile: `CaseTool` then requires the project to
|
|
13
|
+
* carry an already-compiled `.bpmn` and fails the build with an actionable
|
|
14
|
+
* message if it does not. It never packs a case silently missing its BPMN.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Compiles the contents of `caseplan.json` into BPMN XML. */
|
|
18
|
+
export type CaseBpmnCompiler = (casePlanJson: string) => Promise<string>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Global singleton key, keyed with `Symbol.for()` so every copy of this module
|
|
22
|
+
* resolves to the same slot. There are always several: `maestro-tool` and
|
|
23
|
+
* `case-tool` each bundle their own copy of this package, and the Node entry
|
|
24
|
+
* that registers the compiler is a separate build output from the browser one
|
|
25
|
+
* that reads it. A module-local `let` would leave the registration in one copy
|
|
26
|
+
* and the lookup in another — which is silently the old bug, a package packed
|
|
27
|
+
* without its BPMN. Mirrors `toolsFactoryRepository` in
|
|
28
|
+
* `@uipath/solutionpackager-tool-core`.
|
|
29
|
+
*/
|
|
30
|
+
const COMPILER_KEY = Symbol.for("@uipath/packager-tool-case/caseBpmnCompiler");
|
|
31
|
+
|
|
32
|
+
const _global = globalThis as Record<symbol, CaseBpmnCompiler | undefined>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Register the compiler used by `CaseTool.buildAsync`. Last call wins. Pass
|
|
36
|
+
* `undefined` to clear it — how a test reproduces a host that never
|
|
37
|
+
* registered one.
|
|
38
|
+
*/
|
|
39
|
+
export function registerCaseBpmnCompiler(
|
|
40
|
+
caseBpmnCompiler: CaseBpmnCompiler | undefined,
|
|
41
|
+
): void {
|
|
42
|
+
_global[COMPILER_KEY] = caseBpmnCompiler;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The registered compiler, or `undefined` when none was registered. */
|
|
46
|
+
export function getCaseBpmnCompiler(): CaseBpmnCompiler | undefined {
|
|
47
|
+
return _global[COMPILER_KEY];
|
|
48
|
+
}
|
package/src/case-tool.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
ToolErrorCodes,
|
|
18
18
|
ToolResult,
|
|
19
19
|
} from "@uipath/solutionpackager-tool-core";
|
|
20
|
+
import { getCaseBpmnCompiler } from "./case-bpmn-compiler.js";
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Case Management-specific file names
|
|
@@ -24,14 +25,18 @@ import {
|
|
|
24
25
|
const CaseConstants = {
|
|
25
26
|
EntryPointsFileName: "entry-points.json",
|
|
26
27
|
BindingsV2FileName: "bindings_v2.json",
|
|
28
|
+
CasePlanFileName: "caseplan.json",
|
|
29
|
+
CompiledBpmnFileName: "caseplan.json.bpmn",
|
|
27
30
|
} as const;
|
|
28
31
|
|
|
29
32
|
/**
|
|
30
33
|
* Case Management project tool implementation.
|
|
31
34
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
+
* The authored source is `caseplan.json`; the runtime reads the BPMN compiled
|
|
36
|
+
* from it. `entry-points.json` points at `/content/caseplan.json.bpmn`, so the
|
|
37
|
+
* build compiles that file into content/ — a package without it deploys and
|
|
38
|
+
* activates fine and then faults every job it starts (UV-15809). All files are
|
|
39
|
+
* placed in the content/ folder (no separate source folder like flow_files/).
|
|
35
40
|
*/
|
|
36
41
|
export class CaseTool extends ProjectTool {
|
|
37
42
|
private readonly _temporaryStorage: TemporaryStorageService;
|
|
@@ -79,6 +84,15 @@ export class CaseTool extends ProjectTool {
|
|
|
79
84
|
this.logger.progress("Copying files...");
|
|
80
85
|
await this.copyFiles(options.projectPath, contentFolder);
|
|
81
86
|
|
|
87
|
+
this.logger.progress("Compiling case plan to BPMN...");
|
|
88
|
+
const compileResult = await this.compileCasePlan(
|
|
89
|
+
options.projectPath,
|
|
90
|
+
contentFolder,
|
|
91
|
+
);
|
|
92
|
+
if (!compileResult.isSuccess) {
|
|
93
|
+
return compileResult;
|
|
94
|
+
}
|
|
95
|
+
|
|
82
96
|
this.logger.progress("Creating operate.json file...");
|
|
83
97
|
await this.createOperateFile(options, contentFolder);
|
|
84
98
|
|
|
@@ -175,6 +189,153 @@ export class CaseTool extends ProjectTool {
|
|
|
175
189
|
}
|
|
176
190
|
}
|
|
177
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Compile `caseplan.json` into `content/caseplan.json.bpmn`.
|
|
194
|
+
*
|
|
195
|
+
* Runs after copyFiles on purpose: a stale `caseplan.json.bpmn` left in the
|
|
196
|
+
* project directory by an earlier `uip maestro case pack` is copied in
|
|
197
|
+
* first and then overwritten here, so an edited case plan can never ship
|
|
198
|
+
* against an old BPMN. Nothing is written back into the project directory —
|
|
199
|
+
* packing a solution does not mutate the user's source tree.
|
|
200
|
+
*
|
|
201
|
+
* The compiler is injected (see `case-bpmn-compiler.ts`). With none
|
|
202
|
+
* registered — a browser host, where `@uipath/case-schema` cannot run — the
|
|
203
|
+
* project has to bring its own compiled `.bpmn`.
|
|
204
|
+
*/
|
|
205
|
+
private async compileCasePlan(
|
|
206
|
+
projectPath: string,
|
|
207
|
+
contentFolder: string,
|
|
208
|
+
): Promise<ToolResult> {
|
|
209
|
+
const compile = getCaseBpmnCompiler();
|
|
210
|
+
const casePlanPath = Path.join(
|
|
211
|
+
projectPath,
|
|
212
|
+
CaseConstants.CasePlanFileName,
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
if (!compile || !(await this.fileSystem.exists(casePlanPath))) {
|
|
216
|
+
return this.checkEntryPointBpmnPresent(contentFolder);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const casePlan = await this.fileSystem.readFile(casePlanPath);
|
|
220
|
+
if (!casePlan || casePlan.length === 0) {
|
|
221
|
+
return ToolResult.error(
|
|
222
|
+
ToolErrorCodes.InternalError,
|
|
223
|
+
`'${CaseConstants.CasePlanFileName}' in ${projectPath} is empty, so there is nothing to compile into '${CaseConstants.CompiledBpmnFileName}'. Author the case plan, or re-scaffold the project with 'uip maestro case init'.`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const bpmnXml = await compile(new TextDecoder().decode(casePlan));
|
|
229
|
+
await this.fileSystem.writeFile(
|
|
230
|
+
Path.join(contentFolder, CaseConstants.CompiledBpmnFileName),
|
|
231
|
+
bpmnXml,
|
|
232
|
+
);
|
|
233
|
+
// A compile alone does not prove the package is coherent: the
|
|
234
|
+
// entry point could name a different file. Check what was declared.
|
|
235
|
+
return await this.checkEntryPointBpmnPresent(contentFolder);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
const message =
|
|
238
|
+
error instanceof Error ? error.message : String(error);
|
|
239
|
+
this.logger.error(message);
|
|
240
|
+
return ToolResult.error(
|
|
241
|
+
ToolErrorCodes.InternalError,
|
|
242
|
+
`Failed to compile '${CaseConstants.CasePlanFileName}' into '${CaseConstants.CompiledBpmnFileName}': ${message}. Run 'uip maestro case validate ${projectPath}' to find the problem in the case plan, then pack again.`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Verify every `.bpmn` `entry-points.json` names is actually in content/.
|
|
249
|
+
*
|
|
250
|
+
* This is the defect UV-15809 reported, checked mechanically: the entry
|
|
251
|
+
* point resolved to a file the package did not contain, so it deployed and
|
|
252
|
+
* activated cleanly and then faulted every job. Checking the declaration
|
|
253
|
+
* rather than a fixed filename covers both project shapes — a CLI project
|
|
254
|
+
* (`caseplan.json` -> `caseplan.json.bpmn`) and a Studio Web one
|
|
255
|
+
* (`<name>.stage.json` shipped with its compiled `<name>.stage.json.bpmn`)
|
|
256
|
+
* — and a stray `.bpmn` left behind by `uip case debug` cannot stand in for
|
|
257
|
+
* the one that is missing.
|
|
258
|
+
*
|
|
259
|
+
* No `entry-points.json` means nothing declares an entry point, so there is
|
|
260
|
+
* nothing to resolve and nothing to fail on.
|
|
261
|
+
*/
|
|
262
|
+
private async checkEntryPointBpmnPresent(
|
|
263
|
+
contentFolder: string,
|
|
264
|
+
): Promise<ToolResult> {
|
|
265
|
+
const referenced = await this.readEntryPointBpmnFiles(contentFolder);
|
|
266
|
+
if (referenced === null) {
|
|
267
|
+
return ToolResult.error(
|
|
268
|
+
ToolErrorCodes.InternalError,
|
|
269
|
+
`'${CaseConstants.EntryPointsFileName}' could not be read as JSON, so pack cannot check that the BPMN it declares is in the package. Fix or re-scaffold '${CaseConstants.EntryPointsFileName}', then pack again.`,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
if (referenced.length === 0) {
|
|
273
|
+
return ToolResult.success();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const contentFiles = await this.fileSystem.readdir(contentFolder);
|
|
277
|
+
const missing = referenced.filter(
|
|
278
|
+
(file) => !contentFiles.includes(file),
|
|
279
|
+
);
|
|
280
|
+
if (missing.length === 0) {
|
|
281
|
+
return ToolResult.success();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Only the CLI shape can be produced by packing: the missing file is
|
|
285
|
+
// compiled from `caseplan.json`. A Studio Web project ships its own
|
|
286
|
+
// `<name>.stage.json.bpmn`, and telling that user to author a
|
|
287
|
+
// `caseplan.json` their project type does not use is wrong.
|
|
288
|
+
const fix = missing.includes(CaseConstants.CompiledBpmnFileName)
|
|
289
|
+
? `Author '${CaseConstants.CasePlanFileName}' so pack can compile it (see 'uip maestro case init'), then pack again.`
|
|
290
|
+
: `Add the missing file to the project, or point '${CaseConstants.EntryPointsFileName}' at the BPMN the project does ship, then pack again.`;
|
|
291
|
+
|
|
292
|
+
return ToolResult.error(
|
|
293
|
+
ToolErrorCodes.InternalError,
|
|
294
|
+
`'${CaseConstants.EntryPointsFileName}' points at ${missing.map((f) => `'content/${f}'`).join(", ")}, which the package does not contain, so it would deploy and activate and then fault every job. ${fix}`,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* The `.bpmn` file names `entry-points.json` refers to. Entries look like
|
|
300
|
+
* `/content/caseplan.json.bpmn#<triggerId>`; `uip case debug` writes them
|
|
301
|
+
* without the `content/` prefix, so both forms are accepted.
|
|
302
|
+
*
|
|
303
|
+
* No file at all means nothing is declared, so the caller has nothing to
|
|
304
|
+
* check. A file that is there but cannot be read as JSON returns `null`:
|
|
305
|
+
* treating that as "nothing declared" would wave through the very package
|
|
306
|
+
* this check exists to stop, since the entry point it names is unknown.
|
|
307
|
+
*/
|
|
308
|
+
private async readEntryPointBpmnFiles(
|
|
309
|
+
contentFolder: string,
|
|
310
|
+
): Promise<string[] | null> {
|
|
311
|
+
const entryPointsPath = Path.join(
|
|
312
|
+
contentFolder,
|
|
313
|
+
CaseConstants.EntryPointsFileName,
|
|
314
|
+
);
|
|
315
|
+
if (!(await this.fileSystem.exists(entryPointsPath))) {
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const raw = await this.fileSystem.readFile(entryPointsPath);
|
|
320
|
+
if (!raw || raw.length === 0) {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
const parsed = JSON.parse(new TextDecoder().decode(raw)) as {
|
|
326
|
+
entryPoints?: { filePath?: string }[];
|
|
327
|
+
};
|
|
328
|
+
const names = (parsed.entryPoints ?? [])
|
|
329
|
+
.map((entry) => entry.filePath ?? "")
|
|
330
|
+
.map((filePath) => filePath.split("#")[0])
|
|
331
|
+
.map((filePath) => filePath.split("/").pop() ?? "")
|
|
332
|
+
.filter((name) => name.endsWith(".bpmn"));
|
|
333
|
+
return [...new Set(names)];
|
|
334
|
+
} catch {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
178
339
|
/**
|
|
179
340
|
* Create operate.json file if it doesn't already exist
|
|
180
341
|
*/
|
package/src/index.ts
CHANGED
|
@@ -10,4 +10,8 @@ import { CaseToolFactory } from "./case-tool-factory.js";
|
|
|
10
10
|
|
|
11
11
|
toolsFactoryRepository.registerProjectToolFactory(new CaseToolFactory());
|
|
12
12
|
|
|
13
|
+
export {
|
|
14
|
+
type CaseBpmnCompiler,
|
|
15
|
+
registerCaseBpmnCompiler,
|
|
16
|
+
} from "./case-bpmn-compiler.js";
|
|
13
17
|
export { CaseToolFactory };
|
package/src/node.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Node-only entry point: wires the real `caseplan.json` -> BPMN compiler into
|
|
2
|
+
// the Case packager. Kept out of `index.ts` because `@uipath/case-schema`
|
|
3
|
+
// requires Node built-ins and would break the browser build — see
|
|
4
|
+
// `case-bpmn-compiler.ts`.
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
type CaseBpmnCompiler,
|
|
8
|
+
registerCaseBpmnCompiler,
|
|
9
|
+
} from "./case-bpmn-compiler.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `@uipath/case-schema` ships as a single 2.5 MB CommonJS bundle with no
|
|
13
|
+
* `exports` map, so nothing in it can be tree-shaken — importing one function
|
|
14
|
+
* costs the whole file. Behind `await import` it becomes its own lazy chunk,
|
|
15
|
+
* parsed only when a Case project is actually built, instead of loading with
|
|
16
|
+
* every `uip maestro -h`. `case-tool` keeps the same shape for its own
|
|
17
|
+
* `uip maestro case pack` path (`services/case-schema-loader.ts`).
|
|
18
|
+
*/
|
|
19
|
+
const compileCasePlan: CaseBpmnCompiler = async (casePlanJson) => {
|
|
20
|
+
const { serializeCaseDiskJsonToBpmnAndRulesJson } = await import(
|
|
21
|
+
"@uipath/case-schema"
|
|
22
|
+
);
|
|
23
|
+
const { bpmnXml } =
|
|
24
|
+
await serializeCaseDiskJsonToBpmnAndRulesJson(casePlanJson);
|
|
25
|
+
return bpmnXml;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Register the Node `caseplan.json` -> BPMN compiler. Call it wherever the
|
|
30
|
+
* Case project tool factory is registered on Node — without it a Case project
|
|
31
|
+
* can only be packed from an already-compiled `.bpmn`.
|
|
32
|
+
*/
|
|
33
|
+
export function registerNodeCaseBpmnCompiler(): void {
|
|
34
|
+
registerCaseBpmnCompiler(compileCasePlan);
|
|
35
|
+
}
|