Skip to content

Commit

Permalink
Fix problem with Prettier version conflicts for Sky configs (#391)
Browse files Browse the repository at this point in the history
* Fix problem with Prettier version conflicts for Sky configs

* Don't bundle the CLI bin

* Bundle again

* Mini refactor

* Address PR feedback

* Update prettier code
  • Loading branch information
mellson authored Oct 16, 2023
1 parent 2c8387f commit cf8c2b7
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 64 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-boats-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@xstate/cli': patch
---

Fix problem with Prettier version conflicts for Sky configs.
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"commander": "^8.0.0",
"dotenv": "^16.0.3",
"isomorphic-fetch": "^3.0.0",
"prettier": "^2.8.7",
"prettier": "^2.8.8",
"xstate": "^4.33.4",
"xstate-beta": "npm:xstate@beta"
},
Expand Down
28 changes: 24 additions & 4 deletions apps/cli/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,33 @@ program
)
.argument('<files>', 'The files to target, expressed as a glob pattern')
.option('-w, --watch', 'Run sky in watch mode')
.option('-r, --refetch', 'Always refetch and overwrite existing sky configs')
.option(
'-k, --api-key <key>',
'API key to use for interacting with the Stately Studio',
)
.action(
async (
filesPattern: string,
opts: { watch?: boolean; apiKey?: string; host?: string },
opts: {
refetch?: boolean;
watch?: boolean;
apiKey?: string;
host?: string;
},
) => {
const cwd = process.cwd();
const envApiKey = process.env.SKY_API_KEY;
const apiKey = opts.apiKey ?? envApiKey;

if (opts.watch) {
const processFile = (uri: string) => {
writeConfigToFiles({ uri, apiKey, writeToFiles }).catch((e) => {
writeConfigToFiles({
uri,
apiKey,
forceFetch: opts.refetch === true,
writeToFiles,
cwd,
}).catch((e) => {
console.error(e);
});
};
Expand All @@ -82,7 +94,15 @@ program
const tasks: Array<Promise<void>> = [];
watch(filesPattern, { persistent: false })
.on('add', (uri) => {
tasks.push(writeConfigToFiles({ uri, apiKey, writeToFiles }));
tasks.push(
writeConfigToFiles({
uri,
apiKey,
forceFetch: opts.refetch === true,
writeToFiles,
cwd,
}),
);
})
.on('ready', async () => {
const settled = await allSettled(tasks);
Expand Down
21 changes: 18 additions & 3 deletions apps/cli/src/sky/writeConfigToFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import 'dotenv/config';
import * as fs from 'fs/promises';
import fetch from 'isomorphic-fetch';
import { writeToFiles } from '../typegen/writeToFiles';
import { getPrettierInstance } from '../utils';
import { fetchSkyConfig } from './urlUtils';

export const writeConfigToFiles = async (opts: {
uri: string;
apiKey: string | undefined;
writeToFiles: typeof writeToFiles;
forceFetch: boolean;
cwd: string;
}) => {
try {
if (doesSkyConfigExist(opts.uri)) {
if (!opts.forceFetch && doesSkyConfigExist(opts.uri)) {
console.log(`${opts.uri} - skipping, sky config already exists`);
return;
}
Expand Down Expand Up @@ -57,8 +60,20 @@ export const writeConfigToFiles = async (opts: {
createTypeGenFile: runTypeGen ? writeToFiles : undefined,
});

await modifySkyConfigSource({ filePath: opts.uri });
console.log(`${opts.uri} - updated with sky config`);
const fileContents = await fs.readFile(opts.uri, 'utf8');
const code = await modifySkyConfigSource({
fileContents,
filePath: opts.uri,
});
if (code) {
const prettierInstance = getPrettierInstance(opts.cwd);
const formattedCode = await prettierInstance.format(code, {
...(await prettierInstance.resolveConfig(opts.uri)),
parser: 'typescript',
});
await fs.writeFile(opts.uri, formattedCode);
console.log(`${opts.uri} - updated with sky config`);
}
} catch (error) {
console.error(error);
}
Expand Down
18 changes: 1 addition & 17 deletions apps/cli/src/typegen/writeToFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import 'dotenv/config';
import * as fs from 'fs/promises';
import * as path from 'path';
import { getPrettierInstance } from '../utils';

async function removeFile(filePath: string) {
try {
Expand All @@ -21,23 +22,6 @@ async function removeFile(filePath: string) {
}
}

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[],
Expand Down
16 changes: 16 additions & 0 deletions apps/cli/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,19 @@ const allSettled: typeof Promise.allSettled = (promises: Promise<any>[]) =>
),
),
);

let prettier: typeof import('prettier') | undefined;
export 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'));
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"husky": "^8.0.1",
"lint-staged": ">=10",
"patch-package": "^6.4.7",
"prettier": "^2.8.7",
"prettier": "^2.8.8",
"turbo": "^1.1.2",
"typescript": "^5.0.4"
}
Expand Down
1 change: 0 additions & 1 deletion packages/machine-extractor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"@babel/parser": "^7.21.4",
"@babel/traverse": "^7.21.4",
"@babel/types": "^7.21.4",
"prettier": "^2.8.7",
"recast": "^0.23.1"
},
"peerDependencies": {
Expand Down
57 changes: 25 additions & 32 deletions packages/machine-extractor/src/sky/skyConfigModifySource.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as fs from 'fs/promises';
import * as path from 'path';
import * as prettier from 'prettier';
import * as recast from 'recast';
import * as babelTs from 'recast/parsers/babel-ts';
import { ALLOWED_SKY_CONFIG_CALL_EXPRESSION_NAMES } from './skyConfigUtils';

export const modifySkyConfigSource = async (opts: { filePath: string }) => {
const fileContents = await fs.readFile(opts.filePath, 'utf8');
const ast = recast.parse(fileContents, {
export const modifySkyConfigSource = async (opts: {
fileContents: string;
filePath: string;
}) => {
const ast = recast.parse(opts.fileContents, {
parser: babelTs,
});
const b = recast.types.builders;
Expand Down Expand Up @@ -45,34 +45,27 @@ export const modifySkyConfigSource = async (opts: { filePath: string }) => {

// Add the import at the top of the file
ast.program.body.unshift(importDeclaration);
}

recast.visit(ast, {
visitCallExpression(path) {
const node = path.node;
if (
node.callee.type === 'Identifier' &&
ALLOWED_SKY_CONFIG_CALL_EXPRESSION_NAMES.includes(node.callee.name)
) {
const args = node.arguments;
const hasSkyConfig = args.some((arg) => {
return arg.type === 'Identifier' && arg.name === importIdentifier;
});
if (!hasSkyConfig) {
args.push(b.identifier(importIdentifier));
}
// Add the skyConfig argument to the @statelyai/sky calls if it's not already present
recast.visit(ast, {
visitCallExpression(path) {
const node = path.node;
if (
node.callee.type === 'Identifier' &&
ALLOWED_SKY_CONFIG_CALL_EXPRESSION_NAMES.includes(node.callee.name)
) {
const args = node.arguments;
const hasSkyConfig = args.some((arg) => {
return arg.type === 'Identifier' && arg.name === importIdentifier;
});
if (!hasSkyConfig) {
args.push(b.identifier(importIdentifier));
}
return false;
},
});
}
return false;
},
});

const output = recast.print(ast).code;
const prettierConfig = await prettier.resolveConfig(opts.filePath);
await fs.writeFile(
opts.filePath,
prettier.format(output, {
...prettierConfig,
parser: 'typescript',
}),
);
}
return recast.print(ast).code;
};
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"esbuild-jest": "^0.5.0",
"jest": "^27.4.7",
"jest-watch-typeahead": "^1.0.0",
"prettier": "^2.8.7",
"prettier": "^2.8.8",
"typescript": "^5.0.4",
"xstate": "^4.33.4"
},
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6125,10 +6125,10 @@ prettier@^1.19.1:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==

prettier@^2.8.7:
version "2.8.7"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450"
integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==
prettier@^2.8.8:
version "2.8.8"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==

pretty-format@^27.0.0, pretty-format@^27.4.6:
version "27.4.6"
Expand Down

0 comments on commit cf8c2b7

Please sign in to comment.