Skip to content

Commit

Permalink
No longer try all child node constructors.
Browse files Browse the repository at this point in the history
  • Loading branch information
cpojer committed Dec 12, 2024
1 parent 6841f4c commit 445a82c
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -609,11 +609,11 @@ export default class FbtFunctionCallProcessor {
);
fbtCallArgs[0] = fbtContentsNode;

const elementNode = FbtElementNode.fromNode({
const elementNode = FbtElementNode.fromNode(
moduleName,
node,
validExtraOptions: this.validFbtExtraOptions,
});
this.validFbtExtraOptions,
);
if (elementNode == null) {
throw errorAt(
node,
Expand Down
75 changes: 31 additions & 44 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtElementNode.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
CallExpression,
Expression,
identifier,
isArrayExpression,
isCallExpression,
Expand All @@ -21,6 +20,7 @@ import {
ValidFbtOptions,
ValidPronounUsagesKeys,
} from '../FbtConstants.tsx';
import FbtNodeChecker from '../FbtNodeChecker.tsx';
import type { CallExpressionArg, ParamSet } from '../FbtUtil.tsx';
import {
collectOptionsFromFbtConstruct,
Expand Down Expand Up @@ -48,6 +48,7 @@ import type FbtImplicitParamNodeType from './FbtImplicitParamNode.tsx';
import FbtNameNode from './FbtNameNode.tsx';
import type { AnyFbtNode, FbtChildNode } from './FbtNode.tsx';
import FbtNode from './FbtNode.tsx';
import { FbtNodeType } from './FbtNodeType.tsx';
import {
buildFbtNodeMapForSameParam,
getChildNodeText,
Expand Down Expand Up @@ -103,6 +104,19 @@ export interface IFbtElementNode {
registerToken(name: string, source: AnyFbtNode): void;
}

const childNodeClasses = new Map(
[
FbtEnumNode,
FbtNameNode,
FbtParamNode,
FbtPluralNode,
FbtPronounNode,
FbtSameParamNode,
].map(
(Constructor) => [Constructor.type as FbtNodeType, Constructor] as const,
),
);

/**
* Represents the main fbt() or <fbt> construct.
* Every nested fbt construct will be reachable from the `children` property.
Expand Down Expand Up @@ -299,15 +313,11 @@ export default class FbtElementNode
* Create a new class instance given a node root node.
* If that node is incompatible, we'll just return `null`.
*/
static fromNode({
moduleName,
node,
validExtraOptions,
}: {
moduleName: BindingName;
node: Expression;
validExtraOptions: Readonly<FbtOptionConfig>;
}): FbtElementNode | null {
static fromNode(
moduleName: BindingName,
node: Node,
validExtraOptions: Readonly<FbtOptionConfig>,
): FbtElementNode | null {
if (!isCallExpression(node)) {
return null;
}
Expand All @@ -334,53 +344,30 @@ export default class FbtElementNode
if (isSpreadElement(elementChild)) {
throw errorAt(elementChild, `Array spread syntax is not supported`);
}
fbtElement.appendChild(
this.createChildNode({
moduleName,
node: elementChild,
}),
);
fbtElement.appendChild(this.createChildNode(moduleName, elementChild));
}
return fbtElement;
}

/**
* Create a child fbt node for a given node.
*/
static createChildNode({
moduleName,
node,
}: {
moduleName: BindingName;
node: Expression;
}): FbtChildNode {
let fbtChildNode;
const fbtChildNodeClasses = [
FbtEnumNode,
FbtNameNode,
FbtParamNode,
FbtPluralNode,
FbtPronounNode,
FbtSameParamNode,
FbtTextNode,
];

for (const Constructor of fbtChildNodeClasses) {
fbtChildNode = Constructor.fromNode({ moduleName, node });
if (fbtChildNode != null) {
break;
}
}
static createChildNode(moduleName: BindingName, node: Node): FbtChildNode {
const nodeType = FbtNodeChecker.forModule(moduleName).getFbtNodeType(node);
const Constructor = nodeType ? childNodeClasses.get(nodeType) : null;
let childNode: FbtChildNode | null =
Constructor?.fromNode(moduleName, node) ||
FbtTextNode.fromNode(moduleName, node);

// Try to convert to FbtImplicitParamNode as a last resort
if (fbtChildNode == null && isJSXElement(node)) {
if (childNode == null && isJSXElement(node)) {
// Later on, we should only allow non-fbt JSX elements here for auto-wrapping.
// fbt:param, fbt:pronoun, etc... should appear as children of it.
fbtChildNode = FbtImplicitParamNode.fromNode({ moduleName, node });
childNode = FbtImplicitParamNode.fromNode(moduleName, node);
}

if (fbtChildNode != null) {
return fbtChildNode;
if (childNode != null) {
return childNode;
}

throw errorAt(node, `${moduleName}: unsupported node: ${node.type}`);
Expand Down
10 changes: 2 additions & 8 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtEnumNode.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
CallExpression,
Expression,
isArrayExpression,
isCallExpression,
isIdentifier,
Expand Down Expand Up @@ -48,15 +47,10 @@ export default class FbtEnumNode extends FbtNode<
null,
Options
> {
static readonly type = 'enum';
readonly type = 'enum';

static fromNode({
moduleName,
node,
}: {
moduleName: BindingName;
node: Expression;
}): FbtEnumNode | null {
static fromNode(moduleName: BindingName, node: Node): FbtEnumNode | null {
if (!isCallExpression(node)) {
return null;
}
Expand Down
37 changes: 16 additions & 21 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtImplicitParamNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ObjectExpression,
} from '@babel/types';
import invariant from 'invariant';
import { BindingName } from '../FbtConstants.tsx';
import type { ParamSet } from '../FbtUtil.tsx';
import {
convertToStringArrayNodeIfNeeded,
Expand All @@ -30,7 +31,6 @@ import type { IFbtElementNode } from './FbtElementNode.tsx';
import FbtElementNode from './FbtElementNode.tsx';
import type { AnyFbtNode, FbtChildNode, PlainFbtNode } from './FbtNode.tsx';
import FbtNode from './FbtNode.tsx';
import type { FromNodeArgs } from './FbtNodeUtil.tsx';
import {
convertIndexInSiblingsArrayToOuterTokenAlias,
convertToTokenName,
Expand Down Expand Up @@ -199,10 +199,10 @@ export default class FbtImplicitParamNode
* Create a new class instance given a root node.
* If that node is incompatible, we'll just return `null`.
*/
static fromNode({
moduleName,
node,
}: FromNodeArgs): FbtImplicitParamNode | null {
static fromNode(
moduleName: BindingName,
node: Node,
): FbtImplicitParamNode | null {
if (!isJSXElement(node)) {
return null;
}
Expand Down Expand Up @@ -238,14 +238,11 @@ export default class FbtImplicitParamNode
}
} else if (unusedWhitespaceChild != null) {
fbtChildren.push(
FbtTextNode.fromNode({
moduleName,
node: unusedWhitespaceChild,
}),
FbtTextNode.fromNode(moduleName, unusedWhitespaceChild),
);
unusedWhitespaceChild = null;
}
fbtChildren.push(FbtTextNode.fromNode({ moduleName, node: child }));
fbtChildren.push(FbtTextNode.fromNode(moduleName, child));
lastAddedChild = child;
break;

Expand All @@ -260,22 +257,22 @@ export default class FbtImplicitParamNode
convertToStringArrayNodeIfNeeded(moduleName, expression)
.elements || ([] as Array<null>);

elements.forEach((elem) => {
if (elem == null) {
return;
for (const element of elements) {
if (element == null) {
continue;
}
if (elem.type !== 'StringLiteral') {
if (element.type !== 'StringLiteral') {
throw errorAt(
child,
`${moduleName}: only string literals (or concatenations of string literals) ` +
`are supported inside JSX expressions, ` +
`but we found the node type "${elem.type}" instead.`,
`but we found the node type "${element.type}" instead.`,
);
}
fbtChildren.push(
FbtElementNode.createChildNode({ moduleName, node: elem }),
FbtElementNode.createChildNode(moduleName, element),
);
});
}
unusedWhitespaceChild = null;
lastAddedChild = child;
continue;
Expand All @@ -287,17 +284,15 @@ export default class FbtImplicitParamNode
}

fbtChildren.push(
FbtElementNode.createChildNode({ moduleName, node: expression }),
FbtElementNode.createChildNode(moduleName, expression),
);
unusedWhitespaceChild = null;
lastAddedChild = child;
break;
}

case 'JSXElement': {
fbtChildren.push(
FbtElementNode.createChildNode({ moduleName, node: child }),
);
fbtChildren.push(FbtElementNode.createChildNode(moduleName, child));
unusedWhitespaceChild = null;
lastAddedChild = child;
break;
Expand Down
11 changes: 3 additions & 8 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtNameNode.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
CallExpression,
Expression,
isCallExpression,
isStringLiteral,
Node,
stringLiteral,
} from '@babel/types';
import invariant from 'invariant';
Expand Down Expand Up @@ -38,6 +38,7 @@ export default class FbtNameNode extends FbtNode<
null,
Options
> {
static readonly type = 'name';
readonly type = 'name';

override getOptions(): Options {
Expand Down Expand Up @@ -67,13 +68,7 @@ export default class FbtNameNode extends FbtNode<
}
}

static fromNode({
moduleName,
node,
}: {
moduleName: BindingName;
node: Expression;
}): FbtNameNode | null {
static fromNode(moduleName: BindingName, node: Node): FbtNameNode | null {
if (!isCallExpression(node)) {
return null;
}
Expand Down
6 changes: 0 additions & 6 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtNodeUtil.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Node } from '@babel/types';
import invariant from 'invariant';
import type { BindingName } from '../FbtConstants.tsx';
import { errorAt, normalizeSpaces, varDump } from '../FbtUtil.tsx';
import type { TokenAliases } from '../index.tsx';
import type { StringVariationArgsMap } from './FbtArguments.tsx';
Expand Down Expand Up @@ -34,11 +33,6 @@ import type { AnyFbtNode, FbtChildNode, PlainFbtNode } from './FbtNode.tsx';
*/
import FbtSameParamNode from './FbtSameParamNode.tsx';

export type FromNodeArgs = {
moduleName: BindingName;
node: Node;
};

/**
* Returns the closest ancestor node of type: FbtElementNode | FbtImplicitParamNode
*/
Expand Down
9 changes: 2 additions & 7 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtParamNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export default class FbtParamNode extends FbtNode<
null,
Options
> {
static readonly type = 'param';
readonly type = 'param';

override getOptions(): Options {
Expand Down Expand Up @@ -125,13 +126,7 @@ export default class FbtParamNode extends FbtNode<
}
}

static fromNode({
moduleName,
node,
}: {
moduleName: BindingName;
node: Expression;
}): FbtParamNode | null {
static fromNode(moduleName: BindingName, node: Node): FbtParamNode | null {
if (!isCallExpression(node)) {
return null;
}
Expand Down
11 changes: 3 additions & 8 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtPluralNode.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
CallExpression,
Expression,
isCallExpression,
isStringLiteral,
Node,
stringLiteral,
} from '@babel/types';
import invariant from 'invariant';
Expand Down Expand Up @@ -52,15 +52,10 @@ export default class FbtPluralNode extends FbtNode<
null,
Options
> {
static readonly type = 'plural';
readonly type = 'plural';

static fromNode({
moduleName,
node,
}: {
moduleName: BindingName;
node: Expression;
}): FbtPluralNode | null {
static fromNode(moduleName: BindingName, node: Node): FbtPluralNode | null {
if (!isCallExpression(node)) {
return null;
}
Expand Down
11 changes: 3 additions & 8 deletions packages/babel-plugin-fbtee/src/fbt-nodes/FbtPronounNode.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {
CallExpression,
Expression,
identifier,
isCallExpression,
isStringLiteral,
Node,
numericLiteral,
objectExpression,
objectProperty,
Expand Down Expand Up @@ -59,15 +59,10 @@ export default class FbtPronounNode extends FbtNode<
null,
Options
> {
static readonly type = 'pronoun';
readonly type = 'pronoun';

static fromNode({
moduleName,
node,
}: {
moduleName: BindingName;
node: Expression;
}): FbtPronounNode | null {
static fromNode(moduleName: BindingName, node: Node): FbtPronounNode | null {
if (!isCallExpression(node)) {
return null;
}
Expand Down
Loading

0 comments on commit 445a82c

Please sign in to comment.