Skip to content

Commit

Permalink
Add support for Symbol member expression in class method definition (#…
Browse files Browse the repository at this point in the history
…1602)

Summary:


## Summary:
This diff introduces support for [Symbol.iterator] and [Symbol.asyncIterator] as a method definition in flow defs generation. It can be confirmed in the flow lexer that these are the only two tokens prefixed with `@@`. Previously, that type of code wasn't supported and caused an exception:

```js
export default {
  [Symbol.iterator]() {};
  [Symbol.asyncIterator]() {};
}
```

The generated output if the type is not specified should be:

```js
declare export default {
  @iterator(): void;
  @asyncIterator(): void;
}
```

There are a few places in react-native source that will benefit from this, like: DOMRectList, URLSeachParams, NodeList and HTMLCollection.

Changelog:
[flow-api-translator] - Added support for Symbol member expression in class method definition

Reviewed By: pieterv

Differential Revision: D68766740
  • Loading branch information
coado authored and facebook-github-bot committed Jan 29, 2025
1 parent bfb595f commit 1917c0f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,16 @@ describe('flowToFlowDef', () => {
static 2(): void;
}`,
);
await expectTranslate(
`export class A {
[Symbol.iterator]() {}
static get [Symbol.asyncIterator]() {}
}`,
`declare export class A {
@@iterator(): void;
static get @@asyncIterator(): void;
}`,
);
});
});
describe('InterfaceDeclaration', () => {
Expand Down
21 changes: 18 additions & 3 deletions tools/hermes-parser/js/flow-api-translator/src/flowToFlowDef.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import {
isStringLiteral,
isNumericLiteral,
isIdentifier,
isMemberExpressionWithNonComputedProperty,
} from 'hermes-estree';

const EMPTY_TRANSLATION_RESULT = [null, []];
Expand Down Expand Up @@ -1218,7 +1219,13 @@ function convertClassMember(
if (
!isIdentifier(member.key) &&
!isStringLiteral(member.key) &&
!isNumericLiteral(member.key)
!isNumericLiteral(member.key) &&
!(
isMemberExpressionWithNonComputedProperty(member.key) &&
member.key.object.type === 'Identifier' &&
member.key.object.name === 'Symbol' &&
['iterator', 'asyncIterator'].includes(member.key.property.name)
)
) {
throw translationError(
member.key,
Expand All @@ -1229,15 +1236,23 @@ function convertClassMember(

const [resultValue, deps] = convertAFunction(member.value, context);

const newKey =
isMemberExpressionWithNonComputedProperty(member.key) &&
member.key.object.type === 'Identifier' &&
member.key.object.name === 'Symbol'
? t.Identifier({name: `@@${member.key.property.name}`})
: member.key;

if (member.kind === 'get' || member.kind === 'set') {
// accessors are methods - but flow accessor signatures are properties
const kind = member.kind;

return [
t.ObjectTypeAccessorSignature({
// $FlowFixMe[incompatible-call]
key: asDetachedNode<
ClassPropertyNameComputed | ClassPropertyNameNonComputed,
>(member.key),
>(newKey),
value: resultValue,
static: member.static,
kind,
Expand All @@ -1251,7 +1266,7 @@ function convertClassMember(
// $FlowFixMe[incompatible-call]
key: asDetachedNode<
ClassPropertyNameComputed | ClassPropertyNameNonComputed,
>(member.key),
>(newKey),
value: resultValue,
static: member.static,
}),
Expand Down

0 comments on commit 1917c0f

Please sign in to comment.