Skip to content

Commit

Permalink
Improve handling nested scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
mvantellingen committed Apr 12, 2024
1 parent aa16c59 commit a850cca
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/tame-panthers-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@labdigital/intl-extractor": patch
---

Handle nested scopes better
17 changes: 17 additions & 0 deletions src/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,28 @@ describe("Test parseSource", () => {
<h1>{t("title")}</h1>
</div>
)
}
// Nested scope
export function MyOtherComponent = () => {
const t = useTranslations("MyComponent");
const content () => {
const foobar = t("foodiebar");
return (
<div>
<h1>{t("title")}</h1>
</div>
)
}
return content()
}
`;

const result = await parseSource("MyComponent.tsx", source);
const expected = {
foobar: "foobar",
foodiebar: "foodiebar",
title: "title",
};
expect(result).toEqual(expected);
Expand Down
44 changes: 31 additions & 13 deletions src/parse.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { promises as fsPromises } from "fs";
import ts from "typescript";

interface Scope {
variables: Set<string>;
parentScope: Scope | null;
}


export async function findTranslationsUsage(filePath: string) {
const fileContent = await fsPromises.readFile(filePath, "utf8");
return parseSource(filePath, fileContent);
Expand All @@ -19,21 +25,14 @@ export async function parseSource(filename: string, source: string) {
// Create a scope dictionary to track variables assigned from useTranslations
const scopes: Record<string, Set<string>> = {};

Check warning on line 26 in src/parse.ts

View workflow job for this annotation

GitHub Actions / Lint codebase

'scopes' is assigned a value but never used

// Function to create a new scope based on the node's position
function createScope(node: ts.Node): Set<string> {
const nodeScope = new Set<string>();
scopes[node.pos] = nodeScope;
return nodeScope;
}

// Visitor function that traverses the AST and logs calls to t()
function visit(node: ts.Node, currentScope: Set<string>) {
function visit(node: ts.Node, currentScope: Scope) {
if (
ts.isFunctionDeclaration(node) ||
ts.isBlock(node) ||
ts.isSourceFile(node)
) {
currentScope = createScope(node);
currentScope = createScope(currentScope);
}

// Check for variable declarations that initialize with useTranslations
Expand All @@ -48,7 +47,7 @@ export async function parseSource(filename: string, source: string) {
callExpr.expression.text === "useTranslations"
) {
if (node.name && ts.isIdentifier(node.name)) {
currentScope.add(node.name.text);
currentScope.variables.add(node.name.text);
}
}
}
Expand All @@ -68,7 +67,7 @@ export async function parseSource(filename: string, source: string) {
callExpr.expression.text === "getTranslations"
) {
if (node.name && ts.isIdentifier(node.name)) {
currentScope.add(node.name.text);
currentScope.variables.add(node.name.text);
}
}
}
Expand All @@ -77,7 +76,7 @@ export async function parseSource(filename: string, source: string) {
if (
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
currentScope.has(node.expression.text)
findVariableInScopes(node.expression.text, currentScope)
) {
const item = parseText(node);
if (item) {
Expand All @@ -91,11 +90,30 @@ export async function parseSource(filename: string, source: string) {
ts.forEachChild(node, (child) => visit(child, currentScope));
}

const globalScope = createScope(sourceFile);
const globalScope = createScope();
visit(sourceFile, globalScope);
return result;
}

function createScope(parentScope: Scope | null = null): Scope {
return {
variables: new Set<string>(),
parentScope
};
}

function findVariableInScopes(variableName: string, scope: Scope | null): boolean {
while (scope !== null) {
if (scope.variables.has(variableName)) {
return true;
}
scope = scope.parentScope; // Move to the next higher scope
}
return false;
}



function parseText(node: ts.CallExpression) {
const text = node.arguments[0];
if (ts.isStringLiteral(text)) {
Expand Down

0 comments on commit a850cca

Please sign in to comment.