dsherret / dsherret/ts-morph

Get AST after customTransformers.before without emit

Open
#787 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
TypeScript
Stars
6.2k
Forks
238
Avg merge
2m
Merged PRs (30d)
1

Description

**Is your feature request related to a problem? Please describe.**

I am trying to run [@nestjs/swagger](https://github.com/nestjs/swagger)'s plugin over TS files, and rather than emit the source directly, save the source over the original file.

I want to do this, because due to current tsc limitations, this plugin can't run with a normal "tsc" CLI call, which is what I use as part of my build chain, and I prefer not to switch to nest-cli, as that presents one more thing that can go wrong on build and in watch mode.

Working directly with the typescript API I get some runtime errors, which I tried to workaround with edits to @nestjs/swagger itself, but ultimately, I failed (I only kept trading in one error for another), so I thought I'd use ts-morph to abstract the weird stuff I'm apparently not using correctly.

However, even with ts-morph, I seem to be back at square 1, where I have the plugin, and I can't use it.

**Describe the solution you'd like**
ts-morph's SourceFile should provide another transform()-like method that should accept a tsc compatible "before" ```TransformerFactory``` or ```CustomTransformer```, and applies that, allowing further manipulations or just saves over the final files.

e.g. (tentatively calling it "transformWithCompiler"; whatever the name is, it's fine by me...)

```typescript
import { before } from '@nestjs/swagger/dist/plugin';
import { Project, SourceFile } from 'ts-morph';

const project = new Project({
tsConfigFilePath: 'path/to/tsconfig.json',
});

const swaggerTransformer = before({}, project.getProgram().compilerObject);

const saves: Array> = [];
project.getSourceFiles().forEach((file: SourceFile): void => {
saves.push(file.transformWithCompiler(swaggerTransformer).save());
});
Promise.all(saves).then(() => {
console.log('Done');
});
```

Alternatively, the ```TransformTraversalControl``` object could expose a ```ts.TransformerContext``` object. That would allow calling the "tsc" transformer from inside the transform function, e.g.

```typescript
import { before } from '@nestjs/swagger/dist/plugin';
import { Project, SourceFile } from 'ts-morph';
import { Node } from 'typescript';

const project = new Project({
tsConfigFilePath: 'path/to/tsconfig.json',
});

const swaggerTransformer = before({}, project.getProgram().compilerObject);

const saves: Array> = [];
project.getSourceFiles().forEach((file: SourceFile): void => {
saves.push(file.transform((ttc: TransformTraversalControl): Node => {
return swaggerTransformer(ttc.getCompilerTransformContext());
}).save());
});
Promise.all(saves).then(() => {
console.log('Done');
});
```

**Describe alternatives you've considered**

I tried
```typescript
import { before } from '@nestjs/swagger/dist/plugin';
import { Project, SourceFile } from 'ts-morph';

const project = new Project({
tsConfigFilePath: 'path/to/tsconfig.json',
});

const swaggerTransformer = before({}, project.getProgram().compilerObject);

const saves: Array> = [];
project.getSourceFiles().forEach((file: SourceFile): void => {
saves.push(file.transform(/*build error here*/swaggerTransformer).save());
});
Promise.all(saves).then(() => {
console.log('Done');
});
```

but that fails to compile, because the transform() method is using a custom API, not typescript's actual API.

The example at [the emitting page](https://ts-morph.com/emitting) doesn't work either, for the same reason - it's a transformer intended for "typescript", not "ts-morph".

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.