Skip to content

Commit 07e4bf3

Browse files
cortinicometa-codesync[bot]
authored andcommitted
Add Kotlin to yarn format (#58462)
Summary: Pull Request resolved: #58462 Add `yarn format-kotlin` and `yarn format-check-kotlin` using the npm `ktfmt` package and its bundled formatter jar. This adds the offline package mirror and workspace lock entry without changing existing Kotlin source formatting or Gradle configuration. The wrapper discovers a suitable JDK when available and otherwise prints environment-specific Java 17 setup guidance before skipping Kotlin. allow-large-files: The npm package intentionally contains the upstream ktfmt executable jar so offline and public installs use the same formatter. Changelog: [Internal] Reviewed By: javache Differential Revision: D119487612 fbshipit-source-id: cb699a1286cffbf461ef69ed66f694e3f69415d0
1 parent ec9952a commit 07e4bf3

4 files changed

Lines changed: 179 additions & 4 deletions

File tree

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414
"cxx-api-validate": "python -m scripts.cxx-api.parser --validate",
1515
"flow-check": "flow full-check",
1616
"flow": "flow",
17-
"format-check": "yarn format-check-javascript && yarn format-check-cpp",
17+
"format-check": "yarn format-check-javascript && yarn format-check-cpp && yarn format-check-kotlin",
1818
"format-check-cpp": "node ./scripts/clang-format.js --check",
1919
"format-check-javascript": "prettier --check \"./**/*.{cjs,cts,flow,js,jsx,md,mjs,mts,ts,tsx,yaml,yml}\"",
20-
"format": "yarn format-javascript && yarn format-cpp",
20+
"format-check-kotlin": "node ./scripts/format-kotlin.js --check",
21+
"format": "yarn format-javascript && yarn format-cpp && yarn format-kotlin",
2122
"format-cpp": "node ./scripts/clang-format.js",
2223
"format-javascript": "prettier --write \"./**/*.{cjs,cts,flow,js,jsx,md,mjs,mts,ts,tsx,yaml,yml}\"",
24+
"format-kotlin": "node ./scripts/format-kotlin.js",
2325
"featureflags": "yarn --cwd packages/react-native featureflags",
2426
"js-api-diff": "node ./scripts/js-api/diff-api-snapshot",
25-
"lint-kotlin-check": "./gradlew ktfmtCheck",
26-
"lint-kotlin": "./gradlew ktfmtFormat",
2727
"lint-markdown": "markdownlint-cli2 2>&1",
2828
"lint": "eslint --max-warnings 0 .",
2929
"preinstall": "node ./scripts/try-set-hermes-compiler-prebuilt.js",
@@ -101,6 +101,7 @@
101101
"jest-junit": "^16.0.0",
102102
"jest-snapshot": "^29.7.0",
103103
"jsonc-parser": "2.2.1",
104+
"ktfmt": "0.59.0",
104105
"markdownlint-cli2": "^0.17.2",
105106
"markdownlint-rule-relative-links": "^3.0.0",
106107
"memfs": "^4.38.2",

scripts/format-kotlin.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @noflow
8+
* @format
9+
*/
10+
11+
'use strict';
12+
13+
const {findJava, warnMissingJava} = require('./format-utils');
14+
const {spawnSync} = require('node:child_process');
15+
const fs = require('node:fs');
16+
const path = require('node:path');
17+
const {globSync} = require('tinyglobby');
18+
19+
const REPO_ROOT = path.resolve(__dirname, '..');
20+
const KTFMT_JAR = require.resolve('ktfmt/lib/ktfmt.jar');
21+
const GENERATED_MARKER = Buffer.from('@' + 'generated');
22+
const MINIMUM_JAVA_VERSION = 17;
23+
const MAX_FILES_PER_PROCESS = 100;
24+
const MAX_HEADER_BYTES = 4096;
25+
const IGNORE = [
26+
'**/build/**',
27+
'**/com/facebook/yoga/**',
28+
'**/hermes-engine/**',
29+
'**/internal/featureflags/**',
30+
'**/node_modules/**',
31+
'**/systeminfo/ReactNativeVersion.kt',
32+
];
33+
34+
function isGenerated(file) {
35+
const fd = fs.openSync(path.resolve(REPO_ROOT, file), 'r');
36+
try {
37+
const header = Buffer.alloc(MAX_HEADER_BYTES);
38+
const bytesRead = fs.readSync(fd, header, 0, header.length, 0);
39+
return header.subarray(0, bytesRead).includes(GENERATED_MARKER);
40+
} finally {
41+
fs.closeSync(fd);
42+
}
43+
}
44+
45+
function main() {
46+
const check = process.argv[2] === '--check';
47+
const java = findJava(MINIMUM_JAVA_VERSION);
48+
if (java == null) {
49+
warnMissingJava('Kotlin');
50+
return;
51+
}
52+
const files = globSync('**/*.{kt,kts}', {
53+
cwd: REPO_ROOT,
54+
ignore: IGNORE,
55+
}).filter(file => !isGenerated(file));
56+
for (let i = 0; i < files.length; i += MAX_FILES_PER_PROCESS) {
57+
const result = spawnSync(
58+
java,
59+
[
60+
'-jar',
61+
KTFMT_JAR,
62+
'--do-not-remove-unused-imports',
63+
...(check ? ['--dry-run', '--set-exit-if-changed'] : []),
64+
...files.slice(i, i + MAX_FILES_PER_PROCESS),
65+
],
66+
{cwd: REPO_ROOT, stdio: 'inherit'},
67+
);
68+
if (result.error != null) {
69+
throw result.error;
70+
}
71+
if (result.signal != null) {
72+
process.kill(process.pid, result.signal);
73+
return;
74+
}
75+
if (result.status !== 0) {
76+
process.exit(result.status ?? 1);
77+
}
78+
}
79+
}
80+
81+
main();

scripts/format-utils.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @noflow
8+
* @format
9+
*/
10+
11+
'use strict';
12+
13+
const {spawnSync} = require('node:child_process');
14+
const path = require('node:path');
15+
16+
const REPO_ROOT = path.resolve(__dirname, '..');
17+
18+
let metaUtils = null;
19+
try {
20+
metaUtils = require('./format-utils.fb');
21+
} catch (error) {
22+
if (
23+
error == null ||
24+
typeof error !== 'object' ||
25+
error.code !== 'MODULE_NOT_FOUND' ||
26+
!String(error.message).includes("'./format-utils.fb'")
27+
) {
28+
throw error;
29+
}
30+
}
31+
32+
const IS_META_CHECKOUT = metaUtils != null;
33+
34+
function commandVersion(command, prefixArguments = []) {
35+
const result = spawnSync(command, [...prefixArguments, '--version'], {
36+
encoding: 'utf8',
37+
env: {...process.env, PWD: REPO_ROOT},
38+
});
39+
return {
40+
output: `${result.stdout ?? ''}\n${result.stderr ?? ''}`,
41+
status: result.status,
42+
};
43+
}
44+
45+
function findMetaTool(...relativePath) {
46+
return metaUtils?.findMetaTool(...relativePath) ?? null;
47+
}
48+
49+
function javaMajorVersion(command) {
50+
const result = spawnSync(command, ['-version'], {encoding: 'utf8'});
51+
const output = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
52+
const version = /version "(?:1\.)?(\d+)/.exec(output);
53+
return result.status === 0 && version != null ? Number(version[1]) : null;
54+
}
55+
56+
function findJava(minimumVersion) {
57+
if (process.env.JAVA != null && process.env.JAVA !== '') {
58+
return javaMajorVersion(process.env.JAVA) >= minimumVersion
59+
? process.env.JAVA
60+
: null;
61+
}
62+
63+
const candidates = [];
64+
candidates.push(...(metaUtils?.findJavaCandidates() ?? []));
65+
candidates.push('java');
66+
67+
return (
68+
candidates.find(command => javaMajorVersion(command) >= minimumVersion) ??
69+
null
70+
);
71+
}
72+
73+
function warnMissingJava(language) {
74+
const instructions =
75+
metaUtils?.missingJavaInstructions() ??
76+
'Please install a JDK of your choice with Java 17 or newer and make sure the `java` command is in your PATH, or set JAVA=/path/to/java.';
77+
console.warn(
78+
`warning: Skipping ${language} formatting because Java 17 or newer was not found.\n${instructions}`,
79+
);
80+
}
81+
82+
module.exports = {
83+
commandVersion,
84+
findJava,
85+
findMetaTool,
86+
IS_META_CHECKOUT,
87+
warnMissingJava,
88+
};

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6373,6 +6373,11 @@ kleur@^3.0.3:
63736373
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
63746374
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
63756375

6376+
ktfmt@0.59.0:
6377+
version "0.59.0"
6378+
resolved "https://registry.yarnpkg.com/ktfmt/-/ktfmt-0.59.0.tgz#99f98b81dbdc7f1487dfbc9850eb17b3780cf6d5"
6379+
integrity sha512-lOEn/7y2Ez2/nxDTn5EwJv6BSugB8BtzY2Gn6GvyLIAjdUf3xgKzirIxD57t/vu5I6eybivmVtONI3WGXyZ3lw==
6380+
63766381
language-subtag-registry@^0.3.20:
63776382
version "0.3.23"
63786383
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7"

0 commit comments

Comments
 (0)