diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 00000000000..c955f0ad4d5 --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1,6 @@ +packages/react-native/React/I18n/FBXXHashUtils.h +packages/react-native/ReactAndroid/src/main/jni/first-party/yogajni/** +packages/react-native/ReactAndroid/src/main/jni/third-party/** +packages/react-native/ReactCommon/**/platform/windows/third-party/** +packages/react-native/ReactCommon/jsi/jsi/** +packages/react-native/ReactCommon/yoga/** diff --git a/package.json b/package.json index 6170f7f2a32..b9e9c8c3f42 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "build-android": "./gradlew :packages:react-native:ReactAndroid:build", "build": "node ./scripts/build/build.js", "build-types": "node ./scripts/js-api/build-types", - "clang-format": "clang-format -i --glob=*/**/*.{h,cpp,m,mm}", + "clang-format": "node ./scripts/clang-format.js", "clean": "node ./scripts/build/clean.js", "cxx-api-build": "python -m scripts.cxx-api.parser", "cxx-api-validate": "python -m scripts.cxx-api.parser --validate", @@ -70,7 +70,6 @@ "babel-plugin-minify-dead-code-elimination": "^0.5.2", "babel-plugin-transform-define": "^2.1.4", "babel-plugin-transform-flow-enums": "^0.0.2", - "clang-format": "^1.8.0", "connect": "^3.6.5", "debug": "^4.4.0", "deep-equal": "1.1.1", diff --git a/scripts/clang-format b/scripts/clang-format new file mode 100755 index 00000000000..d86751f1e84 --- /dev/null +++ b/scripts/clang-format @@ -0,0 +1,77 @@ +#!/usr/bin/env dotslash + +// 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. + +{ + "name": "clang-format 21.1.2", + "platforms": { + "linux-aarch64": { + "size": 1725525, + "hash": "sha256", + "digest": "f66d2bcf98df1373df6ab4544a2b881e9816985b606e1144e4c77dc8ac87b826", + "providers": [ + { + "type": "http", + "url": "https://files.pythonhosted.org/packages/c5/83/61fadfa8d62a288d778e0a1ad2f73b01abca64574ee34c5d6d078e0821da/clang_format-21.1.2-py2.py3-none-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl" + } + ], + "format": "zip", + "path": "clang_format/data/bin/clang-format" + }, + "linux-x86_64": { + "size": 1805060, + "hash": "sha256", + "digest": "6d7caf74fe89154258ddfd63984c98ffe902ef98f013ac517178fc44d72861ff", + "providers": [ + { + "type": "http", + "url": "https://files.pythonhosted.org/packages/fb/ac/3c04772acc0257f5730e83adb542b2603c1a62d1315010ab593a980af404/clang_format-21.1.2-py2.py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl" + } + ], + "format": "zip", + "path": "clang_format/data/bin/clang-format" + }, + "macos-aarch64": { + "size": 1458874, + "hash": "sha256", + "digest": "fc034652dee24583633177d800bc9deebcc9c65eb7ab53b25bbd0fbd443392a9", + "providers": [ + { + "type": "http", + "url": "https://files.pythonhosted.org/packages/ba/90/b8230efcff90a8543da3fb7fc09d7077afebaba019eceb1686d4db94cac3/clang_format-21.1.2-py2.py3-none-macosx_11_0_arm64.whl" + } + ], + "format": "zip", + "path": "clang_format/data/bin/clang-format" + }, + "macos-x86_64": { + "size": 1440163, + "hash": "sha256", + "digest": "00498efb43d60d7ac4195362009a79936d26145a9a90cdfa7a6013a62ab3c40c", + "providers": [ + { + "type": "http", + "url": "https://files.pythonhosted.org/packages/7d/97/0bb5a6866dfb5f55f7e6ca79466cb0b0081fccbc9f57887949ff23b5c38a/clang_format-21.1.2-py2.py3-none-macosx_10_9_x86_64.whl" + } + ], + "format": "zip", + "path": "clang_format/data/bin/clang-format" + }, + "windows-x86_64": { + "size": 1426244, + "hash": "sha256", + "digest": "c98e195a50c0fa40bb058449511b1b681ca7ad553579aa32425f0cfeca8d81ce", + "providers": [ + { + "type": "http", + "url": "https://files.pythonhosted.org/packages/fe/0d/3b9c6a41a9eed2d45431d91c0e8608da315cd44d0c24c517bfb686db4b6b/clang_format-21.1.2-py2.py3-none-win_amd64.whl" + } + ], + "format": "zip", + "path": "clang_format/data/bin/clang-format.exe" + } + } +} diff --git a/scripts/clang-format.js b/scripts/clang-format.js new file mode 100644 index 00000000000..abdf8c81df4 --- /dev/null +++ b/scripts/clang-format.js @@ -0,0 +1,73 @@ +/** + * 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. + * + * @noflow + * @format + */ + +'use strict'; + +const dotslash = require('fb-dotslash'); +const {spawnSync} = require('node:child_process'); +const fs = require('node:fs'); +const path = require('node:path'); +const {globSync} = require('tinyglobby'); + +const REPO_ROOT = path.resolve(__dirname, '..'); +const CLANG_FORMAT = path.join(__dirname, 'clang-format'); +const GENERATED_MARKER = Buffer.from('@' + 'generated'); +const MAX_HEADER_BYTES = 4096; +const MAX_FILES_PER_PROCESS = 30; + +/** @param {string} file */ +function isGenerated(file) { + let fd; + try { + fd = fs.openSync(path.resolve(REPO_ROOT, file), 'r'); + const header = Buffer.alloc(MAX_HEADER_BYTES); + const bytesRead = fs.readSync(fd, header, 0, header.length, 0); + return header.subarray(0, bytesRead).includes(GENERATED_MARKER); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Unable to inspect ${file}: ${message}`, {cause: error}); + } finally { + if (fd != null) { + fs.closeSync(fd); + } + } +} + +function main() { + const files = + process.argv.length > 2 + ? process.argv.slice(2) + : globSync('*/**/*.{h,cpp,m,mm}', {cwd: REPO_ROOT}); + const sourceFiles = files.filter(file => !isGenerated(file)); + + for (let i = 0; i < sourceFiles.length; i += MAX_FILES_PER_PROCESS) { + const result = spawnSync( + dotslash, + [CLANG_FORMAT, '-i', ...sourceFiles.slice(i, i + MAX_FILES_PER_PROCESS)], + { + cwd: REPO_ROOT, + stdio: 'inherit', + }, + ); + + if (result.error != null) { + throw result.error; + } + if (result.signal != null) { + process.kill(process.pid, result.signal); + return; + } + if (result.status !== 0) { + process.exit(result.status ?? 1); + } + } +} + +main(); diff --git a/yarn.lock b/yarn.lock index bb5f5e4f93a..fdc76eff84a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2912,11 +2912,6 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== -async@^3.2.3: - version "3.2.6" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" - integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== - author-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/author-regex/-/author-regex-1.0.0.tgz#d08885be6b9bbf9439fe087c76287245f0a81450" @@ -3322,15 +3317,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.0.tgz#677de7ed7efff67cc40c9bf1897fea79d41b5215" integrity sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g== -clang-format@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.8.0.tgz#7779df1c5ce1bc8aac1b0b02b4e479191ef21d46" - integrity sha512-pK8gzfu55/lHzIpQ1givIbWfn3eXnU7SfxqIwVgnn5jEM6j4ZJYjpFqFs4iSBPNedzRMmfjYjuQhu657WAXHXw== - dependencies: - async "^3.2.3" - glob "^7.0.0" - resolve "^1.1.6" - cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"