UNPKG

@syntest/analysis-javascript

Version:

SynTest CFG JavaScript is a library for generating control flow graphs for the JavaScript language

269 lines 9.73 kB
"use strict"; /* * Copyright 2020-2023 Delft University of Technology and SynTest contributors * * This file is part of SynTest Framework - SynTest JavaScript. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.extractExportsFromAssignmentExpression = void 0; const logging_1 = require("@syntest/logging"); function extractExportsFromAssignmentExpression(visitor, filePath, path_) { const exports = []; const left = path_.get("left"); const right = path_.get("right"); const partialExport = _checkExportAndDefault(visitor, left); if (!partialExport) { // not an export return []; } const module = true; if (partialExport.default && right.isObjectExpression()) { // module.exports = {...} // exports = {...} // so not default actually // extract the stuff from the object const properties = right.get("properties"); exports.push(..._extractObjectProperties(right, properties, visitor, filePath, module)); } else if (partialExport.default) { // module.exports = ? // exports = ? // but ? is not an object expression const id = visitor._getBindingId(right); const name = _getName(right); exports.push({ id: id, filePath: filePath, name: name, renamedTo: name, default: partialExport.default, module: module, }); } else { // module.exports.? = ? // exports.? = ? // ? can be object but we dont care since it is not a default export const id = visitor._getBindingId(right); const name = _getName(right); exports.push({ id: id, filePath: filePath, name: name === "default" ? partialExport.renamedTo : name, renamedTo: partialExport.renamedTo, default: partialExport.default, module: module, }); } return exports; } exports.extractExportsFromAssignmentExpression = extractExportsFromAssignmentExpression; function _extractObjectProperties(path, properties, visitor, filePath, module) { const default_ = false; const exports = []; for (const property of properties) { if (property.isObjectMethod()) { // {a () {}} const key = property.get("key"); if (!key.isIdentifier()) { // e.g. exports = { () {} } // unsupported // not possible i think throw new Error("Unsupported export declaration"); } exports.push({ id: visitor._getNodeId(property), filePath: filePath, name: key.node.name, renamedTo: key.node.name, default: default_, module: module, }); } else if (property.isObjectProperty()) { // {a: b} const key = property.get("key"); const value = property.get("value"); let keyName; if (key.isStringLiteral() || key.isNumericLiteral() || key.isBooleanLiteral() || key.isBigIntLiteral()) { // e.g. exports = { "a": ? } // e.g. exports = { 1: ? } // e.g. exports = { true: ? } keyName = String(key.node.value); } else if (key.isIdentifier()) { // e.g. exports = { a: ? } keyName = key.node.name; } else { // e.g. exports = { ?: ? } // unsupported throw new Error("Unsupported export declaration"); } if (value.isIdentifier()) { // e.g. exports = { a: b } exports.push({ id: visitor._getBindingId(value), filePath, name: value.node.name, renamedTo: keyName, default: default_, module: module, }); } else { // e.g. exports = { a: 1 } exports.push({ id: visitor._getBindingId(value), filePath, name: keyName, renamedTo: keyName, default: default_, module: module, }); } } else { // {...a} // unsupported if (visitor.syntaxForgiving) { // Log it (0, logging_1.getLogger)("ExportVisitor").warn(`Unsupported export declaration at ${visitor._getNodeId(path)}`); } else { throw new Error(`Unsupported export declaration at ${visitor._getNodeId(path)}`); } } } return exports; } function _getName(expression) { if (expression.isIdentifier()) { return expression.node.name; } if (expression.isLiteral() || expression.isArrayExpression() || expression.isObjectExpression()) { return expression.type; } if (expression.isFunction() || expression.isClass()) { if (!expression.has("id")) { return expression.isFunction() ? "anonymousFunction" : "anonymousClass"; } const id = expression.get("id"); // must be identifier type if it is a nodepath return id.node.name; } return "default"; } function _checkExportAndDefault(visitor, expression) { if (expression.isIdentifier() && expression.node.name === "exports") { // exports = ? return { default: true }; } else if (expression.isMemberExpression()) { // ?.? = ? const object = expression.get("object"); const property = expression.get("property"); if (object.isIdentifier()) { // ?.? = ? if (object.node.name === "module") { if ((!expression.node.computed && property.isIdentifier() && property.node.name === "exports") || (expression.node.computed && property.isStringLiteral() && property.node.value === "exports")) { // module.exports = ? // module['exports'] = ? return { default: true }; } else { // module[exports] = ? // TODO replace by logger console.warn(`Unsupported syntax 'module[x] = ?'`); } } else if (object.node.name === "exports") { // exports.? = ? const name = _getNameOfProperty(visitor, property, expression.node.computed); if (!name) { return false; } return { default: false, renamedTo: name, }; } } else if (object.isMemberExpression()) { // ?.?.? = ? const subObject = object.get("object"); const subProperty = object.get("property"); if (subObject.isIdentifier() && subObject.node.name === "module" && ((!object.node.computed && subProperty.isIdentifier() && subProperty.node.name === "exports") || (object.node.computed && subProperty.isStringLiteral() && subProperty.node.value === "exports"))) { // module.exports.? = ? // module['exports'].? = ? // module.exports[?] = ? const name = _getNameOfProperty(visitor, property, expression.node.computed); if (!name) { return false; } return { default: false, renamedTo: name, }; } } } return false; } function _getNameOfProperty(visitor, property, computed) { if (computed) { // module.exports[?] = ? if (property.isStringLiteral() || property.isNumericLiteral() || property.isBooleanLiteral() || property.isBigIntLiteral()) { // module.exports['x'] = ? return String(property.node.value); } else { // module.exports[a] = ? (0, logging_1.getLogger)("ExportVisitor").warn(`This tool does not support computed export statements. Found one at ${visitor._getNodeId(property)}`); return undefined; } } else if (property.isIdentifier()) { // module.exports.x = ? return property.node.name; } else { // module.exports.? = ? throw new Error('Unsupported syntax "module.exports.? = ?"'); } } //# sourceMappingURL=ExpressionStatement.js.map