Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/

const replaceNullablePropertiesWithUndefined = require('../replaceNullablePropertiesWithUndefined.js');
const {parse, print} = require('hermes-transform');

const prettierOptions = {parser: 'babel'};

async function translate(code: string): Promise<string> {
const parsed = await parse(code);
const result = await replaceNullablePropertiesWithUndefined(parsed);
return print(result.ast, result.mutatedCode, prettierOptions);
}

describe('replaceNullablePropertiesWithUndefined', () => {
test('should not replace nullable with undefined outside object type definition', async () => {
const code = `function foo(arg: ?string) {}`;
const result = await translate(code);
expect(result).toMatchInlineSnapshot(`
"function foo(arg: ?string) {}
"
`);
});

test('should replace nullable with undefined inside object type definition', async () => {
const code = `type Foo = {bar: ?string};`;
const result = await translate(code);
expect(result).toMatchInlineSnapshot(`
"type Foo = { bar: string | undefined };
"
`);
});

test('should replace nullable with undefined inside nested object type definition', async () => {
const code = `type Foo = {bar: {baz: ?string}};`;
const result = await translate(code);
expect(result).toMatchInlineSnapshot(`
"type Foo = { bar: { baz: string | undefined } };
"
`);
});

test('should replace nullable with undefined in function inside object type definition', async () => {
const code = `type Foo = {bar: (?string) => void};`;
const result = await translate(code);
expect(result).toMatchInlineSnapshot(`
"type Foo = { bar: (string | undefined) => void };
"
`);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/

import type {ESNode, TypeAnnotationType} from 'hermes-estree';
import type {TransformVisitor} from 'hermes-transform';
import type {ParseResult} from 'hermes-transform/dist/transform/parse';
import type {TransformASTResult} from 'hermes-transform/dist/transform/transformAST';

const {transformAST} = require('hermes-transform/dist/transform/transformAST');

function isInsideObjectTypeProperty(node: TypeAnnotationType) {
let current: ESNode = node;
while (current) {
if (current.type === 'ObjectTypeProperty') {
return true;
}
current = current.parent;
}
return false;
}

const visitors: TransformVisitor = context => ({
NullableTypeAnnotation(node): void {
if (!isInsideObjectTypeProperty(node)) {
return;
}

// $FlowExpectedError[incompatible-call] - UnionTypeAnnotation is not assignable to NullableTypeAnnotation
context.replaceNode(node, {
type: 'UnionTypeAnnotation',
types: [
node.typeAnnotation,
{
type: 'GenericTypeAnnotation',
id: {
type: 'Identifier',
name: 'undefined',
},
},
],
});
},
});

/**
* Replaces all Stringish type references with string
*/
async function replaceNullablePropertiesWithUndefined(
source: ParseResult,
): Promise<TransformASTResult> {
return transformAST(source, visitors);
}

module.exports = replaceNullablePropertiesWithUndefined;
1 change: 1 addition & 0 deletions scripts/build/build-types/translateSourceFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const preTransforms: Array<PreTransformFn> = [
require('./transforms/replaceRequiresWithImports'),
require('./transforms/replaceEmptyWithNever'),
require('./transforms/replaceStringishWithString'),
require('./transforms/replaceNullablePropertiesWithUndefined'),
];
const postTransforms: Array<PluginObj<mixed>> = [];
const prettierOptions = {parser: 'babel'};
Expand Down