extension: Check tools using TypeScript

This would have caught #10351.
This commit is contained in:
relrelb 2023-03-25 10:48:40 +03:00 committed by relrelb
parent bc1612ae38
commit 3ec473d36f
9 changed files with 186 additions and 43 deletions

85
web/package-lock.json generated
View File

@ -598,6 +598,15 @@
"integrity": "sha512-E0dpiZNdwO20c8d3seh7OmjAvDpwoRkTcU6M8cvggzB45Bd45tyTU2XJeA5Wfq+8NzVGhunvqOJ30AjSkywMXA==",
"dev": true
},
"node_modules/@types/archiver": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.2.tgz",
"integrity": "sha512-IctHreBuWE5dvBDz/0WeKtyVKVRs4h75IblxOACL92wU66v+HGAfEYAOyXkOFphvRJMhuXdI9huDXpX0FC6lCw==",
"dev": true,
"dependencies": {
"@types/readdir-glob": "*"
}
},
"node_modules/@types/body-parser": {
"version": "1.19.2",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
@ -617,6 +626,12 @@
"@types/node": "*"
}
},
"node_modules/@types/caseless": {
"version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==",
"dev": true
},
"node_modules/@types/chrome": {
"version": "0.0.226",
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.226.tgz",
@ -627,6 +642,12 @@
"@types/har-format": "*"
}
},
"node_modules/@types/common-tags": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@types/common-tags/-/common-tags-1.8.1.tgz",
"integrity": "sha512-20R/mDpKSPWdJs5TOpz3e7zqbeCNuMCPhV7Yndk9KU2Rbij2r5W4RzwDPkzC+2lzUqXYu9rFzTktCBnDjHuNQg==",
"dev": true
},
"node_modules/@types/connect": {
"version": "3.4.35",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
@ -767,6 +788,15 @@
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"dev": true
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
"integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/mime": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
@ -785,6 +815,15 @@
"integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==",
"dev": true
},
"node_modules/@types/mz": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/@types/mz/-/mz-2.7.4.tgz",
"integrity": "sha512-Zs0imXxyWT20j3Z2NwKpr0IO2LmLactBblNyLua5Az4UHuqOQ02V3jPTgyKwDkuc33/ahw+C3O1PIZdrhFMuQA==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "18.15.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.10.tgz",
@ -809,6 +848,41 @@
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true
},
"node_modules/@types/readdir-glob": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.1.tgz",
"integrity": "sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/request": {
"version": "2.48.8",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz",
"integrity": "sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ==",
"dev": true,
"dependencies": {
"@types/caseless": "*",
"@types/node": "*",
"@types/tough-cookie": "*",
"form-data": "^2.5.0"
}
},
"node_modules/@types/request/node_modules/form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"dev": true,
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 0.12"
}
},
"node_modules/@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
@ -855,6 +929,12 @@
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
"dev": true
},
"node_modules/@types/tough-cookie": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
"integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
"dev": true
},
"node_modules/@types/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz",
@ -12554,8 +12634,13 @@
},
"devDependencies": {
"@tsconfig/strictest": "^2.0.0",
"@types/archiver": "^5.3.2",
"@types/chrome": "^0.0.226",
"@types/common-tags": "^1.8.1",
"@types/firefox-webext-browser": "^111.0.0",
"@types/jsonwebtoken": "^9.0.1",
"@types/mz": "^2.7.4",
"@types/request": "^2.48.8",
"archiver": "^5.3.1",
"json5": "^2.2.3",
"sign-addon": "^6.0.0",

View File

@ -0,0 +1,2 @@
parserOptions:
sourceType: module

View File

@ -0,0 +1,16 @@
{
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": {
"lib": ["es2021"],
"module": "es2022",
"moduleResolution": "node",
"target": "es2017",
"resolveJsonModule": true,
"maxNodeModuleJsDepth": 0,
// Disable some checks for `sign-addon`.
"noUnusedLocals": false,
"noUncheckedIndexedAccess": false,
},
"include": ["webpack.config.js", "tools/**/*", "../../node_modules/sign-addon/**/*"],
}

View File

