Skip to content
This repository has been archived by the owner on Mar 5, 2023. It is now read-only.

Added --cwd option #50

Closed
wants to merge 3 commits into from
Closed
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/pretty-tomatoes-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate-codegen': patch
---

Added the --cwd option to change the working directory that the CLI tool operates in. This can be useful for altering which node_modules folder you'd like to target.
32 changes: 31 additions & 1 deletion packages/xstate-compiled/readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## Type Safe State Machines

`xstate-codegen` gives you 100% type-safe usage of XState in Typescript. You get type safety on:
`xstate-codegen` gives you 100% type-safe usage of XState in Typescript. [Try it out at this codesandbox!](https://codesandbox.io/s/xstate-codegen-example-7etw2?file=/src/demo.machine.ts)

You get type safety on:

- Transition targets: `on: {EVENT: 'deep.nested.state'}`
- Services
Expand Down Expand Up @@ -46,6 +48,28 @@ type Event = { type: 'DUMMY_TYPE' };
const machine = Machine<Context, Event, 'uniqueId'>({});
```

### Usage with React

```ts
import { useMachine } from '@xstate/compiled/react';
import { machine } from './myMachine.machine';

const [state, dispatch] = useMachine(machine, {
// all options in here will be type checked
});
```

### Usage with Interpret

```ts
import { interpret } from '@xstate/compiled';
import { machine } from './myMachine.machine';

const service = interpret(machine).withConfig({
// all options in here will be type checked
});
```

## Options

### Once
Expand All @@ -61,3 +85,9 @@ By default, the CLI watches for changes in your files. Running `--once` runs the
By default, the CLI adds the required declaration files inside node_modules at `node_modules/@xstate/compiled`. This writes the declaration files to a specified directory.

> Note, this only writes the declaration files to the directory. The `.js` files still get written to `node_modules/@xstate/compiled`.

### cwd

`xstate-codegen "src/**/**.machine.ts" --cwd ../`

Change the working directory that xstate-codegen operates in. This can sometimes be useful for altering which node_modules folder you'd like to target.
11 changes: 7 additions & 4 deletions packages/xstate-compiled/src/extractMachines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ type ReferencePathsByImportName = Record<
Array<babelCore.NodePath<babelCore.types.Node>>
>;

const cwd = process.cwd();
const extensions = ['.tsx', '.ts', '.jsx', '.js'];

const getImports = (
Expand Down Expand Up @@ -241,9 +240,13 @@ const getCreatedExports = (
}
};

export const extractMachines = async (
filePath: string,
): Promise<ExtractedMachine[]> => {
export const extractMachines = async ({
cwd,
filePath,
}: {
filePath: string;
cwd: string;
}): Promise<ExtractedMachine[]> => {
const resolvedFilePath = path.resolve(cwd, filePath);

const build = await rollup({
Expand Down
24 changes: 16 additions & 8 deletions packages/xstate-compiled/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ if (!pattern) {
process.exit(1);
}

const toRelative = (filePath: string) => path.relative(process.cwd(), filePath);
const cwd = objectArgs.cwd || process.cwd();

const toRelative = (filePath: string) => path.relative(cwd, filePath);

const typedSuffix = /\.typed\.(js|ts|tsx|jsx)$/;

Expand All @@ -42,7 +44,13 @@ let fileCache: Record<
ReturnType<typeof introspectMachine> & { id: string }
> = {};

gaze(pattern, {}, async function(err, watcher) {
type GazeOptions = Parameters<typeof gaze>[1];

const gazeOptions: GazeOptions = {
cwd,
};

gaze(pattern, gazeOptions, async function(err, watcher) {
if (err) {
console.log(err);
process.exit(1);
Expand All @@ -61,7 +69,7 @@ gaze(pattern, {}, async function(err, watcher) {
process.exit(1);
}

printJsFiles();
printJsFiles(cwd);
console.clear();

const addToCache = async (filePath: string) => {
Expand All @@ -76,7 +84,7 @@ gaze(pattern, {}, async function(err, watcher) {
if (!code.includes('@xstate/compiled')) {
return;
}
const machines = await extractMachines(filePath);
const machines = await extractMachines({ cwd, filePath });
if (machines.length === 0) {
return;
}
Expand All @@ -100,7 +108,7 @@ gaze(pattern, {}, async function(err, watcher) {
}
}, Promise.resolve());

printToFile(fileCache, objectArgs.outDir);
printToFile({ cache: fileCache, cwd, outDir: objectArgs.outDir });

if (objectArgs.once) {
console.log('Completed!'.green.bold);
Expand All @@ -113,20 +121,20 @@ gaze(pattern, {}, async function(err, watcher) {
this.on('changed', async (filePath) => {
console.log(`File Changed: `.cyan.bold + toRelative(filePath).gray);
await addToCache(filePath);
printToFile(fileCache, objectArgs.outDir);
printToFile({ cache: fileCache, cwd, outDir: objectArgs.outDir });
});
// @ts-ignore
this.on('added', async (filePath) => {
console.log(`File Added: `.green.bold + toRelative(filePath).gray);
await addToCache(filePath);
printToFile(fileCache, objectArgs.outDir);
printToFile({ cache: fileCache, cwd, outDir: objectArgs.outDir });
});

// @ts-ignore
this.on('deleted', async (filePath) => {
console.log(`File Deleted: `.red.bold + toRelative(filePath).gray);
delete fileCache[filePath];
printToFile(fileCache, objectArgs.outDir);
printToFile({ cache: fileCache, cwd, outDir: objectArgs.outDir });
});

console.log(`Watching for file changes in: `.cyan.bold + pattern.gray);
Expand Down
31 changes: 19 additions & 12 deletions packages/xstate-compiled/src/printToFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ export const getDeclarationFileTexts = (
};
};

export const getNodeModulesDir = () => {
const packageJson = pkgUp.sync();
export const getNodeModulesDir = (cwd: string) => {
const packageJson = pkgUp.sync({
cwd,
});

if (!packageJson) {
throw new Error(
Expand All @@ -83,29 +85,34 @@ export const getNodeModulesDir = () => {
return targetDir;
};

export const printToFile = (
cache: Record<string, ReturnType<typeof introspectMachine> & { id: string }>,
outDir?: string,
) => {
export const printToFile = ({
cache,
outDir,
cwd,
}: {
cache: Record<string, ReturnType<typeof introspectMachine> & { id: string }>;
outDir?: string;
cwd: string;
}) => {
const files = getDeclarationFileTexts(cache);
const nodeModulesDir = getNodeModulesDir();
const nodeModulesDir = getNodeModulesDir(cwd);
const targetDir = path.resolve(nodeModulesDir, '@xstate/compiled');

/** Delete @xstate/compiled directory so that it triggers VSCode to re-check it */
rimraf.sync(path.join(targetDir, '*.d.ts'));

printJsFiles();
printJsFiles(cwd);
ensureMultipleFoldersExist(nodeModulesDir, ['@xstate', 'compiled']);

fs.writeFileSync(
outDir
? path.resolve(process.cwd(), outDir, 'index.d.ts')
? path.resolve(cwd, outDir, 'index.d.ts')
: path.join(targetDir, 'index.d.ts'),
files['index.d.ts'],
);
fs.writeFileSync(
outDir
? path.resolve(process.cwd(), outDir, 'react.d.ts')
? path.resolve(cwd, outDir, 'react.d.ts')
: path.join(targetDir, 'react.d.ts'),
files['react.d.ts'],
);
Expand All @@ -123,8 +130,8 @@ export const printToFile = (
* of rollup looking at the code to ensure there is a module for rollup
* to statically analyse
*/
export const printJsFiles = () => {
const nodeModulesDir = getNodeModulesDir();
export const printJsFiles = (cwd: string) => {
const nodeModulesDir = getNodeModulesDir(cwd);
const targetDir = path.resolve(nodeModulesDir, '@xstate/compiled');

ensureMultipleFoldersExist(nodeModulesDir, ['@xstate', 'compiled']);
Expand Down
16 changes: 11 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,22 @@ const machine = Machine<Context, Event, 'uniqueId'>({});

```ts
import { useMachine } from '@xstate/compiled/react';
import { machine } from './myMachine.machine'
import { machine } from './myMachine.machine';

const [state, dispatch] = useMachine(machine, {
// all options in here will be type checked
})
});
```

### Usage with Interpret

```ts
import { interpret } from '@xstate/compiled';
import { machine } from './myMachine.machine'
import { machine } from './myMachine.machine';

const service = interpret(machine, {
const service = interpret(machine).withConfig({
// all options in here will be type checked
})
});
```

## Options
Expand All @@ -85,3 +85,9 @@ By default, the CLI watches for changes in your files. Running `--once` runs the
By default, the CLI adds the required declaration files inside node_modules at `node_modules/@xstate/compiled`. This writes the declaration files to a specified directory.

> Note, this only writes the declaration files to the directory. The `.js` files still get written to `node_modules/@xstate/compiled`.

### cwd

`xstate-codegen "src/**/**.machine.ts" --cwd ../`

Change the working directory that xstate-codegen operates in. This can sometimes be useful for altering which node_modules folder you'd like to target.