mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-02 02:08:24 +08:00
This CL introduces a PRESUBMIT that will: 1. run `npm run regenerate-all-component-bridges` 2. Check that the git diff is clean. If the git diff is not clean, it will fail. If the bridge has to be manually edited (e.g. to work around a bug in the generator), it must have a comment that matches the pattern `MANUALLY_EDITED_BRIDGE=...`. The regeneration script will ignore bridges that contain these. Change-Id: I372a3cd17a8e94bcdcea69ef64db189d2be6bde1 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2364597 Commit-Queue: Jack Franklin <jacktfranklin@chromium.org> Reviewed-by: Tim van der Lippe <tvanderlippe@chromium.org>
123 lines
4.5 KiB
TypeScript
123 lines
4.5 KiB
TypeScript
// Copyright 2020 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
import {generateClosureBridge, GeneratedCode} from './generate_closure.js';
|
|
import {filePathToTypeScriptSourceFile, walkTree} from './walk_tree.js';
|
|
|
|
const chromeLicense = `// Copyright ${new Date().getFullYear()} The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
`;
|
|
|
|
const getFullBridgeFilePath = (inputFilePath: string) => {
|
|
const dir = path.dirname(inputFilePath);
|
|
const baseName = path.basename(inputFilePath, '.ts');
|
|
return path.join(dir, `${baseName}_bridge.js`);
|
|
};
|
|
|
|
export const writeToDisk = (inputFilePath: string, generatedCode: GeneratedCode) => {
|
|
const baseName = path.basename(inputFilePath, '.ts');
|
|
const outputFileName = getFullBridgeFilePath(inputFilePath);
|
|
|
|
const importStatement = `import './${baseName}.js';`;
|
|
|
|
const types = generatedCode.types
|
|
.map(typePart => {
|
|
return typePart.join('\n');
|
|
})
|
|
.join('\n');
|
|
const classDeclaration = generatedCode.closureClass.join('\n');
|
|
const creatorFunction = generatedCode.creatorFunction.join('\n');
|
|
|
|
/*
|
|
* We replace any `\` with `/` here because the PRESUBMIT check rebuilds all
|
|
* bridge files And if we let it use OS-specific separators when outputting
|
|
* this comment it'll be different on Linux vs Windows systems. So to keep the
|
|
* output consistent we ensure we use Linux style separators here. This is
|
|
* only a comment to help the developer find the source file, so it's not a
|
|
* problem that the path isn't accurate on Windows.
|
|
*/
|
|
const relativeFilePath = path.relative(process.cwd(), inputFilePath).replace(/\\/g, '/');
|
|
|
|
const byHandWarning = `/**
|
|
* WARNING: do not modify this file by hand!
|
|
* it was automatically generated by the bridge generator
|
|
* if you made changes to the source code and need to update this file, run:
|
|
* npm run generate-bridge-file ${relativeFilePath}
|
|
*/
|
|
`;
|
|
|
|
// extra \n to ensure ending with a linebreak at end of file
|
|
const finalCode =
|
|
[chromeLicense, byHandWarning, importStatement, types, classDeclaration, creatorFunction].join('\n') + '\n';
|
|
|
|
fs.writeFileSync(outputFileName, finalCode, {encoding: 'utf8'});
|
|
|
|
return {
|
|
output: outputFileName,
|
|
code: finalCode,
|
|
};
|
|
};
|
|
|
|
interface Options {
|
|
forceRewriting: boolean;
|
|
silenceOutput: boolean;
|
|
}
|
|
|
|
const checkForManuallyEditedBridgeFile = (componentSourceFilePath: string): boolean => {
|
|
const bridgeFilePath = getFullBridgeFilePath(componentSourceFilePath);
|
|
if (!fs.existsSync(bridgeFilePath)) {
|
|
return false;
|
|
}
|
|
|
|
const contentsOfBridge = fs.readFileSync(bridgeFilePath, {encoding: 'utf-8'});
|
|
return contentsOfBridge.includes('MANUALLY_EDITED_BRIDGE=');
|
|
};
|
|
|
|
export const parseTypeScriptComponent = (componentSourceFilePath: string, options: Options = {
|
|
forceRewriting: false,
|
|
silenceOutput: false,
|
|
}) => {
|
|
if (!options.silenceOutput) {
|
|
console.log(`\n${path.basename(componentSourceFilePath)}`);
|
|
}
|
|
const hasManuallyEditedBridge = checkForManuallyEditedBridgeFile(componentSourceFilePath);
|
|
if (hasManuallyEditedBridge && !options.forceRewriting) {
|
|
if (!options.silenceOutput) {
|
|
console.log('Skipping bridge generation; existing bridge file contains a `MANUALLY_EDITED_BRIDGE=` comment.');
|
|
console.log('To regenerate, pass the `--force` flag or remove that comment from the existing bridge and re-run.');
|
|
}
|
|
return {output: undefined, code: undefined};
|
|
}
|
|
|
|
const file = filePathToTypeScriptSourceFile(componentSourceFilePath);
|
|
const state = walkTree(file, componentSourceFilePath);
|
|
const generatedCode = generateClosureBridge(state);
|
|
return writeToDisk(componentSourceFilePath, generatedCode);
|
|
};
|
|
|
|
export const main = (args: string[]) => {
|
|
const bridgeComponentPath = path.resolve(process.cwd(), args[0]);
|
|
const forceRewriting = args.includes('--force');
|
|
const silenceOutput = args.includes('--silent');
|
|
|
|
if (!bridgeComponentPath || !fs.existsSync(bridgeComponentPath)) {
|
|
throw new Error(`Could not find bridgeComponent path ${bridgeComponentPath}`);
|
|
}
|
|
|
|
const {output} = parseTypeScriptComponent(bridgeComponentPath, {forceRewriting, silenceOutput});
|
|
|
|
if (output && !silenceOutput) {
|
|
console.log('Wrote bridge file to', path.relative(process.cwd(), output));
|
|
}
|
|
|
|
return output;
|
|
};
|
|
|
|
if (require.main === module) {
|
|
main(process.argv.slice(2));
|
|
}
|