VulpesOS/gaia/tools/html_transformer/html_transformer.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

110 lines
2.9 KiB
JavaScript
Executable file

/**
* @fileoverview A collection of utilities for performing static analysis on
* and transforming apps' html files.
*/
var Promise = require('es6-promise').Promise;
var jsdom = require('jsdom');
function load(filename) {
return new Promise(function(resolve, reject) {
jsdom.env(filename, function(errors, window) {
if (errors && errors.length) {
return reject(errors[0]);
}
return resolve(new HTMLTransformer(window));
});
});
};
function HTMLTransformer(window) {
this.window = window;
}
HTMLTransformer.prototype = {
getSharedDependencies: function() {
var doc = this.window.document;
var links = getSharedElements(doc, 'link');
var scripts = getSharedElements(doc, 'script');
var commented = flatmap(getComments(doc), getSharedElementsFromComment);
return links.concat(scripts).concat(commented);
}
};
function getSharedElements(doc, selector) {
return querySelectorAll(doc, selector).map(getShared).filter(function(x) {
return !!x;
});
}
function getSharedElementsFromComment(comment) {
var sharedLink = /<link\s.*href="(app:\/\/.+\.gaiamobile\.org)?\/?(shared\/.+)".*>/;
var sharedScript = /<script\s.*src="(app:\/\/.+\.gaiamobile\.org)?\/?(shared\/.+)".*>/;
return flatmap(comment.split(/\n/), function(commentLine) {
var links = commentLine.match(sharedLink) || [];
var scripts = commentLine.match(sharedScript) || [];
var results = links.concat(scripts);
return results.filter(function(result) {
return result && result.indexOf('shared') === 0;
});
});
};
// Neither document.createTreeWalker nor document.createNodeIterator
// are supported by jsdom so we're going to do this the old fashioned way...
function getComments(doc) {
var results = [];
var queue = [doc.body];
while (queue.length) {
var next = queue.shift();
if (next.nodeType === 8 /* COMMENT_NODE */) {
results.push(next.textContent);
}
var children = next.childNodes;
if (children && children.length) {
for (var i = 0; i < children.length; i++) {
queue.push(children[i]);
}
}
}
return results;
}
function querySelectorAll(doc, selector) {
return Array.prototype.slice.call(doc.querySelectorAll(selector));
}
function getShared(node) {
var sharedUrl = /^(app:\/\/.+\.gaiamobile\.org)?\/?(shared\/.+)/;
var match;
switch (node.nodeName) {
case 'LINK':
match = node.href.match(sharedUrl);
break;
case 'SCRIPT':
match = node.src.match(sharedUrl);
break;
default:
return false;
}
return (match && match.length) ? match.filter(function(str) {
return str && str.indexOf('shared') === 0;
})[0] : false;
}
function flatmap(array, fn) {
var result = [];
array.map(fn).forEach(function(subresult) {
if (Array.isArray(subresult)) {
result = result.concat(subresult);
}
});
return result;
}
module.exports = { HTMLTransformer: HTMLTransformer, load: load };