Skip to content

Commit

Permalink
add guards support in JavascriptParser
Browse files Browse the repository at this point in the history
  • Loading branch information
vankop committed Mar 10, 2022
1 parent 770dea1 commit 967da80
Show file tree
Hide file tree
Showing 8 changed files with 417 additions and 44 deletions.
102 changes: 101 additions & 1 deletion lib/dependencies/HarmonyImportDependencyParserPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,29 @@ module.exports = class HarmonyImportDependencyParserPlugin {
*/
apply(parser) {
const { exportPresenceMode } = this;
/**
* @param {string[]} ids ids
* @returns {string} guard name
*/
const createGuard = ids => ids.join(".");
/**
* @param {string} guard guard
* @param {number} idsLength ids length
* @returns {number} mode
*/
const detectExportPresenceMode = (guard, idsLength) => {
if (exportPresenceMode === ExportPresenceModes.NONE)
return exportPresenceMode;
if (parser.scope.guards.has(guard)) return ExportPresenceModes.NONE;
if (
parser.scope.inGuardPosition &&
(idsLength === 1 ||
parser.scope.guards.has(guard.slice(0, guard.lastIndexOf("."))))
)
return ExportPresenceModes.NONE;

return exportPresenceMode;
};
parser.hooks.isPure
.for("Identifier")
.tap("HarmonyImportDependencyParserPlugin", expression => {
Expand Down Expand Up @@ -131,10 +154,84 @@ module.exports = class HarmonyImportDependencyParserPlugin {
return true;
}
);
parser.hooks.binaryExpression.tap(
"HarmonyImportDependencyParserPlugin",
expression => {
if (!parser.scope.inGuardPosition) return;
if (expression.operator === "in") {
const leftPartEvaluated = parser.evaluateExpression(expression.left);
if (!leftPartEvaluated || leftPartEvaluated.couldHaveSideEffects())
return;
const leftPart = leftPartEvaluated.asString();
if (!leftPart) return;

const rightPart = parser.evaluateExpression(expression.right);
if (!rightPart || !rightPart.isIdentifier()) return;

const rootInfo = rightPart.rootInfo;
if (
!rootInfo ||
!rootInfo.tagInfo ||
rootInfo.tagInfo.tag !== harmonySpecifierTag
)
return;
parser.walkExpression(rightPart.expression);
return true;
} else if (expression.operator === "!=") {
let identifierEvaluated;
const leftPartEvaluated = parser.evaluateExpression(expression.left);
if (!leftPartEvaluated) {
return;
} else if (leftPartEvaluated.isIdentifier()) {
const rootInfo = leftPartEvaluated.rootInfo;
if (
!rootInfo ||
!rootInfo.tagInfo ||
rootInfo.tagInfo.tag !== harmonySpecifierTag
)
return;
identifierEvaluated = leftPartEvaluated;
} else if (leftPartEvaluated.isFalsy() !== true) {
return;
}

const rightPartEvaluated = parser.evaluateExpression(
expression.right
);
if (!rightPartEvaluated) {
return;
} else if (
!identifierEvaluated &&
rightPartEvaluated.isIdentifier()
) {
const rootInfo = rightPartEvaluated.rootInfo;
if (
!rootInfo ||
!rootInfo.tagInfo ||
rootInfo.tagInfo.tag !== harmonySpecifierTag
)
return;
identifierEvaluated = rightPartEvaluated;
} else if (rightPartEvaluated.isFalsy() !== true) {
return;
}

// other hooks will add guards and dependencies
parser.walkExpression(identifierEvaluated.expression);
return true;
}
}
);
parser.hooks.expression
.for(harmonySpecifierTag)
.tap("HarmonyImportDependencyParserPlugin", expr => {
const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
const guard = createGuard(settings.ids);
const exportPresenceMode = detectExportPresenceMode(
guard,
settings.ids.length
);
if (parser.scope.inGuardPosition) parser.scope.guards.add(guard);
const dep = new HarmonyImportSpecifierDependency(
settings.source,
settings.sourceOrder,
Expand All @@ -157,6 +254,9 @@ module.exports = class HarmonyImportDependencyParserPlugin {
.tap("HarmonyImportDependencyParserPlugin", (expr, members) => {
const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
const ids = settings.ids.concat(members);
const guard = createGuard(ids);
const exportPresenceMode = detectExportPresenceMode(guard, ids.length);
if (parser.scope.inGuardPosition) parser.scope.guards.add(guard);
const dep = new HarmonyImportSpecifierDependency(
settings.source,
settings.sourceOrder,
Expand Down Expand Up @@ -184,7 +284,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
ids,
settings.name,
callee.range,
exportPresenceMode,
detectExportPresenceMode(createGuard(ids), ids.length),
settings.assertions
);
dep.directImport = members.length === 0;
Expand Down
11 changes: 11 additions & 0 deletions lib/javascript/BasicEvaluatedExpression.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,46 +299,57 @@ class BasicEvaluatedExpression {
this.type = TypeString;
this.string = string;
this.sideEffects = false;
if (string === "") this.falsy = true;
else this.truthy = true;
return this;
}

setUndefined() {
this.type = TypeUndefined;
this.sideEffects = false;
this.falsy = true;
return this;
}

setNull() {
this.type = TypeNull;
this.sideEffects = false;
this.falsy = true;
return this;
}

setNumber(number) {
this.type = TypeNumber;
this.number = number;
this.sideEffects = false;
if (number === 0) this.falsy = true;
else this.truthy = true;
return this;
}

setBigInt(bigint) {
this.type = TypeBigInt;
this.bigint = bigint;
this.sideEffects = false;
if (bigint === BigInt(0)) this.falsy = true;
else this.truthy = true;
return this;
}

setBoolean(bool) {
this.type = TypeBoolean;
this.bool = bool;
this.sideEffects = false;
if (bool === false) this.falsy = true;
else this.truthy = true;
return this;
}

setRegExp(regExp) {
this.type = TypeRegExp;
this.regExp = regExp;
this.sideEffects = false;
this.truthy = true;
return this;
}

Expand Down

0 comments on commit 967da80

Please sign in to comment.