@ -4,8 +4,9 @@
"description": "Extension packaging for Ruffle Flash emulator",
"license": "(MIT OR Apache-2.0)",
"private": true,
"type": "module",
"scripts": {
"build": "npm run build:generic && npm run build:firefox",
"build": "tsc -p jsconfig.json && npm run build:generic && npm run build:firefox",
"build:generic": "webpack --env generic && node tools/inject_plugin_polyfill.js && node tools/zip.js dist/ruffle_extension.zip",
"build:firefox": "webpack --env firefox && node tools/inject_plugin_polyfill.js && node tools/zip.js dist/firefox_unsigned.xpi && npm run sign-firefox",
"sign-firefox": "node tools/sign_xpi.js dist/firefox_unsigned.xpi dist/firefox.xpi ../../../reproducible-source.zip"
@ -15,8 +16,13 @@
},
"devDependencies": {
"@tsconfig/strictest": "^2.0.0",
"@types/archiver": "^5.3.2",
"@types/chrome": "^0.0.226",
"@types/common-tags": "^1.8.1",
"@types/firefox-webext-browser": "^111.0.0",
"@types/jsonwebtoken": "^9.0.1",
"@types/mz": "^2.7.4",
"@types/request": "^2.48.8",
"archiver": "^5.3.1",
"json5": "^2.2.3",
"sign-addon": "^6.0.0",

View File

@ -2,4 +2,3 @@ env:
node: true
parserOptions:
ecmaVersion: 2022 # Needed for top-level-await.
sourceType: module

View File

@ -1,3 +0,0 @@
{
"type": "module"
}

View File

@ -1,10 +1,20 @@
import fsSync from "fs";
import fs from "fs/promises";
import fs_callback from "fs";
import { createRequire } from "module";
import url from "url";
import tempDir from "temp-dir";
import { signAddon } from "sign-addon";
import { Client as AMOClient } from "sign-addon/lib/amo-client.js";
/**
* @param {string} apiKey
* @param {string} apiSecret
* @param {string} extensionId
* @param {string} unsignedPath
* @param {string} version
* @param {string} destination
* @param {string} sourcePath
* @param {string} sourceTag
*/
async function sign(
apiKey,
apiSecret,
@ -40,7 +50,7 @@ async function sign(
extensionId
)}/versions/${encodeURIComponent(version)}/`,
formData: {
source: fs_callback.createReadStream(sourcePath),
source: fsSync.createReadStream(sourcePath),
},
});
@ -81,11 +91,14 @@ As this is indeed a complicated build process, please let me know if there is an
throw result;
}
if (result.downloadedFiles.length === 1) {
if (result.downloadedFiles?.length === 1) {
// Copy the downloaded file to the destination.
// (Avoid `rename` because it fails if the destination is on a different drive.)
await fs.copyFile(result.downloadedFiles[0], destination);
await fs.unlink(result.downloadedFiles[0]);
const downloadedFile = /** @type {string} */ (
result.downloadedFiles[0]
);
await fs.copyFile(downloadedFile, destination);
await fs.unlink(downloadedFile);
} else {
console.warn(
"Unexpected downloads for signed Firefox extension, expected 1."
@ -96,23 +109,25 @@ As this is indeed a complicated build process, please let me know if there is an
try {
if (
process.env.MOZILLA_API_KEY &&
process.env.MOZILLA_API_SECRET &&
process.env.FIREFOX_EXTENSION_ID &&
process.env.SOURCE_TAG
process.env["MOZILLA_API_KEY"] &&
process.env["MOZILLA_API_SECRET"] &&
process.env["FIREFOX_EXTENSION_ID"] &&
process.env["SOURCE_TAG"]
) {
// TODO: Import as a JSON module once it becomes stable.
const require = createRequire(import.meta.url);
const { version } = require("../assets/manifest.json");
const manifestPath = url.fileURLToPath(
new URL("../assets/manifest.json", import.meta.url)
);
const manifest = JSON.parse(await fs.readFile(manifestPath, "utf8"));
await sign(
process.env.MOZILLA_API_KEY,
process.env.MOZILLA_API_SECRET,
process.env.FIREFOX_EXTENSION_ID,
process.argv[2],
version,
process.argv[3],
process.argv[4],
process.env.SOURCE_TAG
process.env["MOZILLA_API_KEY"],
process.env["MOZILLA_API_SECRET"],
process.env["FIREFOX_EXTENSION_ID"],
/** @type {string} */ (process.argv[2]),
manifest.version,
/** @type {string} */ (process.argv[3]),
/** @type {string} */ (process.argv[4]),
process.env["SOURCE_TAG"]
);
} else {
console.log(

View File

@ -3,6 +3,10 @@ import path from "path";
import url from "url";
import archiver from "archiver";
/**
* @param {string} source
* @param {string} destination
*/
async function zip(source, destination) {
await fs.mkdir(path.dirname(destination), { recursive: true });
const output = (await fs.open(destination, "w")).createWriteStream();
@ -34,4 +38,4 @@ async function zip(source, destination) {
}
const assets = url.fileURLToPath(new URL("../assets/", import.meta.url));
await zip(assets, process.argv[2]);
await zip(assets, /** @type {string} */ (process.argv[2]));

View File

@ -1,24 +1,29 @@
/* eslint-env node */
const path = require("path");
const json5 = require("json5");
const CopyPlugin = require("copy-webpack-plugin");
const fs = require("fs");
import fs from "fs";
import url from "url";
import json5 from "json5";
import CopyPlugin from "copy-webpack-plugin";
/**
* @param {Buffer} content
* @param {Record<string, any>} env
* @returns {string}
*/
function transformManifest(content, env) {
const manifest = json5.parse(content);
const manifest = json5.parse(content.toString());
let packageVersion = process.env.npm_package_version;
let versionChannel = process.env.CFG_RELEASE_CHANNEL || "nightly";
let packageVersion = process.env["npm_package_version"];
let versionChannel = process.env["CFG_RELEASE_CHANNEL"] || "nightly";
let buildDate = new Date().toISOString().substring(0, 10);
let build_id = process.env.BUILD_ID;
let build_id = process.env["BUILD_ID"];
let firefox_extension_id =
process.env.FIREFOX_EXTENSION_ID || "ruffle@ruffle.rs";
process.env["FIREFOX_EXTENSION_ID"] || "ruffle@ruffle.rs";
if (process.env.ENABLE_VERSION_SEAL === "true") {
if (process.env["ENABLE_VERSION_SEAL"] === "true") {
if (fs.existsSync("../../version_seal.json")) {
const version_seal = JSON.parse(
fs.readFileSync("../../version_seal.json")
fs.readFileSync("../../version_seal.json", "utf8")
);
packageVersion = version_seal.version_number;
@ -44,7 +49,7 @@ function transformManifest(content, env) {
? `${packageVersion}.${build_id}`
: packageVersion;
if (env.firefox) {
if (env["firefox"]) {
manifest.browser_specific_settings = {
gecko: {
id: firefox_extension_id,
@ -73,8 +78,14 @@ function transformManifest(content, env) {
return JSON.stringify(manifest);
}
module.exports = (env, _argv) => {
const mode = process.env.NODE_ENV || "production";
/**
* @type {import("webpack-cli").CallableOption}
*/
export default function (env, _argv) {
const mode =
/** @type {import("webpack").Configuration["mode"]} */ (
process.env["NODE_ENV"]
) || "production";
console.log(`Building ${mode}...`);
return {
@ -89,7 +100,7 @@ module.exports = (env, _argv) => {
pluginPolyfill: "./src/plugin-polyfill.ts",
},
output: {
path: path.resolve(__dirname, "assets/dist/"),
path: url.fileURLToPath(new URL("assets/dist/", import.meta.url)),
publicPath: "",
clean: true,
},
@ -105,6 +116,10 @@ module.exports = (env, _argv) => {
extensions: [".ts", "..."],
},
performance: {
/**
* @param {string} assetFilename
* @returns {boolean}
*/
assetFilter: (assetFilename) =>
!/\.(map|wasm)$/i.test(assetFilename),
},
@ -117,7 +132,11 @@ module.exports = (env, _argv) => {
{
from: "manifest.json5",
to: "../manifest.json",
transform: (content) => transformManifest(content, env),
transform: (content) =>
transformManifest(
content,
/** @type {Record<string, any>} */ (env)
),
},
{ from: "LICENSE*" },
{ from: "README.md" },
@ -125,4 +144,4 @@ module.exports = (env, _argv) => {
}),
],
};
};
}