Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prefer using a local version of Prettier when writing typegen files #328

Merged
merged 1 commit into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/smooth-ducks-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@xstate/cli': minor
---

A local version of Prettier (if available) should now be used when writing typegen files.
5 changes: 5 additions & 0 deletions .changeset/tough-foxes-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@xstate/tools-shared': major
---

Removed some FS-related utils from the package.
1 change: 1 addition & 0 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@xstate/tools-shared": "^2.0.2",
"chokidar": "^3.5.3",
"commander": "^8.0.0",
"prettier": "^2.8.7",
"xstate": "^4.33.4"
},
"author": "Stately Team",
Expand Down
59 changes: 54 additions & 5 deletions apps/cli/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,62 @@

import { extractMachinesFromFile } from '@xstate/machine-extractor';
import {
TypegenData,
getTsTypesEdits,
getTypegenData,
getTypegenOutput,
processFileEdits,
writeToTypegenFile,
} from '@xstate/tools-shared';
import { watch } from 'chokidar';
import { Command } from 'commander';
import * as fs from 'fs/promises';
import * as path from 'path';
import { version } from '../package.json';

async function removeFile(filePath: string) {
try {
await fs.unlink(filePath);
} catch (e: any) {
if (e?.code === 'ENOENT') {
return;
}
throw e;
}
}

let prettier: typeof import('prettier') | undefined;

function getPrettierInstance(cwd: string): typeof import('prettier') {
if (prettier) {
return prettier;
}
try {
return require(require.resolve('prettier', { paths: [cwd] }));
} catch (err) {
if (!err || (err as any).code !== 'MODULE_NOT_FOUND') {
throw err;
}
// we load our own prettier instance lazily on purpose to speed up the init time
return (prettier = require('prettier'));
}
}

const writeToTypegenFile = async (
typegenUri: string,
types: TypegenData[],
{ cwd }: { cwd: string },
) => {
const prettierInstance = getPrettierInstance(cwd);
await fs.writeFile(
typegenUri,
// // Prettier v3 returns a promise
await prettierInstance.format(getTypegenOutput(types), {
...(await prettierInstance.resolveConfig(typegenUri)),
parser: 'typescript',
}),
);
};

// TODO: just use the native one when support for node 12 gets dropped
const allSettled: typeof Promise.allSettled = (promises: Promise<any>[]) =>
Promise.all(
Expand All @@ -28,7 +73,7 @@ const program = new Command();

program.version(version);

const writeToFiles = async (uriArray: string[]) => {
const writeToFiles = async (uriArray: string[], { cwd }: { cwd: string }) => {
/**
* TODO - implement pretty readout
*/
Expand All @@ -43,6 +88,9 @@ const writeToFiles = async (uriArray: string[]) => {
return;
}

const typegenUri =
uri.slice(0, -path.extname(uri).length) + '.typegen.ts';

const types = extracted.machines
.filter(
(
Expand All @@ -54,7 +102,7 @@ const writeToFiles = async (uriArray: string[]) => {
getTypegenData(path.basename(uri), index, machineResult),
);

await writeToTypegenFile(uri, types);
await writeToTypegenFile(typegenUri, types, { cwd });

const edits = getTsTypesEdits(types);
if (edits.length > 0) {
Expand All @@ -80,13 +128,14 @@ program
.argument('<files>', 'The files to target, expressed as a glob pattern')
.option('-w, --watch', 'Run the typegen in watch mode')
.action(async (filesPattern: string, opts: { watch?: boolean }) => {
const cwd = process.cwd();
if (opts.watch) {
// TODO: implement per path queuing to avoid tasks related to the same file from overlapping their execution
const processFile = (path: string) => {
if (path.endsWith('.typegen.ts')) {
return;
}
writeToFiles([path]).catch(() => {});
writeToFiles([path], { cwd }).catch(() => {});
};
// TODO: handle removals
watch(filesPattern, { awaitWriteFinish: true })
Expand All @@ -100,7 +149,7 @@ program
if (path.endsWith('.typegen.ts')) {
return;
}
tasks.push(writeToFiles([path]));
tasks.push(writeToFiles([path], { cwd }));
})
.on('ready', async () => {
const settled = await allSettled(tasks);
Expand Down
1 change: 0 additions & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"test": "jest"
},
"peerDependencies": {
"prettier": "^2.3.1",
"xstate": "^4"
},
"devDependencies": {
Expand Down
2 changes: 0 additions & 2 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,5 @@ export * from './getTypegenOutput';
export * from './introspectMachine';
export * from './isCursorInPosition';
export * from './processFileEdits';
export * from './removeFile';
export * from './resolveUriToFilePrefix';
export * from './types';
export * from './writeToTypegenFile';
12 changes: 0 additions & 12 deletions packages/shared/src/removeFile.ts

This file was deleted.

27 changes: 0 additions & 27 deletions packages/shared/src/writeToTypegenFile.ts

This file was deleted.