Skip to content

Commit 3a9b624

Browse files
committed
fixup! feat(@schematics/angular): use Oxfmt in generated workspaces
1 parent 5faafa7 commit 3a9b624

5 files changed

Lines changed: 55 additions & 23 deletions

File tree

‎packages/angular/cli/src/command-builder/schematics-command-module.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import { isPackageNameSafeForAnalytics } from '../analytics/analytics';
1919
import { EventCustomDimension } from '../analytics/analytics-parameters';
2020
import { getProjectByCwd, getSchematicDefaults } from '../utilities/config';
2121
import { assertIsError } from '../utilities/error';
22+
import { formatFiles } from '../utilities/formatting';
2223
import { memoize } from '../utilities/memoize';
23-
import { formatFiles } from '../utilities/prettier';
2424
import { isTTY } from '../utilities/tty';
2525
import {
2626
CommandModule,

‎packages/angular/cli/src/commands/update/utilities/migration.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import * as semver from 'semver';
1919
import { subscribeToWorkflow } from '../../../command-builder/utilities/schematic-workflow';
2020
import { colors } from '../../../utilities/color';
2121
import { assertIsError } from '../../../utilities/error';
22+
import { formatFiles } from '../../../utilities/formatting';
2223
import { writeErrorToLogFile } from '../../../utilities/log-file';
23-
import { formatFiles } from '../../../utilities/prettier';
2424
import { askChoices } from '../../../utilities/prompt';
2525
import { isTTY } from '../../../utilities/tty';
2626
import { coerceVersionNumber } from './cli-version';

packages/angular/cli/src/utilities/prettier.ts renamed to packages/angular/cli/src/utilities/formatting.ts

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { dirname, join } from 'node:path';
1313
import { promisify } from 'node:util';
1414

1515
const execFileAsync = promisify(execFile);
16-
let prettierCliPath: string | null | undefined;
1716

1817
/**
1918
* Conservative upper bound for the length of a single spawned command line.
@@ -60,7 +59,7 @@ export function batchFilesByArgumentLength(
6059
}
6160

6261
/**
63-
* Formats files using Prettier.
62+
* Formats files using the workspace's Oxfmt or Prettier installation.
6463
* @param cwd The current working directory.
6564
* @param files The files to format.
6665
*/
@@ -69,40 +68,44 @@ export async function formatFiles(cwd: string, files: Set<string>): Promise<void
6968
return;
7069
}
7170

72-
if (prettierCliPath === undefined) {
71+
const workspaceRequire = createRequire(cwd + '/');
72+
let formatterCliPath: string | undefined;
73+
let formatter: string | undefined;
74+
for (const name of ['oxfmt', 'prettier']) {
75+
let packageJsonPath: string;
7376
try {
74-
const prettierPath = createRequire(cwd + '/').resolve('prettier/package.json');
75-
const prettierPackageJson = JSON.parse(await readFile(prettierPath, 'utf-8')) as {
76-
bin: string;
77-
};
78-
prettierCliPath = join(dirname(prettierPath), prettierPackageJson.bin);
77+
packageJsonPath = workspaceRequire.resolve(`${name}/package.json`);
7978
} catch {
80-
// Prettier is not installed.
81-
prettierCliPath = null;
79+
continue;
8280
}
81+
82+
const { bin } = JSON.parse(await readFile(packageJsonPath, 'utf-8')) as {
83+
bin: string | Record<string, string>;
84+
};
85+
formatterCliPath = join(dirname(packageJsonPath), typeof bin === 'string' ? bin : bin[name]);
86+
formatter = name;
87+
break;
8388
}
8489

85-
if (!prettierCliPath) {
90+
if (!formatterCliPath) {
8691
return;
8792
}
8893

89-
const baseArgs = [
90-
prettierCliPath,
91-
'--write',
92-
'--no-error-on-unmatched-pattern',
93-
'--ignore-unknown',
94-
];
94+
const baseArgs = [formatterCliPath, '--write', '--no-error-on-unmatched-pattern'];
95+
if (formatter === 'prettier') {
96+
baseArgs.push('--ignore-unknown');
97+
}
9598
// `process.execPath` is spawned as the first argument and also counts toward the
96-
// command-line limit; it and `prettierCliPath` are absolute paths that may contain
99+
// command-line limit; it and `formatterCliPath` are absolute paths that may contain
97100
// spaces and therefore be quoted.
98101
const baseLength = [process.execPath, ...baseArgs].reduce(
99102
(total, arg) => total + arg.length + (arg.includes(' ') ? 3 : 1),
100103
0,
101104
);
102105

103-
// Spawn Prettier once per batch so repositories with many changed files do not
106+
// Spawn the formatter once per batch so repositories with many changed files do not
104107
// overflow the OS command-line length limit. A failure in one batch (e.g. a file
105-
// Prettier cannot parse) must not stop the remaining batches, matching the previous
108+
// the formatter cannot parse) must not stop the remaining batches, matching the previous
106109
// single-invocation behavior, so errors are collected and reported together.
107110
const errors: string[] = [];
108111
for (const batch of batchFilesByArgumentLength(files, baseLength, MAX_COMMAND_LINE_LENGTH)) {

packages/angular/cli/src/utilities/prettier_spec.ts renamed to packages/angular/cli/src/utilities/formatting_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import { batchFilesByArgumentLength } from './prettier';
9+
import { batchFilesByArgumentLength } from './formatting';
1010

1111
describe('batchFilesByArgumentLength', () => {
1212
it('returns no batches when there are no files', () => {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import assert from 'node:assert/strict';
2+
import { expectFileToMatch, readFile, writeFile } from '../../utils/fs';
3+
import { installPackage, uninstallPackage } from '../../utils/packages';
4+
import { ng } from '../../utils/process';
5+
6+
export default async function () {
7+
const untouched = 'export const untouched={value:"unchanged"};';
8+
await writeFile('src/untouched.ts', untouched);
9+
await writeFile('.oxfmtrc.json', JSON.stringify({ singleQuote: false, semi: false }));
10+
11+
await ng('generate', 'service', 'oxfmt-only', '--skip-tests');
12+
await expectFileToMatch('src/app/oxfmt-only.ts', 'from "@angular/core"\n');
13+
14+
// Distinct configurations make the selected formatter observable when both are installed.
15+
await installPackage('prettier@3.9.10');
16+
await writeFile('.prettierrc', JSON.stringify({ singleQuote: true, semi: false }));
17+
await ng('generate', 'service', 'both-formatters', '--skip-tests');
18+
await expectFileToMatch('src/app/both-formatters.ts', 'from "@angular/core"\n');
19+
20+
await uninstallPackage('oxfmt');
21+
await ng('generate', 'service', 'prettier-only', '--skip-tests');
22+
await expectFileToMatch('src/app/prettier-only.ts', "from '@angular/core'\n");
23+
24+
await uninstallPackage('prettier');
25+
await ng('generate', 'service', 'no-formatter', '--skip-tests');
26+
await expectFileToMatch('src/app/no-formatter.ts', "from '@angular/core';\n");
27+
28+
assert.equal(await readFile('src/untouched.ts'), untouched);
29+
}

0 commit comments

Comments
 (0)