mirror of
https://github.com/electron/electron.git
synced 2026-05-02 03:00:22 -04:00
* build: add oxfmt for code formatting and import sorting
Adds oxfmt as a devDependency alongside oxlint and wires it into the
lint pipeline. The .oxfmtrc.json config matches Electron's current JS
style (single quotes, semicolons, 2-space indent, trailing commas off,
printWidth 100) and configures sortImports with custom groups that
mirror the import/order pathGroups previously enforced by ESLint:
@electron/internal, @electron/*, and {electron,electron/**} each get
their own ordered group ahead of external modules.
- `yarn lint:fmt` runs `oxfmt --check` over JS/TS sources and is
chained into `yarn lint` so CI enforces it automatically.
- `yarn format` runs `oxfmt --write` for local fix-up.
- lint-staged invokes `oxfmt --write` on staged .js/.ts/.mjs/.cjs
files before oxlint, so formatting is applied at commit time.
The next commit applies the formatter to the existing codebase so the
check actually passes.
* chore: apply oxfmt formatting to JS and TS sources
Runs `yarn format` across lib/, spec/, script/, build/, default_app/,
and npm/ to bring the codebase in line with the .oxfmtrc.json settings
added in the previous commit. This is a pure formatting pass: import
statements are sorted into the groups defined by the config, method
chains longer than printWidth are broken, single-quoted strings
containing apostrophes are switched to double quotes, and a handful of
single-statement `if` bodies are re-wrapped and get braces added by
`oxlint --fix` to satisfy the `curly: multi-line` rule.
No behavior changes.
218 lines
6.6 KiB
JavaScript
218 lines
6.6 KiB
JavaScript
const chalk = require('chalk');
|
|
|
|
const childProcess = require('node:child_process');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
|
|
const ELECTRON_DIR = path.resolve(__dirname, '..', '..');
|
|
const SRC_DIR = path.resolve(ELECTRON_DIR, '..');
|
|
|
|
const CHROMIUM_VERSION_DEPS_REGEX = /chromium_version':\n +'(.+?)',/m;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
const pass = chalk.green('✓');
|
|
const fail = chalk.red('✗');
|
|
|
|
function getElectronExec() {
|
|
const OUT_DIR = getOutDir();
|
|
switch (process.platform) {
|
|
case 'darwin':
|
|
return `out/${OUT_DIR}/Electron.app/Contents/MacOS/Electron`;
|
|
case 'win32':
|
|
return `out/${OUT_DIR}/electron.exe`;
|
|
case 'linux':
|
|
return `out/${OUT_DIR}/electron`;
|
|
default:
|
|
throw new Error('Unknown platform');
|
|
}
|
|
}
|
|
|
|
function getOutDir(options = {}) {
|
|
const shouldLog = options.shouldLog || false;
|
|
const presetDirs = ['Testing', 'Release', 'Default', 'Debug'];
|
|
|
|
if (options.outDir || process.env.ELECTRON_OUT_DIR) {
|
|
const outDir = options.outDir || process.env.ELECTRON_OUT_DIR;
|
|
const outPath = path.resolve(SRC_DIR, 'out', outDir);
|
|
|
|
// Check that user-set variable is a valid/existing directory
|
|
if (fs.existsSync(outPath)) {
|
|
if (shouldLog) console.log(`OUT_DIR is: ${outDir}`);
|
|
return outDir;
|
|
}
|
|
|
|
// Throw error if user passed/set nonexistent directory.
|
|
throw new Error(`${outDir} directory not configured on your machine.`);
|
|
} else {
|
|
for (const buildType of presetDirs) {
|
|
const outPath = path.resolve(SRC_DIR, 'out', buildType);
|
|
if (fs.existsSync(outPath)) {
|
|
if (shouldLog) console.log(`OUT_DIR is: ${buildType}`);
|
|
return buildType;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we got here, it means process.env.ELECTRON_OUT_DIR was not
|
|
// set and none of the preset options could be found in /out, so throw
|
|
throw new Error(
|
|
`No valid out directory found; use one of ${presetDirs.join(',')} or set process.env.ELECTRON_OUT_DIR`
|
|
);
|
|
}
|
|
|
|
function getAbsoluteElectronExec() {
|
|
return path.resolve(SRC_DIR, getElectronExec());
|
|
}
|
|
|
|
function handleGitCall(args, gitDir) {
|
|
const result = childProcess.spawnSync('git', args, {
|
|
cwd: gitDir,
|
|
encoding: 'utf8',
|
|
stdio: ['inherit', 'pipe', 'pipe']
|
|
});
|
|
if (result.status === 0) {
|
|
return result.stdout.replace(/^\*|\s+|\s+$/, '');
|
|
} else {
|
|
console.log(`${fail} couldn't parse git process call: `, result.stderr);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
async function getCurrentBranch(gitDir) {
|
|
const RELEASE_BRANCH_PATTERN = /^\d+-x-y$/;
|
|
const MAIN_BRANCH_PATTERN = /^main$/;
|
|
const ORIGIN_MAIN_BRANCH_PATTERN = /^origin\/main$/;
|
|
|
|
let branch = await handleGitCall(['rev-parse', '--abbrev-ref', 'HEAD'], gitDir);
|
|
if (!MAIN_BRANCH_PATTERN.test(branch) && !RELEASE_BRANCH_PATTERN.test(branch)) {
|
|
const lastCommit = await handleGitCall(['rev-parse', 'HEAD'], gitDir);
|
|
const branches = (await handleGitCall(['branch', '--contains', lastCommit, '--remote'], gitDir)).split('\n');
|
|
|
|
branch = branches.find(
|
|
(b) =>
|
|
MAIN_BRANCH_PATTERN.test(b.trim()) ||
|
|
ORIGIN_MAIN_BRANCH_PATTERN.test(b.trim()) ||
|
|
RELEASE_BRANCH_PATTERN.test(b.trim())
|
|
);
|
|
if (!branch) {
|
|
console.log(`${fail} no release branch exists for this ref`);
|
|
process.exit(1);
|
|
}
|
|
if (branch.startsWith('origin/')) branch = branch.substr('origin/'.length);
|
|
}
|
|
return branch.trim();
|
|
}
|
|
|
|
function chunkFilenames(filenames, offset = 0) {
|
|
// Windows has a max command line length of 2047 characters, so we can't
|
|
// provide too many filenames without going over that. To work around that,
|
|
// chunk up a list of filenames such that it won't go over that limit when
|
|
// used as args. Other platforms may have higher limits, but 4095 might be
|
|
// the limit on Linux systems according to `termios(3)`, so cap it there.
|
|
const MAX_FILENAME_ARGS_LENGTH = (os.platform() === 'win32' ? 2047 : 4095) - offset;
|
|
|
|
return filenames.reduce(
|
|
(chunkedFilenames, filename) => {
|
|
const currChunk = chunkedFilenames[chunkedFilenames.length - 1];
|
|
const currChunkLength = currChunk.reduce((totalLength, _filename) => totalLength + _filename.length + 1, 0);
|
|
if (currChunkLength + filename.length + 1 > MAX_FILENAME_ARGS_LENGTH) {
|
|
chunkedFilenames.push([filename]);
|
|
} else {
|
|
currChunk.push(filename);
|
|
}
|
|
return chunkedFilenames;
|
|
},
|
|
[[]]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param {string} top
|
|
* @param {(filename: string) => boolean} test
|
|
* @returns {Promise<string[]>}
|
|
*/
|
|
async function findMatchingFiles(top, test) {
|
|
return fs.promises.readdir(top, { encoding: 'utf8', recursive: true }).then((files) => {
|
|
return files
|
|
.filter((name) => path.basename(name) !== '.bin')
|
|
.filter((name) => test(name))
|
|
.map((name) => path.join(top, name));
|
|
});
|
|
}
|
|
|
|
function compareVersions(v1, v2) {
|
|
const [split1, split2] = [v1.split('.'), v2.split('.')];
|
|
|
|
if (split1.length !== split2.length) {
|
|
throw new Error(`Expected version strings to have same number of sections: ${split1} and ${split2}`);
|
|
}
|
|
for (let i = 0; i < split1.length; i++) {
|
|
const p1 = parseInt(split1[i], 10);
|
|
const p2 = parseInt(split2[i], 10);
|
|
|
|
if (p1 > p2) return 1;
|
|
else if (p1 < p2) return -1;
|
|
// Continue checking the value if this portion is equal
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function getChromiumVersionFromDEPS(depsContent) {
|
|
return CHROMIUM_VERSION_DEPS_REGEX.exec(depsContent)?.[1] ?? null;
|
|
}
|
|
|
|
function getDepotToolsEnv() {
|
|
let depotToolsEnv;
|
|
|
|
const findDepotToolsOnPath = () => {
|
|
const result = childProcess.spawnSync(os.platform() === 'win32' ? 'where' : 'which', ['gclient']);
|
|
|
|
if (result.status === 0) {
|
|
return process.env;
|
|
}
|
|
};
|
|
|
|
const checkForBuildTools = () => {
|
|
const result = childProcess.spawnSync('electron-build-tools', ['show', 'env', '--json'], { shell: true });
|
|
|
|
if (result.status === 0) {
|
|
return {
|
|
...process.env,
|
|
...JSON.parse(result.stdout.toString().trim())
|
|
};
|
|
}
|
|
};
|
|
|
|
try {
|
|
depotToolsEnv = checkForBuildTools();
|
|
if (!depotToolsEnv) depotToolsEnv = findDepotToolsOnPath();
|
|
} catch {}
|
|
|
|
if (!depotToolsEnv) {
|
|
throw new Error("Couldn't find depot_tools, ensure it's on your PATH");
|
|
}
|
|
|
|
if (!('CHROMIUM_BUILDTOOLS_PATH' in depotToolsEnv)) {
|
|
throw new Error('CHROMIUM_BUILDTOOLS_PATH environment variable must be set');
|
|
}
|
|
|
|
return depotToolsEnv;
|
|
}
|
|
|
|
module.exports = {
|
|
chunkFilenames,
|
|
compareVersions,
|
|
findMatchingFiles,
|
|
getChromiumVersionFromDEPS,
|
|
getCurrentBranch,
|
|
getDepotToolsEnv,
|
|
getElectronExec,
|
|
getOutDir,
|
|
getAbsoluteElectronExec,
|
|
handleGitCall,
|
|
ELECTRON_DIR,
|
|
SRC_DIR
|
|
};
|