Last active
March 30, 2019 14:20
-
-
Save queengooborg/db303f7e72a582d2bf89d84bc4d035e2 to your computer and use it in GitHub Desktop.
Check against IDL files in browsers and a list for implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import sys | |
import widlparser | |
prefix_list = ["", "webkit", "Webkit", "WebKit", "Moz", "moz"] | |
browser = 'firefox' | |
if len(sys.argv) > 1: | |
browser = sys.argv[1] | |
if browser == 'firefox': | |
webidl_path = "/Users/vinyldarkscratch/Developer/git/gecko-dev/dom/webidl" | |
elif browser == 'chrome': | |
webidl_path = "/Users/vinyldarkscratch/Developer/git/chromium/src/third_party/blink" | |
elif browser == 'safari': | |
webidl_path = "/Users/vinyldarkscratch/Developer/WebKit/Source" | |
data = "" | |
with open("/Users/vinyldarkscratch/Desktop/%s_null.txt" %browser) as f: | |
entries_to_check = [l.replace("\n", "") for l in f.readlines() if l.startswith("api.")] | |
def dir_walk(path): | |
response = [] | |
for root, subdirs, files in os.walk(path): | |
response += [os.path.join(root, f) for f in files if (f.endswith('.idl') or f.endswith('.webidl'))] | |
for s in subdirs: | |
response += dir_walk(s) | |
return response | |
def prefixes(name): | |
return [p + name for p in prefix_list] | |
def get_interface(name, widl): | |
definitions = [] | |
implements = [] | |
for w in widl: | |
if w.name in prefixes(name): | |
if w.idlType == 'interface': | |
definitions.append(w) | |
elif w.idlType == 'implements': | |
implements.append(w.implements) | |
for i in implements: | |
definitions += get_interface(i, widl) | |
return definitions | |
def which_prefix(entry): | |
for i in range(1, len(prefix_list)): | |
if entry.name.startswith(prefix_list[i]): | |
return " - Prefix: {0}".format(prefix_list[i]) | |
return "" | |
def get_runtime_flags(entry): | |
for flag in entry.extendedAttributes: | |
if flag.name in ['RuntimeEnabled', 'Pref']: | |
return " - Flag: {0}".format(flag.attribute.value or flag.attribute.string) | |
return "" | |
def check_entry(entry): | |
e = entry.split(".") | |
for w in widl: | |
if w.name in prefixes(e[1]): | |
if len(e) == 2: | |
return "found{0}{1}".format(get_runtime_flags(w), which_prefix(w)) | |
elif len(e) >= 4: | |
return "feature_requires_manual_review" | |
elif len(e) == 3: | |
if hasattr(w, 'members'): | |
for d in get_interface(w.name, widl): | |
for m in d.members: | |
if m.name in prefixes(e[2]): | |
return "found{0}{1}".format(get_runtime_flags(m), which_prefix(m)) | |
return "not_defined" | |
return "no_idl" | |
files = sorted(dir_walk(webidl_path)) | |
for fn in files: | |
with open(os.path.join(webidl_path, fn), 'r') as f: | |
new_data = f.read() | |
data += new_data | |
with open("{0}.idl".format(browser), 'w') as f: | |
f.write(data) | |
widl = widlparser.parser.Parser(data) | |
with open("{0}.data.txt".format(browser), 'w') as f: | |
for entry in entries_to_check: | |
c = check_entry(entry) | |
f.write("%s - %s\n" %(entry, c)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const path = require('path'); | |
const compareVersions = require('compare-versions'); | |
const browser_to_test = 'firefox'; | |
const version_added_to_test = null; | |
/** | |
* Version is Bool check. | |
* | |
* This checker aims at improving data quality | |
* by detecting inconsistent information. | |
*/ | |
class VersionBoolChecker | |
{ | |
/** | |
* @param {object} data | |
* @returns {Array<object>} | |
*/ | |
check(data) { | |
return this.checkSubfeatures(data); | |
} | |
/** | |
* @param {object} data | |
* @param {array} path | |
* @returns {Array<object>} | |
*/ | |
checkSubfeatures(data, path = []) { | |
let allErrors = []; | |
// Check this feature. | |
if (this.isFeature(data)) { | |
const feature = path.length ? path[path.length - 1] : 'ROOT'; | |
const featurePath = path.length ? path.slice(0, path.length - 1).join('.') : ''; | |
const errors = this.checkFeature(data); | |
if (errors.length) { | |
allErrors.push({ | |
feature, | |
path, | |
errors | |
}); | |
} | |
} | |
// Check sub-features. | |
const keys = Object.keys(data).filter(key => key != '__compat'); | |
keys.forEach(key => { | |
allErrors = [ | |
...allErrors, | |
...this.checkSubfeatures(data[key], [...path, key]) | |
]; | |
}); | |
return allErrors; | |
} | |
/** | |
* @param {object} data | |
* @returns {Array<object>} | |
*/ | |
checkFeature(data) { | |
let errors = []; | |
// Add errors | |
Object.keys(data['__compat']['support']).forEach(browser => { | |
if (browser == browser_to_test && data['__compat']['support'][browser]['version_added'] === version_added_to_test) { | |
const errortype = 'version_added'; | |
errors.push({errortype, browser}); | |
} | |
}); | |
return errors; | |
} | |
/** | |
* @param {object} data | |
* @returns {boolean} | |
*/ | |
isFeature(data) { | |
return '__compat' in data; | |
} | |
/** | |
* @param {object} compatData | |
* @returns {Array<string>} | |
*/ | |
extractUnsupportedBrowsers(compatData) { | |
return this.extractBrowsers(compatData, data => data.version_added === false || typeof data.version_removed !== 'undefined' && data.version_removed !== false); | |
} | |
/** | |
* @param {object} compatData | |
* @returns {Array<string>} | |
*/ | |
extractSupportedBrowsersWithVersion(compatData) { | |
return this.extractBrowsers(compatData, data => typeof(data.version_added) === 'string'); | |
} | |
/* | |
* @param {object} compatData | |
* @returns {string} | |
*/ | |
getVersionAdded(compatData) { | |
var version_added = null; | |
if (typeof(compatData.version_added) === 'string') | |
return compatData.version_added; | |
if (compatData.constructor === Array) { | |
for (var i = compatData.length - 1; i >= 0; i--) { | |
var va = compatData[i].version_added; | |
if (typeof(va) === 'string' && (version_added == null || compareVersions(version_added, va) == 1)) | |
version_added = va; | |
} | |
} | |
return version_added; | |
} | |
/* | |
* @param {string} a | |
* @param {string} b | |
* @returns {boolean} | |
*/ | |
isVersionAddedGreater(a, b) { | |
var a_version_added = this.getVersionAdded(a); | |
var b_version_added = this.getVersionAdded(b); | |
if (typeof(a_version_added) === 'string' && typeof(b_version_added) === 'string') | |
return compareVersions(a_version_added, b_version_added) == -1; | |
return false; | |
} | |
/** | |
* | |
* @param {object} compatData | |
* @param {callback} callback | |
* @returns {boolean} | |
*/ | |
extractBrowsers(compatData, callback) | |
{ | |
return Object.keys(compatData.support).filter(browser => { | |
const browserData = compatData.support[browser]; | |
if (Array.isArray(browserData)) { | |
return browserData.every(callback); | |
} else if (typeof browserData === 'object') { | |
return callback(browserData); | |
} else { | |
return false; | |
} | |
}); | |
} | |
} | |
function testVersionBool(filename) { | |
let data = require(filename); | |
const checker = new VersionBoolChecker(); | |
const errors = checker.check(data); | |
if (errors.length) { | |
const relativeFilename = path.relative(process.cwd(), filename); | |
console.error(`\x1b[34m Found \x1b[1m${errors.length}\x1b[0m\x1b[34m inconsistent feature(s) in \x1b[3m${relativeFilename}:\x1b[0m`); | |
errors.forEach(({ feature, path, errors }) => { | |
console.error(`\x1b[34m → \x1b[1m${errors.length}\x1b[0m\x1b[34m × \x1b[1m${feature}\x1b[0m\x1b[34m [\x1b[3m${path.join('.')}\x1b[0m\x1b[34m]: `); | |
errors.forEach(({ errortype, browser }) => { | |
console.error(`\x1b[34m → version_added for \x1b[1m${browser}\x1b[0m\x1b[34m was declared as \x1b[1m${version_added_to_test}\x1b[0m`); | |
}); | |
}) | |
return true; | |
} else { | |
console.log('\x1b[32m Version is Bool – OK \x1b[0m'); | |
return false; | |
} | |
} | |
module.exports = testVersionBool; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment