mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Update JS API snapshot to group exports in single block (#52235)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52235 Adds `organizeDeclarations` transform, replacing `sortTypeDefinitions`. All `export declare ...` statements are now collected and represented at the end of the snapshot in a single `export {}` block — significantly improving readability and diffing. Changelog: [Internal] Reviewed By: j-piasecki Differential Revision: D77150017 fbshipit-source-id: 1bd451c0e2a18fd6fc0504970b10a5d2502ac872
This commit is contained in:
committed by
Facebook GitHub Bot
parent
08a59c59e0
commit
ece8ca82cd
@@ -36,10 +36,10 @@ const inputFilesPostTransforms: $ReadOnlyArray<PluginObj<mixed>> = [
|
||||
|
||||
const postTransforms: $ReadOnlyArray<PluginObj<mixed>> = [
|
||||
require('./transforms/typescript/stripUnstableApis'),
|
||||
require('./transforms/typescript/sortTypeDefinitions'),
|
||||
require('./transforms/typescript/sortProperties'),
|
||||
require('./transforms/typescript/sortUnions'),
|
||||
require('./transforms/removeUndefinedFromOptionalMembers'),
|
||||
require('./transforms/typescript/organizeDeclarations'),
|
||||
];
|
||||
|
||||
async function buildAPISnapshot(validate: boolean) {
|
||||
|
||||
+10
-9
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`sortTypeDefinitions should divide top-lelvel declarations into exported and non-exported sections 1`] = `
|
||||
exports[`organizeDeclarations should sort declarations and move exports into single export block 1`] = `
|
||||
"/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
@@ -9,16 +9,17 @@ exports[`sortTypeDefinitions should divide top-lelvel declarations into exported
|
||||
*/
|
||||
|
||||
import * as React from \\"react\\";
|
||||
export declare type ExportedFoo = \\"A\\" | \\"B\\";
|
||||
export declare type ExportedBar = null | string | number;
|
||||
export declare class ExportedBaz {
|
||||
foo: string;
|
||||
}
|
||||
export declare function exportedFn(): void;
|
||||
declare type Foo = \\"A\\" | \\"B\\";
|
||||
declare type Bar = null | string | number;
|
||||
declare class Baz {
|
||||
foo: string;
|
||||
}
|
||||
declare function fn(): void;"
|
||||
declare type ExportedBar = null | string | number;
|
||||
declare class ExportedBaz {
|
||||
foo: string;
|
||||
}
|
||||
declare function exportedFn(): void;
|
||||
declare type ExportedFoo = \\"A\\" | \\"B\\";
|
||||
declare function fn(): void;
|
||||
declare type Foo = \\"A\\" | \\"B\\";
|
||||
export { ExportedBar, ExportedBaz, ExportedFoo, exportedFn };"
|
||||
`;
|
||||
+5
-5
@@ -8,23 +8,23 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
const sortTypeDefinitionsVisitor = require('../sortTypeDefinitions');
|
||||
const organizeDeclarations = require('../organizeDeclarations');
|
||||
const babel = require('@babel/core');
|
||||
const {promises: fs} = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function translate(code: string): Promise<string> {
|
||||
const result = await babel.transformAsync(code, {
|
||||
plugins: ['@babel/plugin-syntax-typescript', sortTypeDefinitionsVisitor],
|
||||
plugins: ['@babel/plugin-syntax-typescript', organizeDeclarations],
|
||||
});
|
||||
|
||||
return result.code;
|
||||
}
|
||||
|
||||
describe('sortTypeDefinitions', () => {
|
||||
test('should divide top-lelvel declarations into exported and non-exported sections', async () => {
|
||||
describe('organizeDeclarations', () => {
|
||||
test('should sort declarations and move exports into single export block', async () => {
|
||||
const code = await fs.readFile(
|
||||
path.join(__dirname, '../__fixtures__/sortTypeDefinitions.d.ts'),
|
||||
path.join(__dirname, '../__fixtures__/organizeDeclarations.d.ts'),
|
||||
'utf-8',
|
||||
);
|
||||
const result = await translate(code);
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
import type {PluginObj} from '@babel/core';
|
||||
|
||||
import * as t from '@babel/types';
|
||||
|
||||
/**
|
||||
* A visitor that organizes top level type declarations into our desired API
|
||||
* snapshot format.
|
||||
*
|
||||
* - Sorts declarations alphabetically.
|
||||
* - Moves all exports into a single block at the end of the file.
|
||||
*/
|
||||
const visitor: PluginObj<mixed> = {
|
||||
visitor: {
|
||||
Program(path) {
|
||||
const exportedIdentifiers: Set<string> = new Set();
|
||||
|
||||
// Collect exported identifiers
|
||||
path.get('body').forEach(nodePath => {
|
||||
if (nodePath.isExportNamedDeclaration()) {
|
||||
if (nodePath.node.declaration) {
|
||||
const declaration = nodePath.node.declaration;
|
||||
if (
|
||||
t.isTSInterfaceDeclaration(declaration) ||
|
||||
t.isTSTypeAliasDeclaration(declaration) ||
|
||||
t.isFunctionDeclaration(declaration) ||
|
||||
t.isClassDeclaration(declaration) ||
|
||||
t.isVariableDeclaration(declaration) ||
|
||||
t.isTSDeclareFunction(declaration) ||
|
||||
t.isTSModuleDeclaration(declaration) ||
|
||||
t.isTSEnumDeclaration(declaration)
|
||||
) {
|
||||
if (declaration.id && declaration.id.name != null) {
|
||||
exportedIdentifiers.add(declaration.id.name);
|
||||
} else if (
|
||||
t.isVariableDeclaration(declaration) &&
|
||||
declaration.declarations.length > 0
|
||||
) {
|
||||
declaration.declarations.forEach(declarator => {
|
||||
if (t.isIdentifier(declarator.id)) {
|
||||
exportedIdentifiers.add(declarator.id.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
nodePath.replaceWith(declaration); // Remove export
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unexpected declaration type for top-level export: ${declaration.type}`,
|
||||
);
|
||||
}
|
||||
} else if (nodePath.node.specifiers) {
|
||||
nodePath.node.specifiers.forEach(specifier => {
|
||||
if (specifier.type === 'ExportSpecifier') {
|
||||
exportedIdentifiers.add(specifier.local.name);
|
||||
}
|
||||
});
|
||||
nodePath.remove(); // Remove export statement
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Sort declarations alphabetically
|
||||
path.node.body.sort((a, b) => {
|
||||
const aName = a.id?.name || '';
|
||||
const bName = b.id?.name || '';
|
||||
return aName.localeCompare(bName);
|
||||
});
|
||||
|
||||
// Move all exports into single `export {}` block
|
||||
if (exportedIdentifiers.size > 0) {
|
||||
const sortedIdentifiers = Array.from(exportedIdentifiers).sort();
|
||||
const exportStatement = t.exportNamedDeclaration(
|
||||
// $FlowIgnore[incompatible-call]
|
||||
null,
|
||||
sortedIdentifiers.map(name =>
|
||||
t.exportSpecifier(t.identifier(name), t.identifier(name)),
|
||||
),
|
||||
);
|
||||
path.pushContainer('body', exportStatement);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = visitor;
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
import type {PluginObj} from '@babel/core';
|
||||
|
||||
import * as t from '@babel/types';
|
||||
|
||||
const visitor: PluginObj<mixed> = {
|
||||
visitor: {
|
||||
Program(path) {
|
||||
path.node.body.sort((a, b) => {
|
||||
// Push import declarations at the top of the file
|
||||
if (t.isImportDeclaration(a) && !t.isImportDeclaration(b)) {
|
||||
return -1;
|
||||
} else if (!t.isImportDeclaration(a) && t.isImportDeclaration(b)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const aExported = t.isExportNamedDeclaration(a);
|
||||
const bExported = t.isExportNamedDeclaration(b);
|
||||
|
||||
// Push exported declarations before non-exported declarations
|
||||
if (aExported && !bExported) {
|
||||
return -1;
|
||||
} else if (!aExported && bExported) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = visitor;
|
||||
Reference in New Issue
Block a user