readme, license and scripts

This commit is contained in:
Joseph HENRY 2025-11-17 17:58:05 +01:00
parent 5e6b69af34
commit 95e760d1d3
13 changed files with 156 additions and 438 deletions

9
LICENSE.md Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2025 Autour du Volcan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

123
README.md
View File

@ -1,10 +1,22 @@
# tb-harmony-modern-ts # tb-harmony-modern-ts
This repository is a project template that allows you to code in modern TypeScript for ToonBoom Harmony. ![](./img/toonboom.png) ![](https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white) ![](https://img.shields.io/badge/Webpack-8DD6F9?style=for-the-badge&logo=Webpack&logoColor=white) ![](https://img.shields.io/badge/Babel-F9DC3E?style=for-the-badge&logo=babel&logoColor=white)
This repository is a project template that allows you to code in modern TypeScript (ES6) for ToonBoom Harmony.
## Example script ## Example script
This script prints all the nodes recursively (following node groups) in the scene using JavaScript generators:
```ts ```ts
// src/lib/console.ts
const console = { log: MessageLog.trace };
```
```ts
// src/scripts/generator.ts
import console from "../lib/console";
function* recursiveIterNodes(n: string): Generator<string> { function* recursiveIterNodes(n: string): Generator<string> {
yield n; yield n;
if (node.isGroup(n)) { if (node.isGroup(n)) {
@ -31,16 +43,86 @@ You can script in two ways for ToonBoom Harmony: either with [Python](https://do
[QtScript](https://doc.qt.io/archives/qt-5.15/qtscript-index.html) (scripting engine part of the Qt framework) is an old JavaScript dialect that is based on the [ECMAScript 3.0 standard](https://www-archive.mozilla.org/js/language/e262-3.pdf), therefore it lacks features like modules, modern syntax, arrow functions, etc... [QtScript](https://doc.qt.io/archives/qt-5.15/qtscript-index.html) (scripting engine part of the Qt framework) is an old JavaScript dialect that is based on the [ECMAScript 3.0 standard](https://www-archive.mozilla.org/js/language/e262-3.pdf), therefore it lacks features like modules, modern syntax, arrow functions, etc...
Today we have [TypeScript](https://www.typescriptlang.org/) which is a superset of JavaScript with syntax for types, ES modules, async/await and more but how can we use those? Today we have [TypeScript](https://www.typescriptlang.org/) which is a superset of JavaScript with syntax for types, ES modules, async/await. All those features provide better code organization, type checking and robustness.
## Usage
This template was built in a script-centric workflow. All the `.ts` scripts in the `src/scripts` directory are entrypoints and built into the `dist` directory as `.js` bundles.
1. Clone and install the dependencies:
```shell
git clone https://git.autourdeminuit.com/autour_de_minuit/tb-harmony-modern-ts
cd tb-harmony-modern-ts
npm install
```
2. Then create a new script in `src/scripts`:
```shell
touch src/scripts/arrow-function.ts
```
```ts
// src/scripts/arrow-function.ts
const hello = (name: string) => MessageLog.trace(`Hello, ${name}!`);
hello("Alice");
```
3. And build it:
```shell
npm run build # runs webpack
```
Then it's built as an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) and transpiled into QtScript compatible syntax:
```js
// dist/arrow-function.js
/******/ (function () {
// webpackBootstrap
var hello = function hello(name) {
return MessageLog.trace("Hello, ".concat(name, "!"));
};
hello("Alice");
/******/
})();
```
Then you can run it by starting Harmony with the `TOONBOOM_GLOBAL_SCRIPT_LOCATION` env variable pointing at the `dist` folder where you cloned this repo.
For example you can also run this script from the command line in [batch mode](https://docs.toonboom.com/help/harmony-24/scripting/script/index.html#batch_mode) (in PowerShell):
```powershell
$env:TOONBOOM_GLOBAL_SCRIPT_LOCATION="tb-harmony-modern-ts/dist"
&"path\to\HarmonyPremium.exe" -scene "scene.xstage" -batch -compile "dist/arrow-function.js"
# ...
# Loading script: tb-harmony-modern-ts\dist\arrow-function.js
# Hello, Alice!
```
## How ## How
Based on the above example, here is a diagram that shows the compilation/transpilation process (simplified):
![](./img/tb_ts_compilation_diagram.png)
### TypeScript and type definitions ### TypeScript and type definitions
We can code in TypeScript but in order to use Harmony's QtScript API, we need type definitions (`.d.ts` files describing the types). We can code in TypeScript but in order to use Harmony's QtScript API, we need type definitions (`.d.ts` files describing the types).
Luckily for us, Bryan Fordney made scripts to generate them: [tba-types](https://github.com/bryab/tba-types) (Typescript definitions for Toon Boom Harmony and Storyboard Pro) Luckily for us, Bryan Fordney made scripts to generate them: [tba-types](https://github.com/bryab/tba-types) (Typescript definitions for Toon Boom Harmony and Storyboard Pro)
We can now type-check our code with the right classes and members accessible in the global QtScript scope. Those type definitions still have a few quirks but they can be improved through PRs!
### ES6 syntax and polyfill
The JavaScript language specification is moving fast. What if you want to use the newest features but your runtime isn't as recent? Here comes [Babel](https://babeljs.io/), it's a JavaScript compiler that allows us to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
This is perfect because QtScript is like ES3 and we want to use ES6 features.
A key feature of Babel is that it integrates with [core-js](https://github.com/zloirock/core-js), providing polyfills for modern JavaScript features. For example QtScript don't have `async`/`await` but core-js can inject the [Regenerator runtime](https://www.npmjs.com/package/regenerator-runtime) to make it work.
### Modules and imports ### Modules and imports
In Harmony's QtScript you can import code from another file in two ways: In Harmony's QtScript you can import code from another file in two ways:
@ -70,4 +152,39 @@ module.test();
Which is a [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules) "like" custom implementation from ToonBoom without the same semantics. It's also used to define [ToonBoom packages](https://docs.toonboom.com/help/harmony-24/scripting/extended/index.html#create_package) by exporting a `configure` function from a `configure.js` file. Which is a [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules) "like" custom implementation from ToonBoom without the same semantics. It's also used to define [ToonBoom packages](https://docs.toonboom.com/help/harmony-24/scripting/extended/index.html#create_package) by exporting a `configure` function from a `configure.js` file.
-> In today's modern JavaScript, the official standard package format is [ECMAScript modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) (or ESM/ES6 modules) with `import`/`export`. In today's modern JavaScript, the official standard package format is [ECMAScript modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules) (or ESM/ES6 modules) with `import`/`export`.
### Module bundling
We use WebPack as the [module bundler](https://webpack.js.org/concepts/). This is a common technique to organize and combine many files into a single JavaScript file. It resolves imports and optimize the bundles.
Since ToonBoom Harmony's QtScript module system is not that advanced, it allows us to use ES modules (and CommonJS too) to split code into separate files without having to manually import files.
This also means that we can use and import NPM packages with Harmony! (if they use a compatible standard library thought).
#### QtScript syntax fixes (custom Webpack plugin)
In QtScript, this syntax is not valid:
```js
var obj = { for: 0 }; // Unexpected keyword "for" for literal property name
obj.for = 1; // Same here as property name
```
```js
var re = /[^\s(/]/; // Syntax error, / is not escaped
// The correct syntax is /[^\s(\/]/
```
Most of the time, those expressions are injected from corejs polyfills. In order to patch this, I created a custom [`FindReplacePlugin`](./webpack.config.ts) for Webpack that does simple regex find/replace to fix those syntax errors.
## Acknowledgements
- [OpenHarmony](https://cfourney.github.io/OpenHarmony/) - The Toonboom Harmony Open Source DOM Library created by Mathieu Chaptel and Chris Fourney.
This library is like PyMEL but for ToonBoom Harmony and a huge source of knowledge about the details of scripting in Harmony. 🙏
- [tba-types](https://github.com/bryab/tba-types) - Typescript definitions for Toon Boom Harmony and Storyboard Pro created by Bryan Fordney.
These are generated types scrapped from the ToonBoom documentation itself.
## License
[MIT](./LICENSE.md)

View File

@ -1,42 +0,0 @@
import babelLoader from "babel-loader";
import { ConfigItem } from "@babel/core";
export default babelLoader.custom(() => {
// Extract the custom options in the custom plugin
function myPlugin() {
return {
visitor: {},
};
}
return {
// Passed the loader options.
// customOptions({ opt1, opt2, ...loader }) {
// return {
// // Pull out any custom options that the loader might have.
// custom: { opt1, opt2 },
//
// // Pass the options back with the two custom options removed.
// loader,
// };
// },
// Passed Babel's 'PartialConfig' object.
config(cfg: ConfigItem) {
return {
...cfg.options,
plugins: [
...((cfg.options && cfg.options["plugins"]) || []),
[myPlugin],
],
};
},
// result(result) {
// return {
// ...result,
// code: result.code + "\n// Generated by some custom loader",
// };
// },
};
});

View File

@ -1,24 +0,0 @@
// Example from: https://github.com/babel/babel/blob/main/packages/babel-plugin-transform-reserved-words/src/index.ts
import { declare } from "@babel/helper-plugin-utils";
import { types as t, type NodePath } from "@babel/core";
import { isIdentifierName } from "@babel/helper-validator-identifier";
const QT_SCRIPT_RESERVED_WORDS = new Set(["for"]);
function isQtScriptReservedWord(name: string): boolean {
return isIdentifierName(name) && QT_SCRIPT_RESERVED_WORDS.has(name);
}
export default declare((_api) => {
return {
name: "test",
visitor: {
Identifier(path: NodePath<t.Identifier>) {
if (isQtScriptReservedWord(path.node.name)) {
console.log(path.node.name);
path.scope.rename(path.node.name);
}
},
},
};
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
img/toonboom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

328
package-lock.json generated
View File

@ -8,22 +8,15 @@
"name": "tb-harmony-modern-ts", "name": "tb-harmony-modern-ts",
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": {
"axios": "^1.13.2"
},
"devDependencies": { "devDependencies": {
"@babel/core": "^7.28.5", "@babel/core": "^7.28.5",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/preset-env": "^7.28.5", "@babel/preset-env": "^7.28.5",
"@babel/preset-typescript": "^7.28.5", "@babel/preset-typescript": "^7.28.5",
"@types/babel__helper-plugin-utils": "^7.10.3", "@types/node": "^24.10.1",
"@types/babel__helper-validator-identifier": "^7.15.2",
"@types/node": "^24.10.0",
"@types/webpack": "^5.28.5", "@types/webpack": "^5.28.5",
"babel-loader": "^10.0.0", "babel-loader": "^10.0.0",
"core-js": "^3.46.0", "core-js": "^3.46.0",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"replace-text-in-bundle-plugin": "^1.0.3",
"tba-types": "github:bryab/tba-types", "tba-types": "github:bryab/tba-types",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
@ -1748,68 +1741,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7",
"@types/babel__generator": "*",
"@types/babel__template": "*",
"@types/babel__traverse": "*"
}
},
"node_modules/@types/babel__generator": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
"integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__helper-plugin-utils": {
"version": "7.10.3",
"resolved": "https://registry.npmjs.org/@types/babel__helper-plugin-utils/-/babel__helper-plugin-utils-7.10.3.tgz",
"integrity": "sha512-FcLBBPXInqKfULB2nvOBskQPcnSMZ0s1Y2q76u9H1NPPWaLcTeq38xBeKfF/RBUECK333qeaqRdYoPSwW7rTNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/babel__core": "*"
}
},
"node_modules/@types/babel__helper-validator-identifier": {
"version": "7.15.2",
"resolved": "https://registry.npmjs.org/@types/babel__helper-validator-identifier/-/babel__helper-validator-identifier-7.15.2.tgz",
"integrity": "sha512-l3dkwCt890NFhMwPKXbxsWXC0Por0/+KaFIiQP1j38/vWSH2P3Tn6m+IuJHkx2SBI3VLFqincFe9JtBk2NFHOw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/babel__template": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__traverse": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
"integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.2"
}
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "9.6.1", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
@ -1847,9 +1778,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "24.10.0", "version": "24.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
"integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2184,23 +2115,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/babel-loader": { "node_modules/babel-loader": {
"version": "10.0.0", "version": "10.0.0",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz",
@ -2311,19 +2225,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001753", "version": "1.0.30001753",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001753.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001753.tgz",
@ -2377,18 +2278,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": { "node_modules/commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@ -2487,15 +2376,6 @@
} }
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/diff": { "node_modules/diff": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@ -2506,20 +2386,6 @@
"node": ">=0.3.1" "node": ">=0.3.1"
} }
}, },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.245", "version": "1.5.245",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.245.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.245.tgz",
@ -2554,24 +2420,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-module-lexer": { "node_modules/es-module-lexer": {
"version": "1.7.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
@ -2579,33 +2427,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escalade": { "node_modules/escalade": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@ -2744,46 +2565,11 @@
"flat": "cli.js" "flat": "cli.js"
} }
}, },
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
@ -2799,43 +2585,6 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/glob-to-regexp": { "node_modules/glob-to-regexp": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
@ -2843,18 +2592,6 @@
"dev": true, "dev": true,
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@ -2872,37 +2609,11 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
@ -3113,15 +2824,6 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -3133,6 +2835,7 @@
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -3142,6 +2845,7 @@
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"mime-db": "1.52.0" "mime-db": "1.52.0"
@ -3326,12 +3030,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/randombytes": { "node_modules/randombytes": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@ -3413,16 +3111,6 @@
"regjsparser": "bin/parser" "regjsparser": "bin/parser"
} }
}, },
"node_modules/replace-text-in-bundle-plugin": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/replace-text-in-bundle-plugin/-/replace-text-in-bundle-plugin-1.0.3.tgz",
"integrity": "sha512-DZJgonL3NaB6Sz1ti3bJQrKNRvt/YMWHxMPeQo0eA5742Tct98tpzjIqsOsjYJJAlXJ8diy8Q0uzzasOSKAlmQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"webpack": "^5.85.0"
}
},
"node_modules/require-from-string": { "node_modules/require-from-string": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",

View File

@ -13,25 +13,18 @@
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.28.5", "@babel/core": "^7.28.5",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/preset-env": "^7.28.5", "@babel/preset-env": "^7.28.5",
"@babel/preset-typescript": "^7.28.5", "@babel/preset-typescript": "^7.28.5",
"@types/babel__helper-plugin-utils": "^7.10.3", "@types/node": "^24.10.1",
"@types/babel__helper-validator-identifier": "^7.15.2",
"@types/node": "^24.10.0",
"@types/webpack": "^5.28.5", "@types/webpack": "^5.28.5",
"babel-loader": "^10.0.0", "babel-loader": "^10.0.0",
"core-js": "^3.46.0", "core-js": "^3.46.0",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"replace-text-in-bundle-plugin": "^1.0.3",
"tba-types": "github:bryab/tba-types", "tba-types": "github:bryab/tba-types",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"webpack": "^5.102.1", "webpack": "^5.102.1",
"webpack-cli": "^6.0.1" "webpack-cli": "^6.0.1"
},
"dependencies": {
"axios": "^1.13.2"
} }
} }

2
src/lib/console.ts Normal file
View File

@ -0,0 +1,2 @@
const console = { log: MessageLog.trace };
export default console;

View File

@ -0,0 +1,2 @@
const hello = (name: string) => MessageLog.trace(`Hello, ${name}!`);
hello("Alice");

View File

@ -1,4 +1,4 @@
const console = { log: MessageLog.trace }; import console from "../lib/console";
function* recursiveIterNodes(n: string): Generator<string> { function* recursiveIterNodes(n: string): Generator<string> {
yield n; yield n;

View File

@ -1,33 +0,0 @@
class Node {
name: string;
constructor(name: string) {
this.name = name;
}
static root() {
return new Node(node.root());
}
get isGroup() {
return node.isGroup(this.name);
}
*subNodesRecursive(): Generator<Node> {
for (let i = 0; i < node.numberOfSubNodes(this.name); i++) {
const subNode = new Node(node.subNode(this.name, i));
yield subNode;
yield* subNode.subNodesRecursive();
}
}
}
function main() {
const root = Node.root();
for (const node of root.subNodesRecursive()) {
MessageLog.trace(node.name);
}
}
main();

View File

@ -38,12 +38,11 @@ class FindReplacePlugin {
// For every regex pattern, replace it in the source content // For every regex pattern, replace it in the source content
for (const { from, to } of this.options.replace) { for (const { from, to } of this.options.replace) {
const matches = replaced.match(from); const matches = replaced.match(from);
logger.info(
from, if (matches) {
to, matches[0];
`Found ${matches ? matches.length : 0} matches`, logger.info(`${from} | Found ${matches.length} matches`);
matches, }
);
replaced = replaced.replace(from, to); replaced = replaced.replace(from, to);
} }
@ -68,12 +67,15 @@ class FindReplacePlugin {
const babelRule: RuleSetRule = { const babelRule: RuleSetRule = {
test: /\.(ts|js)$/, test: /\.(ts|js)$/,
// Excluding node_modules is really important to avoid Babel injecting corejs in corejs files themselves
exclude: /node_modules/,
use: { use: {
loader: "babel-loader", loader: "babel-loader",
options: { options: {
targets: "defaults", targets: "defaults",
sourceType: "unambiguous", sourceType: "unambiguous",
presets: [ presets: [
// Parse TypeScript
["@babel/preset-typescript"], ["@babel/preset-typescript"],
[ [
"@babel/preset-env", "@babel/preset-env",
@ -81,6 +83,7 @@ const babelRule: RuleSetRule = {
// Use this to cover the lowest possible syntax requirement for QtScript // Use this to cover the lowest possible syntax requirement for QtScript
// See: https://browsersl.ist/ // See: https://browsersl.ist/
targets: "cover 100%", targets: "cover 100%",
// Adds at the top of each file imports of polyfills only for features used in the current and not supported by target environments
useBuiltIns: "usage", useBuiltIns: "usage",
corejs: "3.46.0", corejs: "3.46.0",
}, },
@ -133,7 +136,10 @@ const config: Configuration = {
* For example { for: 0 } -> { "for": 0 } * For example { for: 0 } -> { "for": 0 }
*/ */
{ from: /(for|return):/g, to: '"$1":' }, { from: /(for|return):/g, to: '"$1":' },
{ from: /\/(.*)\[([^\]]*)\/([^\]]*)\](.*)\//g, to: "/$1[$2\/$3]$4/" }, /**
* Some Regexp uses "/" character in character sets but must be escaped in QtScript syntax (don't know why)
*/
{ from: /\[\^\\s\(\/\]/g, to: "[^\\s(\\/]" },
], ],
}), }),
], ],