From 27973d9ccdac2f8601593dd2a218f83a45f0b323 Mon Sep 17 00:00:00 2001 From: Eli Kogan-Wang Date: Thu, 20 Mar 2025 16:33:37 +0100 Subject: [PATCH] Migrate scripts to ES modules and update related configurations --- eslint.config.mjs | 2 +- package.json | 4 +- po/Makefile | 4 +- po/po2js.cjs | 6 +- po/{xgettext-html.cjs => xgettext-html.js} | 6 +- utils/build.js | 74 +++++++++++ utils/convert.cjs | 140 --------------------- 7 files changed, 85 insertions(+), 151 deletions(-) rename po/{xgettext-html.cjs => xgettext-html.js} (97%) create mode 100644 utils/build.js delete mode 100755 utils/convert.cjs diff --git a/eslint.config.mjs b/eslint.config.mjs index 3b055296..43d463f9 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -62,7 +62,7 @@ export default [ } }, { - files: ["po/po2js.cjs", "po/xgettext-html.cjs"], + files: ["po/po2js.js", "po/xgettext-html.js"], languageOptions: { globals: { ...globals.node, diff --git a/package.json b/package.json index 8779797d..ec645c1e 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ "docs/LICENSE*" ], "scripts": { - "lint": "eslint app core po/po2js.cjs po/xgettext-html.cjs tests utils", + "lint": "eslint app core po/po2js.js po/xgettext-html.js tests utils", "test": "karma start karma.conf.cjs", - "prepare": "node ./utils/convert.cjs --clean" + "prepare": "node ./utils/build.js --clean" }, "repository": { "type": "git", diff --git a/po/Makefile b/po/Makefile index e31056b0..b44a0042 100644 --- a/po/Makefile +++ b/po/Makefile @@ -15,7 +15,7 @@ update-js: $(JSONFILES) %.po: FORCE msgmerge --update --lang=$* $@ noVNC.pot ../app/locale/%.json: FORCE - ./po2js.cjs $*.po $@ + ./po2js.js $*.po $@ update-pot: xgettext --output=noVNC.js.pot \ @@ -29,7 +29,7 @@ update-pot: ../app/*.js \ ../core/*.js \ ../core/input/*.js - ./xgettext-html.cjs --output=noVNC.html.pot \ + ./xgettext-html.js --output=noVNC.html.pot \ ../vnc.html msgcat --output-file=noVNC.pot \ --sort-by-file noVNC.js.pot noVNC.html.pot diff --git a/po/po2js.cjs b/po/po2js.cjs index 6347e1ea..38effd30 100755 --- a/po/po2js.cjs +++ b/po/po2js.cjs @@ -17,9 +17,9 @@ * along with this program. If not, see . */ -const { program } = require('commander'); -const fs = require('fs'); -const pofile = require("pofile"); +import { program } from 'commander'; +import fs from 'fs'; +import pofile from "pofile"; program .argument('') diff --git a/po/xgettext-html.cjs b/po/xgettext-html.js similarity index 97% rename from po/xgettext-html.cjs rename to po/xgettext-html.js index f5ba57cc..39b86de3 100755 --- a/po/xgettext-html.cjs +++ b/po/xgettext-html.js @@ -5,9 +5,9 @@ * Licensed under MPL 2.0 (see LICENSE.txt) */ -const { program } = require('commander'); -const jsdom = require("jsdom"); -const fs = require("fs"); +import { program } from 'commander'; +import jsdom from 'jsdom'; +import fs from 'fs'; program .argument('') diff --git a/utils/build.js b/utils/build.js new file mode 100644 index 00000000..eb3d8f94 --- /dev/null +++ b/utils/build.js @@ -0,0 +1,74 @@ +#!/usr/bin/env node +import fs from "fs"; +import path from "path"; +import fse from "fs-extra"; +import { program } from "commander"; +import { ensureDir } from "fs-extra"; +import { fileURLToPath } from "url"; + +program + .option("--clean", "clear the lib folder before building") + .parse(process.argv); + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +// the various important paths +const paths = { + main: path.resolve(__dirname, ".."), + core: path.resolve(__dirname, "..", "core"), + vendor: path.resolve(__dirname, "..", "vendor"), + libDirBase: path.resolve(__dirname, "..", "lib"), +}; + +// walkDir *recursively* walks directories trees, +// calling the callback for all normal files found. +const walkDir = async (basePath, cb, filter) => { + const files = await fs.promises.readdir(basePath); + const paths = files.map((filename) => path.join(basePath, filename)); + return Promise.all( + paths.map(async (filepath) => { + const stats = await fs.promises.lstat(filepath); + if (filter !== undefined && !filter(filepath, stats)) return; + if (stats.isSymbolicLink()) return; + if (stats.isFile()) return cb(filepath); + if (stats.isDirectory()) return walkDir(filepath, cb, filter); + }) + ); +}; + +const makeLibFiles = async () => { + fse.ensureDirSync(paths.libDirBase); + const outFiles = []; + + const handleDir = async (vendorRewrite, inPathBase, filename) => { + const outPath = path.join( + paths.libDirBase, + path.relative(inPathBase, filename) + ); + if (path.extname(filename) !== ".js") { + return; // skip non-javascript files + } + await ensureDir(path.dirname(outPath)); + await fs.promises.copyFile(filename, outPath); + console.log(`Writing ${outPath}`); + outFiles.push(`${outPath}`); + }; + const handler = handleDir.bind(null, false, paths.main); + await walkDir(paths.vendor, handler); + const handler2 = handleDir.bind(null, true, paths.core); + await walkDir(paths.core, handler2); + return outFiles; +}; +const options = program.opts(); +if (options.clean) { + console.log(`Removing ${paths.libDirBase}`); + fse.removeSync(paths.libDirBase); +} +makeLibFiles() + .then((outFiles) => { + console.log(`Converted ${outFiles.length} files`); + }) + .catch((err) => { + console.error(`Failure converting modules: ${err}`); + process.exit(1); + }); diff --git a/utils/convert.cjs b/utils/convert.cjs deleted file mode 100755 index 35dfe9e8..00000000 --- a/utils/convert.cjs +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env node - -const path = require('path'); -const { program } = require('commander'); -const fs = require('fs'); -const fse = require('fs-extra'); -const babel = require('@babel/core'); - -program - .option('-m, --with-source-maps [type]', 'output source maps when not generating a bundled app (type may be empty for external source maps, inline for inline source maps, or both) ') - .option('--clean', 'clear the lib folder before building') - .parse(process.argv); - -// the various important paths -const paths = { - main: path.resolve(__dirname, '..'), - core: path.resolve(__dirname, '..', 'core'), - vendor: path.resolve(__dirname, '..', 'vendor'), - libDirBase: path.resolve(__dirname, '..', 'lib'), -}; - -// util.promisify requires Node.js 8.x, so we have our own -function promisify(original) { - return function promiseWrap() { - const args = Array.prototype.slice.call(arguments); - return new Promise((resolve, reject) => { - original.apply(this, args.concat((err, value) => { - if (err) return reject(err); - resolve(value); - })); - }); - }; -} - -const writeFile = promisify(fs.writeFile); - -const readdir = promisify(fs.readdir); -const lstat = promisify(fs.lstat); - -const ensureDir = promisify(fse.ensureDir); - -const babelTransformFile = promisify(babel.transformFile); - -// walkDir *recursively* walks directories trees, -// calling the callback for all normal files found. -function walkDir(basePath, cb, filter) { - return readdir(basePath) - .then((files) => { - const paths = files.map(filename => path.join(basePath, filename)); - return Promise.all(paths.map(filepath => lstat(filepath) - .then((stats) => { - if (filter !== undefined && !filter(filepath, stats)) return; - - if (stats.isSymbolicLink()) return; - if (stats.isFile()) return cb(filepath); - if (stats.isDirectory()) return walkDir(filepath, cb, filter); - }))); - }); -} - -function makeLibFiles(sourceMaps) { - // NB: we need to make a copy of babelOpts, since babel sets some defaults on it - const babelOpts = () => ({ - plugins: [], - presets: [ - [ '@babel/preset-env', - { modules: false } ] - ], - ast: false, - sourceMaps: sourceMaps, - }); - - fse.ensureDirSync(paths.libDirBase); - - const outFiles = []; - - const handleDir = (vendorRewrite, inPathBase, filename) => Promise.resolve() - .then(() => { - const outPath = path.join(paths.libDirBase, path.relative(inPathBase, filename)); - - if (path.extname(filename) !== '.js') { - return; // skip non-javascript files - } - return Promise.resolve() - .then(() => ensureDir(path.dirname(outPath))) - .then(() => { - const opts = babelOpts(); - // Adjust for the fact that we move the core files relative - // to the vendor directory - if (vendorRewrite) { - opts.plugins.push(["import-redirect", - {"root": paths.libDirBase, - "redirect": { "vendor/(.+)": "./vendor/$1"}}]); - } - - return babelTransformFile(filename, opts) - .then((res) => { - console.log(`Writing ${outPath}`); - const {map} = res; - let {code} = res; - if (sourceMaps === true) { - // append URL for external source map - code += `\n//# sourceMappingURL=${path.basename(outPath)}.map\n`; - } - outFiles.push(`${outPath}`); - return writeFile(outPath, code) - .then(() => { - if (sourceMaps === true || sourceMaps === 'both') { - console.log(` and ${outPath}.map`); - outFiles.push(`${outPath}.map`); - return writeFile(`${outPath}.map`, JSON.stringify(map)); - } - }); - }); - }); - }); - - Promise.resolve() - .then(() => { - const handler = handleDir.bind(null, false, paths.main); - return walkDir(paths.vendor, handler); - }) - .then(() => { - const handler = handleDir.bind(null, true, paths.core); - return walkDir(paths.core, handler); - }) - .catch((err) => { - console.error(`Failure converting modules: ${err}`); - process.exit(1); - }); -} - -let options = program.opts(); - -if (options.clean) { - console.log(`Removing ${paths.libDirBase}`); - fse.removeSync(paths.libDirBase); -} - -makeLibFiles(options.withSourceMaps);