mirror of
https://github.com/koloml/philomena-tagging-assistant.git
synced 2026-05-09 15:12:21 +00:00
219 lines
5.9 KiB
JavaScript
219 lines
5.9 KiB
JavaScript
import fs from "fs";
|
|
|
|
/**
|
|
* Helper class for processing and using manifest for packing the extension.
|
|
*/
|
|
class ManifestProcessor {
|
|
/**
|
|
* Current state of the manifest object.
|
|
* @type {Manifest}
|
|
*/
|
|
#manifestObject;
|
|
|
|
/**
|
|
* @param {Manifest} parsedManifest Original manifest contents parsed as JSON object.
|
|
*/
|
|
constructor(parsedManifest) {
|
|
this.#manifestObject = parsedManifest;
|
|
}
|
|
|
|
/**
|
|
* Collect all the content scripts & stylesheets for single build action.
|
|
*
|
|
* @returns {Set<string>}
|
|
*/
|
|
collectContentScripts() {
|
|
const contentScripts = this.#manifestObject.content_scripts;
|
|
|
|
if (!contentScripts) {
|
|
console.info('No content scripts to collect.');
|
|
return new Set();
|
|
}
|
|
|
|
const entryPoints = new Set();
|
|
|
|
for (let entry of contentScripts) {
|
|
if (entry.js) {
|
|
for (let jsPath of entry.js) {
|
|
entryPoints.add(jsPath);
|
|
}
|
|
}
|
|
|
|
if (entry.css) {
|
|
for (let cssPath of entry.css) {
|
|
entryPoints.add(cssPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
return entryPoints;
|
|
}
|
|
|
|
/**
|
|
* Map over every content script defined in the manifest. If no content scripts defined, no calls will be made to the
|
|
* callback.
|
|
*
|
|
* @param {function(ContentScriptsEntry): Promise<ContentScriptsEntry>} mapCallback Processing function to call on
|
|
* every entry. Entries should be modified and returned. Function should be asynchronous.
|
|
*
|
|
* @return {Promise<void>}
|
|
*/
|
|
async mapContentScripts(mapCallback) {
|
|
const contentScripts = this.#manifestObject.content_scripts;
|
|
|
|
if (!contentScripts) {
|
|
console.info('No content scripts to map over.');
|
|
return;
|
|
}
|
|
|
|
for (let entryIndex = 0; entryIndex < contentScripts.length; entryIndex++) {
|
|
contentScripts[entryIndex] = await mapCallback(contentScripts[entryIndex]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Pass the version of the plugin from following package.json file.
|
|
*
|
|
* @param {string} packageFilePath Path to the JSON file to parse and extract the version from. If version is not
|
|
* found, original version will be kept.
|
|
*/
|
|
passVersionFromPackage(packageFilePath) {
|
|
/** @type {PackageObject} */
|
|
const packageObject = JSON.parse(fs.readFileSync(packageFilePath, 'utf8'));
|
|
|
|
if (packageObject.version) {
|
|
this.#manifestObject.version = packageObject.version;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find all patterns in content scripts and host permissions and replace the hostname to the different one.
|
|
*
|
|
* @param {string|string[]} singleOrMultipleHostnames One or multiple hostnames to replace the original hostname with.
|
|
*/
|
|
replaceHostTo(singleOrMultipleHostnames) {
|
|
if (typeof singleOrMultipleHostnames === 'string') {
|
|
singleOrMultipleHostnames = [singleOrMultipleHostnames];
|
|
}
|
|
|
|
const matchPatterReplacer = ManifestProcessor.#createHostnameReplacementReduce(singleOrMultipleHostnames);
|
|
|
|
this.#manifestObject.host_permissions = singleOrMultipleHostnames.map(hostname => `*://*.${hostname}/`);
|
|
|
|
this.#manifestObject.content_scripts?.forEach(entry => {
|
|
entry.matches = entry.matches.reduce(matchPatterReplacer, []);
|
|
|
|
if (entry.exclude_matches) {
|
|
entry.exclude_matches = entry.exclude_matches.reduce(matchPatterReplacer, []);
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Set different identifier for Gecko-based browsers (Firefox).
|
|
*
|
|
* @param {string} id ID of the extension to use.
|
|
*/
|
|
setGeckoIdentifier(id) {
|
|
this.#manifestObject.browser_specific_settings.gecko.id = id;
|
|
}
|
|
|
|
/**
|
|
* Set the different extension name.
|
|
*
|
|
* @param {string} booruName
|
|
*/
|
|
replaceBooruNameWith(booruName) {
|
|
this.#manifestObject.name = this.#manifestObject.name.replaceAll('Furbooru', booruName);
|
|
this.#manifestObject.description = this.#manifestObject.description.replaceAll('Furbooru', booruName);
|
|
}
|
|
|
|
/**
|
|
* Save the current state of the manifest into the selected file.
|
|
*
|
|
* @param {string} manifestFilePath File to write the resulting manifest to. Should be called after all the
|
|
* modifications.
|
|
*/
|
|
saveTo(manifestFilePath) {
|
|
fs.writeFileSync(
|
|
manifestFilePath,
|
|
JSON.stringify(this.#manifestObject, null, 2),
|
|
{
|
|
encoding: 'utf8'
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param {string|(string[])} singleOrMultipleHostnames
|
|
* @return {function(string[], string): string[]}
|
|
*/
|
|
static #createHostnameReplacementReduce(singleOrMultipleHostnames) {
|
|
return (
|
|
/**
|
|
* @param {string[]} resultMatches
|
|
* @param {string} originalMatchPattern
|
|
* @return {string[]}
|
|
*/
|
|
(resultMatches, originalMatchPattern) => {
|
|
for (const updatedHostname of singleOrMultipleHostnames) {
|
|
resultMatches.push(
|
|
originalMatchPattern.replace(
|
|
/\*:\/\/\*\.[a-z]+\.[a-z]+\//,
|
|
`*://*.${updatedHostname}/`
|
|
),
|
|
);
|
|
}
|
|
|
|
return resultMatches;
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load the manifest and create a processor object.
|
|
*
|
|
* @param {string} filePath Path to the original manifest file.
|
|
*
|
|
* @return {ManifestProcessor} Object for manipulating manifest file.
|
|
*/
|
|
export function loadManifest(filePath) {
|
|
const manifest = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
|
|
return new ManifestProcessor(manifest);
|
|
}
|
|
|
|
/**
|
|
* @typedef {Object} Manifest
|
|
* @property {string} name
|
|
* @property {string} description
|
|
* @property {string} version
|
|
* @property {BrowserSpecificSettings} browser_specific_settings
|
|
* @property {string[]} host_permissions
|
|
* @property {ContentScriptsEntry[]|undefined} content_scripts
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} BrowserSpecificSettings
|
|
* @property {GeckoSettings} gecko
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} GeckoSettings
|
|
* @property {string} id
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} ContentScriptsEntry
|
|
* @property {string[]} matches
|
|
* @property {string[]} exclude_matches
|
|
* @property {string[]|undefined} js
|
|
* @property {string[]|undefined} css
|
|
*/
|
|
|
|
/**
|
|
* @typedef {Object} PackageObject
|
|
* @property {string|undefined} version
|
|
*/
|