123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- "use strict";
- const path = require("path");
- const fs = require("fs");
- const helpers = require("./helpers");
- const htmlparser = require("htmlparser2");
- function parseBooleanConfig(string, comment) {
- let items = {};
-
- string = string.replace(/\s*:\s*/g, ":");
-
- string = string.replace(/\s*,\s*/g, ",");
- string.split(/\s|,+/).forEach(function(name) {
- if (!name) {
- return;
- }
- let pos = name.indexOf(":");
- let value;
- if (pos !== -1) {
- value = name.substring(pos + 1, name.length);
- name = name.substring(0, pos);
- }
- items[name] = {
- value: value === "true",
- comment,
- };
- });
- return items;
- }
- const globalCache = new Map();
- var globalDiscoveryInProgressForFiles = new Set();
- var lastHTMLGlobals = {};
- function GlobalsForNode(filePath, context) {
- this.path = filePath;
- this.context = context;
- if (this.path) {
- this.dirname = path.dirname(this.path);
- } else {
- this.dirname = null;
- }
- }
- GlobalsForNode.prototype = {
- Program(node) {
- let globals = [];
- for (let comment of node.comments) {
- if (comment.type !== "Block") {
- continue;
- }
- let value = comment.value.trim();
- value = value.replace(/\n/g, "");
-
-
- let match = /^globals?\s+(.+)/.exec(value);
- if (match) {
- let values = parseBooleanConfig(match[1].trim(), node);
- for (let name of Object.keys(values)) {
- globals.push({
- name,
- writable: values[name].value,
- });
- }
-
- continue;
- }
- match = /^import-globals-from\s+(.+)$/.exec(value);
- if (!match) {
- continue;
- }
- if (!this.dirname) {
-
- return globals;
- }
- let filePath = match[1].trim();
- if (filePath.endsWith(".mjs")) {
- if (this.context) {
- this.context.report(
- comment,
- "import-globals-from does not support module files - use a direct import instead"
- );
- } else {
-
-
- throw new Error(
- "import-globals-from does not support module files - use a direct import instead"
- );
- }
- continue;
- }
- if (!path.isAbsolute(filePath)) {
- filePath = path.resolve(this.dirname, filePath);
- } else {
- filePath = path.join(helpers.rootDir, filePath);
- }
- globals = globals.concat(module.exports.getGlobalsForFile(filePath));
- }
- return globals;
- },
- ExpressionStatement(node, parents, globalScope) {
- let isGlobal = helpers.getIsGlobalThis(parents);
- let globals = [];
-
-
- if (node.expression.type === "AssignmentExpression") {
- globals = helpers.convertThisAssignmentExpressionToGlobals(
- node,
- isGlobal
- );
- } else if (node.expression.type === "CallExpression") {
- globals = helpers.convertCallExpressionToGlobals(node, isGlobal);
- }
-
-
-
-
-
- if (globalScope && globalScope.set.get("importScripts") && this.dirname) {
- let workerDetails = helpers.convertWorkerExpressionToGlobals(
- node,
- isGlobal,
- this.dirname
- );
- globals = globals.concat(workerDetails);
- }
- return globals;
- },
- };
- module.exports = {
-
- getGlobalsForFile(filePath, astOptions = {}) {
- if (globalCache.has(filePath)) {
- return globalCache.get(filePath);
- }
- if (globalDiscoveryInProgressForFiles.has(filePath)) {
-
-
- return [];
- }
- globalDiscoveryInProgressForFiles.add(filePath);
- let content = fs.readFileSync(filePath, "utf8");
-
- let { ast, scopeManager, visitorKeys } = helpers.parseCode(
- content,
- astOptions
- );
-
- let globalScope = scopeManager.acquire(ast);
- let globals = Object.keys(globalScope.variables).map(v => ({
- name: globalScope.variables[v].name,
- writable: true,
- }));
-
- let handler = new GlobalsForNode(filePath);
- helpers.walkAST(ast, visitorKeys, (type, node, parents) => {
- if (type in handler) {
- let newGlobals = handler[type](node, parents, globalScope);
- globals.push.apply(globals, newGlobals);
- }
- });
- globalCache.set(filePath, globals);
- globalDiscoveryInProgressForFiles.delete(filePath);
- return globals;
- },
-
- getGlobalsForCode(code, astOptions = {}) {
-
- let { ast, scopeManager, visitorKeys } = helpers.parseCode(
- code,
- astOptions,
- { useBabel: false }
- );
-
- let globalScope = scopeManager.acquire(ast);
- let globals = Object.keys(globalScope.variables).map(v => ({
- name: globalScope.variables[v].name,
- writable: true,
- }));
-
- let handler = new GlobalsForNode(null);
- helpers.walkAST(ast, visitorKeys, (type, node, parents) => {
- if (type in handler) {
- let newGlobals = handler[type](node, parents, globalScope);
- globals.push.apply(globals, newGlobals);
- }
- });
- return globals;
- },
-
- getImportedGlobalsForHTMLFile(filePath) {
- if (lastHTMLGlobals.filename === filePath) {
- return lastHTMLGlobals.globals;
- }
- let dir = path.dirname(filePath);
- let globals = [];
- let content = fs.readFileSync(filePath, "utf8");
- let scriptSrcs = [];
-
- let parser = new htmlparser.Parser(
- {
- onopentag(name, attribs) {
- if (name === "script" && "src" in attribs) {
- scriptSrcs.push({
- src: attribs.src,
- type:
- "type" in attribs && attribs.type == "module"
- ? "module"
- : "script",
- });
- }
- },
- },
- {
- xmlMode: filePath.endsWith("xhtml"),
- }
- );
- parser.parseComplete(content);
- for (let script of scriptSrcs) {
-
- if (!script.src) {
- continue;
- }
- let scriptName;
- if (script.src.includes("http:")) {
-
- } else if (script.src.includes("chrome")) {
-
- script.src = script.src.replace("chrome://mochikit/content/", "/");
- scriptName = path.join(
- helpers.rootDir,
- "testing",
- "mochitest",
- script.src
- );
- } else if (script.src.includes("SimpleTest")) {
-
- scriptName = path.join(
- helpers.rootDir,
- "testing",
- "mochitest",
- script.src
- );
- } else if (script.src.startsWith("/tests/")) {
- scriptName = path.join(helpers.rootDir, script.src.substring(7));
- } else {
-
- scriptName = path.join(dir, script.src);
- }
- if (scriptName && fs.existsSync(scriptName)) {
- globals.push(
- ...module.exports.getGlobalsForFile(scriptName, {
- ecmaVersion: helpers.getECMAVersion(),
- sourceType: script.type,
- })
- );
- }
- }
- lastHTMLGlobals.filePath = filePath;
- return (lastHTMLGlobals.globals = globals);
- },
-
- getESLintGlobalParser(context) {
- let globalScope;
- let parser = {
- Program(node) {
- globalScope = context.getScope();
- },
- };
- let filename = context.getFilename();
- let extraHTMLGlobals = [];
- if (filename.endsWith(".html") || filename.endsWith(".xhtml")) {
- extraHTMLGlobals = module.exports.getImportedGlobalsForHTMLFile(filename);
- }
-
- let handler = new GlobalsForNode(helpers.getAbsoluteFilePath(context));
- for (let type of Object.keys(GlobalsForNode.prototype)) {
- parser[type] = function(node) {
- if (type === "Program") {
- globalScope = context.getScope();
- helpers.addGlobals(extraHTMLGlobals, globalScope);
- }
- let globals = handler[type](node, context.getAncestors(), globalScope);
- helpers.addGlobals(
- globals,
- globalScope,
- node.type !== "Program" && node
- );
- };
- }
- return parser;
- },
- };
|