Skip to content

Commit

Permalink
feat(referencesImport): support named exports accessed via namespace …
Browse files Browse the repository at this point in the history
…imports

* test(traverse): referencesImport
* feat(referencesImport): support named exports accessed via namespace imports
* feat(referencesImport): support `namespaceObj?.importName` and `namespaceObj["importName"]`
* refactor(referencesImport): simplify member expression computed branches
* test(referencesImport): aliased named import case
* fix(referencesImport): do not be fooled by import name "*"
  at least when detecting accessing a named import via a '*' import

Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
  • Loading branch information
jeysal and nicolo-ribaudo committed Feb 21, 2021
1 parent 33fbf84 commit 191a654
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 3 deletions.
23 changes: 20 additions & 3 deletions packages/babel-traverse/src/path/introspection.ts
Expand Up @@ -164,13 +164,30 @@ export function isStatementOrBlock(this: NodePath): boolean {
*/

export function referencesImport(
this: NodePath<t.Identifier>,
this: NodePath<t.Expression>,
moduleSource: string,
importName: string,
): boolean {
if (!this.isReferencedIdentifier()) return false;
if (!this.isReferencedIdentifier()) {
if (
(this.isMemberExpression() || this.isOptionalMemberExpression()) &&
(this.node.computed
? t.isStringLiteral(this.node.property, { value: importName })
: (this.node.property as t.Identifier).name === importName)
) {
const object = (this as NodePath<
t.MemberExpression | t.OptionalMemberExpression
>).get("object");
return (
object.isReferencedIdentifier() &&
object.referencesImport(moduleSource, "*")
);
}

return false;
}

const binding = this.scope.getBinding(this.node.name);
const binding = this.scope.getBinding((this.node as t.Identifier).name);
if (!binding || binding.kind !== "module") return false;

const path = binding.path;
Expand Down
104 changes: 104 additions & 0 deletions packages/babel-traverse/test/introspection.js
Expand Up @@ -100,4 +100,108 @@ describe("path/introspection", function () {
});
});
});

describe("referencesImport", function () {
it("accepts a default import", function () {
const program = getPath(`import dep from "source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "default")).toBe(true);
});
it("rejects a default import from the wrong module", function () {
const program = getPath(`import dep from "wrong-source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "default")).toBe(false);
});
it("rejects a named instead of default import", function () {
const program = getPath(`import { dep } from "source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "default")).toBe(false);
});

it("accepts a named import", function () {
const program = getPath(`import { dep } from "source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "dep")).toBe(true);
});
it("accepts an aliased named import", function () {
const program = getPath(`import { dep as alias } from "source"; alias;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "dep")).toBe(true);
});
it("accepts a named import via a namespace import member expression", function () {
const program = getPath(`import * as ns from "source"; ns.dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "dep")).toBe(true);
});
it("accepts a named import via a namespace import optional member expression", function () {
const program = getPath(`import * as ns from "source"; ns?.dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "dep")).toBe(true);
});
it("accepts a named import via a namespace import computed member expression", function () {
const program = getPath(`import * as ns from "source"; ns["😅"];`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "😅")).toBe(true);
});
it("rejects a named import from the wrong module", function () {
const program = getPath(`import { dep } from "wrong-source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "dep")).toBe(false);
});
it("rejects a default instead of named import", function () {
const program = getPath(`import dep from "source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "dep")).toBe(false);
});
it('rejects the "export called *" trick', function () {
const program = getPath(`import * as ns from "source"; ns["*"].nested;`, {
sourceType: "module",
plugins: ["moduleStringNames"],
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "nested")).toBe(false);
});

it("accepts a namespace import", function () {
const program = getPath(`import * as dep from "source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "*")).toBe(true);
});
it("rejects a namespace import from the wrong module", function () {
const program = getPath(`import * as dep from "wrong-source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "*")).toBe(false);
});
it("rejects a default instead of a namespace import", () => {
const program = getPath(`import dep from "source"; dep;`, {
sourceType: "module",
});
const reference = program.get("body.1.expression");
expect(reference.referencesImport("source", "*")).toBe(false);
});
});
});

0 comments on commit 191a654

Please sign in to comment.