mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
918f02dcc3
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52469 Organise `scripts/build-types/` and `scripts/diff-api-snapshot/` into a single grouping `scripts/js-api/` parent dir — matching the newly relocated `scripts/cxx-api/`. Changelog: [Internal] Reviewed By: robhogan Differential Revision: D77865488 fbshipit-source-id: 33754d9275e65c3bda686294f18d855221ec7bff
132 lines
3.6 KiB
JavaScript
132 lines
3.6 KiB
JavaScript
/**
|
|
* 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
|
|
* @format
|
|
* @oncall react_native
|
|
*/
|
|
|
|
const babel = require('@babel/core');
|
|
const t = require('@babel/types');
|
|
|
|
const Result = {
|
|
BREAKING: 'BREAKING',
|
|
POTENTIALLY_NON_BREAKING: 'POTENTIALLY_NON_BREAKING',
|
|
NON_BREAKING: 'NON_BREAKING',
|
|
} as const;
|
|
|
|
type Output = {
|
|
result: $Values<typeof Result>,
|
|
changedApis: Array<string>,
|
|
};
|
|
|
|
type Hash = string;
|
|
type APISpecifier = string;
|
|
|
|
function diffApiSnapshot(prevSnapshot: string, newSnapshot: string): Output {
|
|
const prevSnapshotAST = babel.parseSync(prevSnapshot, {
|
|
plugins: ['@babel/plugin-syntax-typescript'],
|
|
});
|
|
const newSnapshotAST = babel.parseSync(newSnapshot, {
|
|
plugins: ['@babel/plugin-syntax-typescript'],
|
|
});
|
|
|
|
const prevSpecHashPair = getExportedSymbols(prevSnapshotAST);
|
|
const newSpecHashPair = getExportedSymbols(newSnapshotAST);
|
|
|
|
if (prevSpecHashPair == null || newSpecHashPair == null) {
|
|
return {
|
|
result: Result.BREAKING,
|
|
changedApis: [],
|
|
};
|
|
}
|
|
|
|
return analyzeSpecHashPairs(prevSpecHashPair, newSpecHashPair);
|
|
}
|
|
|
|
function analyzeSpecHashPairs(
|
|
prevSpecHashPairs: Array<[APISpecifier, Hash]>,
|
|
newSpecHashPairs: Array<[APISpecifier, Hash]>,
|
|
): Output {
|
|
const output = {
|
|
result: Result.NON_BREAKING,
|
|
changedApis: [],
|
|
} as Output;
|
|
|
|
const newSpecHashMapping = Object.fromEntries(newSpecHashPairs);
|
|
for (const [name, hash] of prevSpecHashPairs) {
|
|
if (newSpecHashMapping[name]) {
|
|
const newHash = newSpecHashMapping[name];
|
|
if (hash !== newHash) {
|
|
// The hash has changed which means that the statement has changed
|
|
output.result = Result.BREAKING;
|
|
output.changedApis.push(name);
|
|
}
|
|
delete newSpecHashMapping[name];
|
|
} else {
|
|
// There is no statement of that name in the new rollup which means that:
|
|
// 1. This statement was entirely removed
|
|
// 2. This statement was renamed
|
|
// 3. It is not public anymore
|
|
output.result = Result.BREAKING;
|
|
output.changedApis.push(name);
|
|
}
|
|
}
|
|
|
|
if (
|
|
output.result === Result.NON_BREAKING &&
|
|
Object.keys(newSpecHashMapping).length > 0
|
|
) {
|
|
output.result = Result.POTENTIALLY_NON_BREAKING;
|
|
for (const name of Object.keys(newSpecHashMapping)) {
|
|
// saving new APIs
|
|
output.changedApis.push(name);
|
|
}
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
function getExportedSymbols(
|
|
ast: BabelNodeFile,
|
|
): Array<[APISpecifier, Hash]> | null {
|
|
for (const nodePath of ast.program.body) {
|
|
if (
|
|
t.isExportNamedDeclaration(nodePath) &&
|
|
!nodePath.declaration &&
|
|
nodePath.specifiers != null
|
|
) {
|
|
const specifiers = nodePath.specifiers;
|
|
const result: Array<[APISpecifier, Hash]> = [];
|
|
for (let i = 0; i < specifiers.length; i++) {
|
|
const specifier = specifiers[i];
|
|
const name = specifier.exported.name || '';
|
|
const comment =
|
|
specifier.leadingComments && specifier.leadingComments.length > 0
|
|
? specifier.leadingComments[0]?.value
|
|
: '';
|
|
|
|
if (i > 0) {
|
|
result[i - 1][1] = comment;
|
|
}
|
|
result.push([name, comment]);
|
|
}
|
|
|
|
const lastSpec = specifiers[specifiers.length - 1];
|
|
const comment =
|
|
lastSpec.trailingComments && lastSpec.trailingComments.length > 0
|
|
? lastSpec.trailingComments[0]?.value
|
|
: '';
|
|
result[result.length - 1][1] = comment;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
module.exports = {diffApiSnapshot, Result};
|