dazscript-framework 1.0.3 → 1.0.5
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/README.md +37 -5
- package/dist/scripts/cli.js +31 -1
- package/dist/scripts/encrypt.js +178 -0
- package/dist/scripts/init.js +2 -0
- package/dist/scripts/launchers.js +91 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
**DazScript Framework** is a TypeScript toolkit for writing [Daz Studio](https://www.daz3d.com/daz-studio) scripts. It layers a full TypeScript development experience on top of [DAZ Script](https://docs.daz3d.com/public/software/dazstudio/4/referenceguide/scripting/start) (Qt Script / ECMAScript 5.1), and ships a fluent dialog builder so you can build UIs in code without touching the Qt widget API directly.
|
|
4
4
|
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Why use it?](#why-use-it)
|
|
8
|
+
- [Quick Start: Hello World](#quick-start-hello-world)
|
|
9
|
+
- [Quick Start: A Simple Dialog](#quick-start-a-simple-dialog)
|
|
10
|
+
- [Documentation](#documentation)
|
|
11
|
+
- [Installation & Setup](#installation--setup)
|
|
12
|
+
- [Project Configuration](#project-configuration)
|
|
13
|
+
- [The `action(...)` Entrypoint](#the-action-entrypoint)
|
|
14
|
+
- [Build Output: Launcher Shims](#build-output-launcher-shims)
|
|
15
|
+
- [Generated Setup Script](#generated-setup-script)
|
|
16
|
+
- [Setup Keyboard Shortcuts](#setup-keyboard-shortcuts)
|
|
17
|
+
- [Action-Level Bundles](#action-level-bundles)
|
|
18
|
+
- [Building UIs: Dialogs & Observables](#building-uis-dialogs--observables)
|
|
19
|
+
- [Observables](#observables)
|
|
20
|
+
- [Dialog Builder Reference](#dialog-builder-reference)
|
|
21
|
+
- [Available Helpers](#available-helpers)
|
|
22
|
+
- [Directory Structure](#directory-structure)
|
|
23
|
+
- [Development & Publishing](#development--publishing)
|
|
24
|
+
- [Resources](#resources)
|
|
25
|
+
- [Examples](#examples)
|
|
26
|
+
|
|
5
27
|
## Why use it?
|
|
6
28
|
|
|
7
29
|
DAZ Script gives you direct access to the entire Daz Studio API. The DazScript Framework builds on that foundation and adds:
|
|
@@ -10,7 +32,7 @@ DAZ Script gives you direct access to the entire Daz Studio API. The DazScript F
|
|
|
10
32
|
- **Fast UI development** — a fluent builder API lets you describe dialogs declaratively without touching the Qt widget API by hand.
|
|
11
33
|
- **Two-way data binding** — link your data model to UI controls so they stay in sync automatically. The user types in a field and your model updates; you update the model in code and the UI reflects it instantly. No manual synchronization needed.
|
|
12
34
|
- **One-command build** — `npm run build` compiles TypeScript to `.dsa` files that Daz Studio runs directly.
|
|
13
|
-
- **Stable launcher shims** — built scripts use a
|
|
35
|
+
- **Stable launcher shims** — built scripts use a launcher/implementation layout so iterating on your code never requires reinstalling actions in Daz Studio.
|
|
14
36
|
- **Automated installer generation** — `npm run installer` produces a full setup dialog by reading action metadata from your source code.
|
|
15
37
|
|
|
16
38
|
---
|
|
@@ -31,7 +53,7 @@ npm install dazscript-framework dazscript-types
|
|
|
31
53
|
npx dazscript init
|
|
32
54
|
```
|
|
33
55
|
|
|
34
|
-
Follow the prompt for your AppData author namespace (e.g. `YourName/my-project`). This creates `dazscript.config.ts`, `tsconfig.json`, and wires the `build`, `watch`, `icons`, and `installer` scripts into `package.json`.
|
|
56
|
+
Follow the prompt for your AppData author namespace (e.g. `YourName/my-project`). This creates `dazscript.config.ts`, `tsconfig.json`, and wires the `build`, `build:encrypted`, `watch`, `encrypt`, `icons`, and `installer` scripts into `package.json`.
|
|
35
57
|
|
|
36
58
|
### 3. Write the script
|
|
37
59
|
|
|
@@ -137,7 +159,7 @@ If `--app-data-path` is not provided, `init` prompts for the AppData author name
|
|
|
137
159
|
This generates:
|
|
138
160
|
- `dazscript.config.ts`
|
|
139
161
|
- `tsconfig.json`
|
|
140
|
-
- `package.json` script wiring for `build`, `watch`, `icons`, and `installer`
|
|
162
|
+
- `package.json` script wiring for `build`, `build:encrypted`, `watch`, `encrypt`, `icons`, and `installer`
|
|
141
163
|
|
|
142
164
|
Available `init` flags:
|
|
143
165
|
|
|
@@ -222,11 +244,21 @@ action({ text: 'My Script' }, MyScript);
|
|
|
222
244
|
Each built action produces two files:
|
|
223
245
|
|
|
224
246
|
- `out/<script>.dsa` — the stable **launcher** registered with Daz Studio (menus, toolbars, shortcuts)
|
|
225
|
-
- `out/<folder>/lib/<script-name
|
|
247
|
+
- `out/<folder>/lib/<script-name>/<script-name>.dsa` — the **implementation bundle** the launcher executes
|
|
226
248
|
|
|
227
249
|
When you rebuild, only the implementation bundle changes. The launcher path stays stable, so re-registering the action in Daz Studio is normally not required.
|
|
228
250
|
|
|
229
|
-
At runtime the launcher looks for
|
|
251
|
+
At runtime the launcher looks for a local encrypted `script.dse` bundle first, then the local `script.dsa` bundle, then the same encrypted/plain fallback paths under `App.getAppDataPath()/<appDataPath>`.
|
|
252
|
+
|
|
253
|
+
To encrypt implementation bundles before packaging, run the build and then call Daz Studio through the framework CLI:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
npx dazscript encrypt --out-dir ./out --daz-studio "C:/Program Files/DAZ 3D/DAZStudio4/DAZStudio.exe"
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The `encrypt` command launches Daz Studio with `-headless -noPrompt`, converts each implementation bundle under `out/**/lib/**/*.dsa` to a matching `.dse` file, and deletes the source `.dsa` after the matching encrypted file is written. Add `--keep-source` to leave the plain implementation bundles in place.
|
|
260
|
+
|
|
261
|
+
Individual script packages can wrap this command in `package.json` scripts such as `npm run encrypt` or `npm run build:encrypted` so release packaging does not depend on remembering the full Daz Studio executable argument.
|
|
230
262
|
|
|
231
263
|
---
|
|
232
264
|
|
package/dist/scripts/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ const readline = require('readline');
|
|
|
6
6
|
const { runWebpack } = require('./build');
|
|
7
7
|
const { loadConfig } = require('./config-loader');
|
|
8
8
|
const { copyIcons } = require('./icons');
|
|
9
|
+
const { runEncrypt } = require('./encrypt');
|
|
9
10
|
const { generateInstallerFiles } = require('./install-generator');
|
|
10
11
|
const { initProject } = require('./init');
|
|
11
12
|
|
|
@@ -16,14 +17,18 @@ Commands:
|
|
|
16
17
|
init Scaffold a DazScript project in the current directory
|
|
17
18
|
build Build DazScript files
|
|
18
19
|
watch Build and watch DazScript files
|
|
20
|
+
encrypt Encrypt built implementation bundles through Daz Studio
|
|
19
21
|
icons Copy png assets into the output directory
|
|
20
22
|
installer Generate Install.dsa.ts and Uninstall.dsa.ts
|
|
21
23
|
|
|
22
|
-
Options
|
|
24
|
+
Options:
|
|
23
25
|
--menu-path <path> Default menu path. Default: /MyScripts
|
|
24
26
|
--scripts-path <path> Source directory to scan. Default: ./src
|
|
25
27
|
--out-dir <path> Build output directory. Default: ./out
|
|
26
28
|
--app-data-path <path> AppData namespace used by launcher fallbacks. Example: Author/Product
|
|
29
|
+
--daz-studio <path> Daz Studio executable for encrypt
|
|
30
|
+
--keep-source Keep source script.dsa files after encrypting
|
|
31
|
+
--timeout-ms <value> Daz Studio encrypt timeout. Default: 300000
|
|
27
32
|
--force Overwrite generated files
|
|
28
33
|
--help Show this message
|
|
29
34
|
`);
|
|
@@ -110,6 +115,23 @@ function parseOptions(args, defaults) {
|
|
|
110
115
|
continue;
|
|
111
116
|
}
|
|
112
117
|
|
|
118
|
+
if (arg === '--daz-studio') {
|
|
119
|
+
options.dazStudio = args[index + 1];
|
|
120
|
+
index += 1;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (arg === '--keep-source') {
|
|
125
|
+
options.keepSource = true;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (arg === '--timeout-ms') {
|
|
130
|
+
options.timeoutMs = Number(args[index + 1]);
|
|
131
|
+
index += 1;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
113
135
|
if (arg === '--file') {
|
|
114
136
|
options.file = args[index + 1];
|
|
115
137
|
index += 1;
|
|
@@ -158,6 +180,9 @@ async function main(argv) {
|
|
|
158
180
|
outDir: undefined,
|
|
159
181
|
appDataPath: undefined,
|
|
160
182
|
file: undefined,
|
|
183
|
+
dazStudio: undefined,
|
|
184
|
+
keepSource: false,
|
|
185
|
+
timeoutMs: undefined,
|
|
161
186
|
});
|
|
162
187
|
|
|
163
188
|
if (options.help) {
|
|
@@ -192,6 +217,11 @@ async function main(argv) {
|
|
|
192
217
|
return;
|
|
193
218
|
}
|
|
194
219
|
|
|
220
|
+
if (command === 'encrypt') {
|
|
221
|
+
runEncrypt(workdir, resolvedOptions);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
195
225
|
if (command === 'icons') {
|
|
196
226
|
copyIcons(workdir, resolvedOptions);
|
|
197
227
|
return;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
function toDazPath(filePath) {
|
|
9
|
+
return path.resolve(filePath).replace(/\\/g, '/');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function findImplementationScripts(dir) {
|
|
13
|
+
const scripts = [];
|
|
14
|
+
|
|
15
|
+
function visit(currentDir) {
|
|
16
|
+
if (!fs.existsSync(currentDir)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (const entry of fs.readdirSync(currentDir, { withFileTypes: true })) {
|
|
21
|
+
const entryPath = path.join(currentDir, entry.name);
|
|
22
|
+
|
|
23
|
+
if (entry.isDirectory()) {
|
|
24
|
+
visit(entryPath);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
entry.isFile() &&
|
|
30
|
+
entry.name.endsWith('.dsa') &&
|
|
31
|
+
entryPath.split(path.sep).includes('lib')
|
|
32
|
+
) {
|
|
33
|
+
scripts.push(entryPath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
visit(dir);
|
|
39
|
+
return scripts;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function makeConverterScript() {
|
|
43
|
+
return [
|
|
44
|
+
'(function(){',
|
|
45
|
+
' function log(message) { print("[dazscript encrypt] " + message); }',
|
|
46
|
+
' function fail(message) {',
|
|
47
|
+
' print("[dazscript encrypt] ERROR " + message);',
|
|
48
|
+
' App.quit();',
|
|
49
|
+
' }',
|
|
50
|
+
' function splitList(value) {',
|
|
51
|
+
' if (!value) return [];',
|
|
52
|
+
' return String(value).split("|");',
|
|
53
|
+
' }',
|
|
54
|
+
' function removeSourceFile(sourcePath) {',
|
|
55
|
+
' var sourceFile = new DzFile(sourcePath);',
|
|
56
|
+
' if (sourceFile.exists() && !sourceFile.remove()) {',
|
|
57
|
+
' log("warning: encrypted but could not delete " + sourcePath);',
|
|
58
|
+
' }',
|
|
59
|
+
' sourceFile.deleteLater();',
|
|
60
|
+
' }',
|
|
61
|
+
' var args = App.scriptArgs;',
|
|
62
|
+
' var sourceList = splitList(args[0]);',
|
|
63
|
+
' var deleteSources = String(args[1]) == "delete";',
|
|
64
|
+
' if (!sourceList.length) {',
|
|
65
|
+
' log("no implementation scripts found");',
|
|
66
|
+
' App.quit();',
|
|
67
|
+
' return;',
|
|
68
|
+
' }',
|
|
69
|
+
' var failures = 0;',
|
|
70
|
+
' for (var i = 0; i < sourceList.length; i += 1) {',
|
|
71
|
+
' var sourcePath = sourceList[i];',
|
|
72
|
+
' var destPath = sourcePath.replace(/\\.dsa$/i, ".dse");',
|
|
73
|
+
' var script = new DzScript();',
|
|
74
|
+
' log("encrypt " + sourcePath);',
|
|
75
|
+
' if (!script.loadFromFile(sourcePath)) {',
|
|
76
|
+
' failures += 1;',
|
|
77
|
+
' log("failed to load " + sourcePath);',
|
|
78
|
+
' script.deleteLater();',
|
|
79
|
+
' continue;',
|
|
80
|
+
' }',
|
|
81
|
+
' if (!script.checkSyntax()) {',
|
|
82
|
+
' failures += 1;',
|
|
83
|
+
' log("syntax error in " + sourcePath + " line " + script.errorLine() + ": " + script.errorMessage());',
|
|
84
|
+
' script.deleteLater();',
|
|
85
|
+
' continue;',
|
|
86
|
+
' }',
|
|
87
|
+
' var writeError = script.saveFile(destPath, DzScript.EncDAZScriptFile);',
|
|
88
|
+
' script.deleteLater();',
|
|
89
|
+
' if (Number(writeError) != 0) {',
|
|
90
|
+
' failures += 1;',
|
|
91
|
+
' log("failed to save " + destPath + " error=" + writeError);',
|
|
92
|
+
' continue;',
|
|
93
|
+
' }',
|
|
94
|
+
' if (deleteSources) {',
|
|
95
|
+
' removeSourceFile(sourcePath);',
|
|
96
|
+
' }',
|
|
97
|
+
' log("wrote " + destPath);',
|
|
98
|
+
' }',
|
|
99
|
+
' if (failures) {',
|
|
100
|
+
' fail(String(failures) + " script(s) failed");',
|
|
101
|
+
' return;',
|
|
102
|
+
' }',
|
|
103
|
+
' log("complete");',
|
|
104
|
+
' App.quit();',
|
|
105
|
+
'})();',
|
|
106
|
+
'',
|
|
107
|
+
].join('\n');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function runEncrypt(workdir, options) {
|
|
111
|
+
if (!options.dazStudio) {
|
|
112
|
+
throw new Error('Missing required option: --daz-studio <path>');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const outDir = path.resolve(workdir, options.outDir || './out');
|
|
116
|
+
const dazStudioPath = path.resolve(workdir, options.dazStudio);
|
|
117
|
+
|
|
118
|
+
if (!fs.existsSync(dazStudioPath)) {
|
|
119
|
+
throw new Error(`Daz Studio executable not found: ${dazStudioPath}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!fs.existsSync(outDir)) {
|
|
123
|
+
throw new Error(`Output directory not found: ${outDir}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const implementationScripts = findImplementationScripts(outDir);
|
|
127
|
+
if (!implementationScripts.length) {
|
|
128
|
+
console.log(`[dazscript encrypt] no implementation scripts found under ${outDir}`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dazscript-encrypt-'));
|
|
133
|
+
const converterPath = path.join(tempDir, 'encrypt-output.dsa');
|
|
134
|
+
fs.writeFileSync(converterPath, makeConverterScript(), 'utf8');
|
|
135
|
+
|
|
136
|
+
const args = [
|
|
137
|
+
'-headless',
|
|
138
|
+
'-noPrompt',
|
|
139
|
+
'-scriptArg',
|
|
140
|
+
implementationScripts.map(toDazPath).join('|'),
|
|
141
|
+
'-scriptArg',
|
|
142
|
+
options.keepSource ? 'keep' : 'delete',
|
|
143
|
+
toDazPath(converterPath),
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
console.log(`[dazscript encrypt] encrypting ${implementationScripts.length} implementation script(s)`);
|
|
147
|
+
const result = spawnSync(dazStudioPath, args, {
|
|
148
|
+
encoding: 'utf8',
|
|
149
|
+
stdio: 'inherit',
|
|
150
|
+
timeout: options.timeoutMs || 300000,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
154
|
+
|
|
155
|
+
if (result.error) {
|
|
156
|
+
throw result.error;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (result.status !== 0) {
|
|
160
|
+
throw new Error(`Daz Studio exited with code ${result.status}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const missingOutputs = implementationScripts.filter((scriptPath) => {
|
|
164
|
+
const encryptedPath = scriptPath.replace(/\.dsa$/i, '.dse');
|
|
165
|
+
return !fs.existsSync(encryptedPath);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (missingOutputs.length) {
|
|
169
|
+
throw new Error(
|
|
170
|
+
'Daz Studio did not produce encrypted output for:\n' +
|
|
171
|
+
missingOutputs.map((scriptPath) => ` ${scriptPath}`).join('\n')
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
runEncrypt,
|
|
178
|
+
};
|
package/dist/scripts/init.js
CHANGED
|
@@ -93,8 +93,10 @@ function updatePackageJson(workdir, options) {
|
|
|
93
93
|
...(packageJson.scripts || {}),
|
|
94
94
|
prebuild: 'npm run installer',
|
|
95
95
|
build: 'dazscript build',
|
|
96
|
+
'build:encrypted': 'npm run build && npm run encrypt',
|
|
96
97
|
postbuild: 'npm run icons',
|
|
97
98
|
watch: 'dazscript watch',
|
|
99
|
+
encrypt: 'dazscript encrypt --out-dir ./out --daz-studio "C:\\Program Files\\DAZ 3D\\DAZStudio4\\DAZStudio.exe"',
|
|
98
100
|
icons: 'dazscript icons',
|
|
99
101
|
installer: 'dazscript installer',
|
|
100
102
|
};
|
|
@@ -16,17 +16,40 @@ function getActionOutputPath(workdir, outDir, sourceFile) {
|
|
|
16
16
|
return relativeSourceFile.replace(/\.ts$/, '');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function getImplementationRelativePath(outputRelativePath) {
|
|
19
|
+
function getImplementationRelativePath(outputRelativePath, extension = 'dsa') {
|
|
20
20
|
const outputDirectory = path.posix.dirname(outputRelativePath);
|
|
21
21
|
const outputBaseName = path.posix.basename(outputRelativePath, '.dsa');
|
|
22
22
|
const implementationDirectory = outputDirectory === '.'
|
|
23
23
|
? path.posix.join('lib', outputBaseName)
|
|
24
24
|
: path.posix.join(outputDirectory, 'lib', outputBaseName);
|
|
25
25
|
|
|
26
|
-
return path.posix.join(implementationDirectory,
|
|
26
|
+
return path.posix.join(implementationDirectory, `${outputBaseName}.${extension}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getFlatImplementationRelativePath(outputRelativePath, extension = 'dsa') {
|
|
30
|
+
const outputDirectory = path.posix.dirname(outputRelativePath);
|
|
31
|
+
const outputBaseName = path.posix.basename(outputRelativePath, '.dsa');
|
|
32
|
+
const implementationDirectory = outputDirectory === '.'
|
|
33
|
+
? 'lib'
|
|
34
|
+
: path.posix.join(outputDirectory, 'lib');
|
|
35
|
+
|
|
36
|
+
return path.posix.join(implementationDirectory, `${outputBaseName}.${extension}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getLegacyImplementationRelativePath(outputRelativePath, extension = 'dsa') {
|
|
40
|
+
const outputDirectory = path.posix.dirname(outputRelativePath);
|
|
41
|
+
const outputBaseName = path.posix.basename(outputRelativePath, '.dsa');
|
|
42
|
+
const implementationDirectory = outputDirectory === '.'
|
|
43
|
+
? path.posix.join('lib', outputBaseName)
|
|
44
|
+
: path.posix.join(outputDirectory, 'lib', outputBaseName);
|
|
45
|
+
|
|
46
|
+
return path.posix.join(implementationDirectory, `script.${extension}`);
|
|
27
47
|
}
|
|
28
48
|
|
|
29
49
|
function makeLauncherSource(implementationRelativePath, appDataImplementationRelativePath) {
|
|
50
|
+
const encryptedImplementationRelativePath = implementationRelativePath.replace(/\.dsa$/, '.dse');
|
|
51
|
+
const encryptedAppDataImplementationRelativePath = appDataImplementationRelativePath.replace(/\.dsa$/, '.dse');
|
|
52
|
+
|
|
30
53
|
return [
|
|
31
54
|
'// Auto-generated launcher shim.',
|
|
32
55
|
'// The installed Daz action points at this stable file.',
|
|
@@ -34,7 +57,9 @@ function makeLauncherSource(implementationRelativePath, appDataImplementationRel
|
|
|
34
57
|
'// and from the AppData fallback location second.',
|
|
35
58
|
'',
|
|
36
59
|
`var implementationRelativePath = '${implementationRelativePath}';`,
|
|
60
|
+
`var encryptedImplementationRelativePath = '${encryptedImplementationRelativePath}';`,
|
|
37
61
|
`var appDataImplementationRelativePath = '${appDataImplementationRelativePath}';`,
|
|
62
|
+
`var encryptedAppDataImplementationRelativePath = '${encryptedAppDataImplementationRelativePath}';`,
|
|
38
63
|
'var launcherFileName = getScriptFileName();',
|
|
39
64
|
'var launcherInfo = new DzFileInfo(launcherFileName);',
|
|
40
65
|
'var launcherDirectory = typeof launcherInfo.canonicalPath == "function"',
|
|
@@ -42,10 +67,20 @@ function makeLauncherSource(implementationRelativePath, appDataImplementationRel
|
|
|
42
67
|
' : launcherInfo.path();',
|
|
43
68
|
'launcherInfo.deleteLater();',
|
|
44
69
|
'',
|
|
45
|
-
"var implementationPath = launcherDirectory + '/' +
|
|
70
|
+
"var implementationPath = launcherDirectory + '/' + encryptedImplementationRelativePath;",
|
|
46
71
|
'var implementationFile = new DzFile(implementationPath);',
|
|
47
72
|
'if (!implementationFile.exists()) {',
|
|
48
73
|
' implementationFile.deleteLater();',
|
|
74
|
+
" implementationPath = launcherDirectory + '/' + implementationRelativePath;",
|
|
75
|
+
' implementationFile = new DzFile(implementationPath);',
|
|
76
|
+
'}',
|
|
77
|
+
'if (!implementationFile.exists()) {',
|
|
78
|
+
' implementationFile.deleteLater();',
|
|
79
|
+
" implementationPath = App.getAppDataPath() + '/' + encryptedAppDataImplementationRelativePath;",
|
|
80
|
+
' implementationFile = new DzFile(implementationPath);',
|
|
81
|
+
'}',
|
|
82
|
+
'if (!implementationFile.exists()) {',
|
|
83
|
+
' implementationFile.deleteLater();',
|
|
49
84
|
" implementationPath = App.getAppDataPath() + '/' + appDataImplementationRelativePath;",
|
|
50
85
|
' implementationFile = new DzFile(implementationPath);',
|
|
51
86
|
'}',
|
|
@@ -74,6 +109,14 @@ function ensureParentDir(filePath) {
|
|
|
74
109
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
75
110
|
}
|
|
76
111
|
|
|
112
|
+
function removeEmptyDir(dirPath) {
|
|
113
|
+
try {
|
|
114
|
+
fs.rmdirSync(dirPath);
|
|
115
|
+
} catch (_err) {
|
|
116
|
+
// Directory is missing or still contains user/generated files.
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
77
120
|
function createActionLaunchers(workdir, options) {
|
|
78
121
|
const outDir = path.resolve(workdir, options.outDir || './out');
|
|
79
122
|
const appDataPath = validateAppDataPath(options.appDataPath, workdir);
|
|
@@ -86,15 +129,60 @@ function createActionLaunchers(workdir, options) {
|
|
|
86
129
|
const launcherPath = path.join(outDir, outputRelativePath);
|
|
87
130
|
const implementationRelativePath = getImplementationRelativePath(outputRelativePath);
|
|
88
131
|
const implementationPath = path.join(outDir, implementationRelativePath);
|
|
132
|
+
const encryptedImplementationPath = path.join(
|
|
133
|
+
outDir,
|
|
134
|
+
getImplementationRelativePath(outputRelativePath, 'dse')
|
|
135
|
+
);
|
|
136
|
+
const legacyImplementationPath = path.join(
|
|
137
|
+
outDir,
|
|
138
|
+
getLegacyImplementationRelativePath(outputRelativePath)
|
|
139
|
+
);
|
|
140
|
+
const legacyEncryptedImplementationPath = path.join(
|
|
141
|
+
outDir,
|
|
142
|
+
getLegacyImplementationRelativePath(outputRelativePath, 'dse')
|
|
143
|
+
);
|
|
144
|
+
const flatImplementationPath = path.join(
|
|
145
|
+
outDir,
|
|
146
|
+
getFlatImplementationRelativePath(outputRelativePath)
|
|
147
|
+
);
|
|
148
|
+
const flatEncryptedImplementationPath = path.join(
|
|
149
|
+
outDir,
|
|
150
|
+
getFlatImplementationRelativePath(outputRelativePath, 'dse')
|
|
151
|
+
);
|
|
89
152
|
|
|
90
153
|
if (!fs.existsSync(launcherPath)) {
|
|
91
154
|
return;
|
|
92
155
|
}
|
|
93
156
|
|
|
157
|
+
if (path.resolve(launcherPath) === path.resolve(implementationPath)) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`[dazscript] Launcher path collides with implementation path: ${implementationRelativePath}. ` +
|
|
160
|
+
`Move the source action out of a lib/ folder or use a different script name.`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
94
164
|
ensureParentDir(implementationPath);
|
|
95
165
|
if (fs.existsSync(implementationPath)) {
|
|
96
166
|
fs.unlinkSync(implementationPath);
|
|
97
167
|
}
|
|
168
|
+
if (fs.existsSync(encryptedImplementationPath)) {
|
|
169
|
+
fs.unlinkSync(encryptedImplementationPath);
|
|
170
|
+
}
|
|
171
|
+
if (fs.existsSync(legacyImplementationPath)) {
|
|
172
|
+
fs.unlinkSync(legacyImplementationPath);
|
|
173
|
+
}
|
|
174
|
+
if (fs.existsSync(legacyEncryptedImplementationPath)) {
|
|
175
|
+
fs.unlinkSync(legacyEncryptedImplementationPath);
|
|
176
|
+
}
|
|
177
|
+
if (fs.existsSync(flatImplementationPath)) {
|
|
178
|
+
fs.unlinkSync(flatImplementationPath);
|
|
179
|
+
}
|
|
180
|
+
if (fs.existsSync(flatEncryptedImplementationPath)) {
|
|
181
|
+
fs.unlinkSync(flatEncryptedImplementationPath);
|
|
182
|
+
}
|
|
183
|
+
if (path.resolve(path.dirname(legacyImplementationPath)) !== path.resolve(path.dirname(implementationPath))) {
|
|
184
|
+
removeEmptyDir(path.dirname(legacyImplementationPath));
|
|
185
|
+
}
|
|
98
186
|
|
|
99
187
|
fs.renameSync(launcherPath, implementationPath);
|
|
100
188
|
|