webextensions-schema
Version:
Programmatically consume the WebExtensions Schema JSON files
131 lines (130 loc) • 4.76 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const request_1 = __importDefault(require("request"));
const unzipper_1 = __importDefault(require("unzipper"));
const strip_json_comments_1 = __importDefault(require("strip-json-comments"));
class DownloadParse {
constructor({ tag } = {}) {
this.mozRepo = 'mozilla-unified';
this.mozArchiveURL = 'https://hg.mozilla.org/mozilla-unified/archive';
this.mozLatestFxURL = 'https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US';
this.outDir = path_1.default.join(__dirname, '..', '.schemas');
this.schemaTypes = ['browser', 'toolkit'];
this.schemasDir = ['components', 'extensions', 'schemas'];
this.schemas = {
raw: {},
namespaces: {},
};
if (tag) {
this.tag = tag;
}
}
set tag(tag) {
this._tag = tag;
this.tagDir = path_1.default.join(this.outDir, `${this.mozRepo}-${tag}`);
}
get tag() {
return this._tag;
}
async run() {
if (!this.tag) {
await this.fetchLatestStableTag();
}
if (!(await this.tagDirExists())) {
await this.downloadSchemas();
}
await this.parseSchemas();
this.extractNamespaces();
return this;
}
getSchemas() {
return this.schemas;
}
getTag() {
return this.tag;
}
extractNamespaces() {
Object.values(this.schemas.raw).forEach(schemaJson => {
schemaJson.forEach(namespace => {
if (!this.schemas.namespaces[namespace.namespace]) {
this.schemas.namespaces[namespace.namespace] = [];
}
this.schemas.namespaces[namespace.namespace].push(namespace);
});
});
}
async parseSchemas() {
const unordered = {};
await Promise.all(this.schemaTypes.map(async (type) => {
const dir = path_1.default.join(this.tagDir, type, ...this.schemasDir);
const files = await fs_1.promises.readdir(dir);
await Promise.all(files.map(async (file) => {
if (path_1.default.extname(file) !== '.json') {
return;
}
const jsonBuffer = await fs_1.promises.readFile(path_1.default.join(dir, file));
const schema = JSON.parse(strip_json_comments_1.default(jsonBuffer.toString()));
unordered[file] = schema;
}));
}));
Object.keys(unordered)
.sort()
.forEach(file => {
this.schemas.raw[file] = unordered[file];
});
}
async downloadSchemas() {
await Promise.all(this.schemaTypes.map((type) => this.downloadSchema(type)));
}
async downloadSchema(type) {
return new Promise(resolve => {
const url = this.getDownloadArchiveUrl(type);
request_1.default.get(url).on('response', response => {
if (response.statusCode !== 200) {
throw new Error(`http status ${response.statusCode} while trying to download ${url} - probably invalid tag name`);
}
response
.pipe(unzipper_1.default.Extract({ path: this.outDir }))
.on('finish', resolve);
});
});
}
async tagDirExists() {
try {
await fs_1.promises.access(this.tagDir);
return true;
}
catch (error) {
return false;
}
}
async fetchLatestStableTag() {
return new Promise(resolve => {
request_1.default
.head({ followRedirect: false, url: this.mozLatestFxURL })
.on('response', response => {
var _a;
const [, release] = ((_a = response.headers.location) === null || _a === void 0 ? void 0 : _a.match(/\/pub\/firefox\/releases\/([^/]+)\//)) || [];
if (!release) {
throw new Error("Couldn't automatically resolve latest stable tag");
}
this.tag = `FIREFOX_${release.replace(/\./g, '_')}_RELEASE`;
resolve();
});
});
}
getDownloadArchiveUrl(type) {
return [
this.mozArchiveURL,
`${this.tag}.zip`,
type,
...this.schemasDir,
].join('/');
}
}
exports.DownloadParse = DownloadParse;