@uipath/packager-tool-businessrules 1.202.1 → 1.203.0-preview.180
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/business-rules-tool.d.ts +36 -13
- package/dist/index.js +57 -13
- package/package.json +4 -4
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { IProjectBuildOptions, IProjectPackOptions, IProjectRestoreOptions, IProjectValidateOptions } from "@uipath/solutionpackager-tool-core";
|
|
2
2
|
import { ProjectTool, ToolResult } from "@uipath/solutionpackager-tool-core";
|
|
3
3
|
/**
|
|
4
|
-
* Business Rules project tool.
|
|
4
|
+
* Business Rules project tool. Only `packAsync` does anything.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* A rule ships as a `.uirule`, not wrapped in a nupkg: `options.outputPath` is already
|
|
7
|
+
* `files/{projectId}`, so writing the archive there is the whole job. The archive holds every
|
|
8
|
+
* `.dmn` plus `entry-points.json` at its root, and the manifest is where a deployed rule's argument
|
|
9
|
+
* contract is read from. Its `filePath` values keep a `/content/` prefix, which is an identifier
|
|
10
|
+
* inherited from the nupkg convention rather than a path into this archive.
|
|
10
11
|
*/
|
|
11
12
|
export declare class BusinessRulesTool extends ProjectTool {
|
|
12
13
|
restoreAsync(_options: IProjectRestoreOptions, _cancellationToken?: AbortSignal): Promise<ToolResult>;
|
|
@@ -14,25 +15,47 @@ export declare class BusinessRulesTool extends ProjectTool {
|
|
|
14
15
|
buildAsync(_options: IProjectBuildOptions, _cancellationToken?: AbortSignal): Promise<ToolResult>;
|
|
15
16
|
packAsync(options: IProjectPackOptions, _cancellationToken?: AbortSignal): Promise<ToolResult>;
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* The v1 artefact: the rule's single document, copied under the resource's name.
|
|
19
|
+
*
|
|
20
|
+
* Reached only when the project has no manifest. One document, because a v1 rule is addressed by
|
|
21
|
+
* file name alone -- several would leave the extras unreferenced, since the project has a single
|
|
22
|
+
* `businessRule` resource.
|
|
23
|
+
*/
|
|
24
|
+
private copyRuleDocumentAsync;
|
|
25
|
+
/**
|
|
26
|
+
* `{ruleName}-{version}.uirule`, which is what Orchestrator's export handler
|
|
18
27
|
* builds for the same rule. Publish and export have to agree on this or a
|
|
19
28
|
* rule stops round-tripping between solutions.
|
|
20
29
|
*
|
|
21
|
-
* `ruleName` is the name of the `businessRule` resource, never
|
|
30
|
+
* `ruleName` is the name of the `businessRule` resource, never any `.dmn`
|
|
22
31
|
* file's own basename — a project folder named "Business Rules" holding
|
|
23
|
-
* "Business rule.dmn" is what Studio Web produces today
|
|
24
|
-
* the
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* the
|
|
32
|
+
* "Business rule.dmn" is what Studio Web produces today, and with several
|
|
33
|
+
* documents in the project no single basename could stand for the rule
|
|
34
|
+
* anyway. Orchestrator takes the rule's name from the resource (`Spec.Name`)
|
|
35
|
+
* and rebuilds the file name from it on export, and the service reads a
|
|
36
|
+
* rule's version back out of this name by stripping the resource name off
|
|
37
|
+
* the front. Deriving the name from a document would break both.
|
|
28
38
|
*
|
|
29
39
|
* So resolve it the way `solution projects add` does when it registers the
|
|
30
40
|
* resource: `project.uiproj`'s `Name`, falling back to the folder. Blank also
|
|
31
41
|
* falls back — `projects add` passes an empty `Name` through, but here it
|
|
32
|
-
* would produce a file called "-1.0.0.
|
|
42
|
+
* would produce a file called "-1.0.0.uirule".
|
|
33
43
|
*
|
|
34
44
|
* Returns `undefined` when the declared name cannot be used in a file name.
|
|
35
45
|
*/
|
|
36
46
|
private resolveRuleName;
|
|
47
|
+
/**
|
|
48
|
+
* The document names the manifest declares, or `null` when it cannot be read.
|
|
49
|
+
*
|
|
50
|
+
* `filePath` is an identifier of the form `/content/{file}#{decisionId}` -- the `/content/`
|
|
51
|
+
* prefix is inherited from the nupkg convention and does not describe the archive, which is
|
|
52
|
+
* flat -- so only the file name is kept.
|
|
53
|
+
*
|
|
54
|
+
* A manifest that declares no entry points is readable and returns an empty list. That is the
|
|
55
|
+
* caller's to allow: it ships a `.uirule` exposing nothing, which is what the designer wrote.
|
|
56
|
+
*/
|
|
57
|
+
private readDeclaredDocuments;
|
|
58
|
+
/** Declared documents that are not among the packed entries. */
|
|
59
|
+
private declaredDocumentsMissingFrom;
|
|
37
60
|
private findRuleFiles;
|
|
38
61
|
}
|
package/dist/index.js
CHANGED
|
@@ -11,9 +11,12 @@ import {
|
|
|
11
11
|
Path,
|
|
12
12
|
ProjectTool,
|
|
13
13
|
ToolErrorCodes,
|
|
14
|
-
ToolResult
|
|
14
|
+
ToolResult,
|
|
15
|
+
ZipService
|
|
15
16
|
} from "@uipath/solutionpackager-tool-core";
|
|
16
17
|
var DmnExtension = ".dmn";
|
|
18
|
+
var RuleArchiveExtension = ".uirule";
|
|
19
|
+
var EntryPointsFileName = "entry-points.json";
|
|
17
20
|
var ReservedInFileName = /[<>:"/\\|?*]/;
|
|
18
21
|
function isUsableInFileName(name) {
|
|
19
22
|
return !ReservedInFileName.test(name) && ![...name].some((character) => character.charCodeAt(0) < 32);
|
|
@@ -38,22 +41,38 @@ class BusinessRulesTool extends ProjectTool {
|
|
|
38
41
|
if (ruleFiles.length === 0) {
|
|
39
42
|
return ToolResult.error(ToolErrorCodes.InternalError, `No ${DmnExtension} file found in ${options.projectPath}.`, "Add a decision to the project, then pack again.");
|
|
40
43
|
}
|
|
41
|
-
if (ruleFiles.length > 1) {
|
|
42
|
-
return ToolResult.error(ToolErrorCodes.InternalError, `Found ${ruleFiles.length} ${DmnExtension} files in ${options.projectPath}, expected one.`, `Keep one decision per project and move the rest to their own projects.`);
|
|
43
|
-
}
|
|
44
|
-
const sourceFile = ruleFiles[0];
|
|
45
44
|
const ruleName = await this.resolveRuleName(options);
|
|
46
45
|
if (ruleName === undefined) {
|
|
47
46
|
return ToolResult.error(ToolErrorCodes.InternalError, `The project name in project.uiproj cannot be used in a file name.`, `Rename the project so its name has no path separators and none of < > : " | ? * characters.`);
|
|
48
47
|
}
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
const manifest = await this.fileSystem.readFile(Path.join(options.projectPath, EntryPointsFileName));
|
|
49
|
+
if (!manifest || manifest.length === 0) {
|
|
50
|
+
this.logger.warn(`No ${EntryPointsFileName} in ${options.projectPath}, so the rule ships as a ${DmnExtension} and exposes no arguments. Open the project in Studio Web and save it to write its entry points.`);
|
|
51
|
+
return this.copyRuleDocumentAsync(options, ruleFiles, ruleName);
|
|
52
|
+
}
|
|
53
|
+
const declared = this.readDeclaredDocuments(manifest);
|
|
54
|
+
if (declared === null) {
|
|
55
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `${EntryPointsFileName} in ${options.projectPath} is not valid JSON.`, `Open the project in Studio Web and save it to rewrite its entry points, then pack again.`);
|
|
56
|
+
}
|
|
57
|
+
const entries = {
|
|
58
|
+
[EntryPointsFileName]: manifest
|
|
59
|
+
};
|
|
60
|
+
for (const ruleFile of ruleFiles) {
|
|
61
|
+
const content = await this.fileSystem.readFile(ruleFile);
|
|
62
|
+
if (!content) {
|
|
63
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `Could not read ${ruleFile}.`);
|
|
64
|
+
}
|
|
65
|
+
entries[Path.basename(ruleFile)] = content;
|
|
55
66
|
}
|
|
56
|
-
|
|
67
|
+
const missing = this.declaredDocumentsMissingFrom(declared, entries);
|
|
68
|
+
if (missing.length > 0) {
|
|
69
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `${EntryPointsFileName} names ${missing.join(", ")}, which ${missing.length === 1 ? "is" : "are"} not in ${options.projectPath}.`, `Move every .dmn the rule uses to the top level of the project, then pack again.`);
|
|
70
|
+
}
|
|
71
|
+
const targetName = `${ruleName}-${options.package.version}${RuleArchiveExtension}`;
|
|
72
|
+
const targetFile = Path.join(options.outputPath, targetName);
|
|
73
|
+
this.logger.progress(`Packing ${ruleFiles.length} ${DmnExtension} file(s) into ${targetName}...`);
|
|
74
|
+
const archive = new ZipService(this.fileSystem).compressEntries(entries);
|
|
75
|
+
await this.fileSystem.writeFile(targetFile, archive);
|
|
57
76
|
return new ToolResult(ToolErrorCodes.Success, "done", []);
|
|
58
77
|
} catch (error) {
|
|
59
78
|
const message = error instanceof Error ? error.toString() : String(error);
|
|
@@ -61,6 +80,19 @@ class BusinessRulesTool extends ProjectTool {
|
|
|
61
80
|
return ToolResult.error(ToolErrorCodes.InternalError, "An error occurred while packing the Business Rules project");
|
|
62
81
|
}
|
|
63
82
|
}
|
|
83
|
+
async copyRuleDocumentAsync(options, ruleFiles, ruleName) {
|
|
84
|
+
if (ruleFiles.length > 1) {
|
|
85
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `Found ${ruleFiles.length} ${DmnExtension} files in ${options.projectPath}, expected one.`, `Keep one decision per project and move the rest to their own projects, or save the project in Studio Web so its entry points name the callable one.`);
|
|
86
|
+
}
|
|
87
|
+
const content = await this.fileSystem.readFile(ruleFiles[0]);
|
|
88
|
+
if (!content) {
|
|
89
|
+
return ToolResult.error(ToolErrorCodes.InternalError, `Could not read ${ruleFiles[0]}.`);
|
|
90
|
+
}
|
|
91
|
+
const targetName = `${ruleName}-${options.package.version}${DmnExtension}`;
|
|
92
|
+
this.logger.progress(`Copying ${targetName}...`);
|
|
93
|
+
await this.fileSystem.writeFile(Path.join(options.outputPath, targetName), content);
|
|
94
|
+
return new ToolResult(ToolErrorCodes.Success, "done", []);
|
|
95
|
+
}
|
|
64
96
|
async resolveRuleName(options) {
|
|
65
97
|
const uiProject = await this.getUiProjectAsync(options.projectPath);
|
|
66
98
|
const declared = uiProject?.Name?.trim();
|
|
@@ -69,6 +101,18 @@ class BusinessRulesTool extends ProjectTool {
|
|
|
69
101
|
}
|
|
70
102
|
return isUsableInFileName(declared) ? declared : undefined;
|
|
71
103
|
}
|
|
104
|
+
readDeclaredDocuments(manifest) {
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(new TextDecoder().decode(manifest));
|
|
107
|
+
return (parsed.entryPoints ?? []).map((entryPoint) => entryPoint.filePath).filter((filePath) => !!filePath).map((filePath) => Path.basename(filePath.split("#")[0]));
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
declaredDocumentsMissingFrom(declared, entries) {
|
|
113
|
+
const packed = new Set(Object.keys(entries));
|
|
114
|
+
return [...new Set(declared)].filter((document) => !packed.has(document));
|
|
115
|
+
}
|
|
72
116
|
async findRuleFiles(projectPath) {
|
|
73
117
|
const entries = await this.fileSystem.readdir(projectPath);
|
|
74
118
|
const ruleFiles = [];
|
|
@@ -103,4 +147,4 @@ export {
|
|
|
103
147
|
BusinessRulesToolFactory
|
|
104
148
|
};
|
|
105
149
|
|
|
106
|
-
//# debugId=
|
|
150
|
+
//# debugId=FC8F16D6B30A334C64756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/packager-tool-businessrules",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.203.0-preview.180",
|
|
4
4
|
"description": "UiPath Business Rules tool implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
|
-
"author": "",
|
|
21
|
+
"author": "UiPath",
|
|
22
22
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@uipath/solutionpackager-tool-core": "1.
|
|
24
|
+
"@uipath/solutionpackager-tool-core": "1.203.0"
|
|
25
25
|
},
|
|
26
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "4e0a51e3ab2c9d89afd3d35a7b087a7fa58133a0"
|
|
27
27
|
}
|