Skip to content

Commit

Permalink
feat(transformer): fallback when failed to strip flow with sucrase
Browse files Browse the repository at this point in the history
  • Loading branch information
leegeunhyeok committed Sep 14, 2024
1 parent d17d758 commit 443e727
Show file tree
Hide file tree
Showing 7 changed files with 3,044 additions and 789 deletions.
17 changes: 14 additions & 3 deletions packages/transformer/lib/pipelines/AsyncTransformPipeline.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import path from 'node:path';
import fs from 'node:fs/promises';
import type { OnLoadArgs } from 'esbuild';
import { parse as hermesParse } from 'hermes-parser';
import {
transformWithBabel,
transformWithSwc,
stripFlowWithSucrase,
transformWithBabelAst,
} from '../transformer';
import { transformByBabelRule, transformBySwcRule } from '../helpers';
import type { AsyncTransformStep, ModuleMeta, TransformResult } from '../types';
Expand Down Expand Up @@ -61,15 +63,24 @@ export class AsyncTransformPipelineBuilder extends TransformPipelineBuilder<
this.stripFlowPackageNames,
);
if (stripFlowPackageNamesRegExp) {
pipeline.addStep((code, args) => {
pipeline.addStep(async (code, args) => {
if (
stripFlowPackageNamesRegExp.test(args.path) ||
this.isFlow(code, args.path)
) {
code = stripFlowWithSucrase(code, this.getContext(args));
const context = this.getContext(args);

try {
code = stripFlowWithSucrase(code, context);
} catch {
code = await transformWithBabelAst(
hermesParse(code, { babel: true, flow: 'all' }),
context,
);
}
}

return Promise.resolve({ code, done: false });
return { code, done: false };
});
}

Expand Down
37 changes: 31 additions & 6 deletions packages/transformer/lib/transformer/babel/babel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { TransformOptions } from '@babel/core';
import { loadOptions, transformAsync, transformSync } from '@babel/core';
import {
loadOptions,
transformAsync,
transformSync,
transformFromAstAsync,
type TransformOptions,
type Node,
} from '@babel/core';
import type {
AsyncTransformer,
SyncTransformer,
Expand All @@ -18,7 +24,7 @@ const loadBabelOptions = (
};

export const transformWithBabel: AsyncTransformer<TransformOptions> = async (
code: string,
source,
context,
preset,
) => {
Expand All @@ -27,7 +33,7 @@ export const transformWithBabel: AsyncTransformer<TransformOptions> = async (
throw new Error('cannot load babel options');
}

const result = await transformAsync(code, babelOptions);
const result = await transformAsync(source, babelOptions);
if (typeof result?.code !== 'string') {
throw new Error('babel transformed source is empty');
}
Expand All @@ -36,7 +42,7 @@ export const transformWithBabel: AsyncTransformer<TransformOptions> = async (
};

export const transformSyncWithBabel: SyncTransformer<TransformOptions> = (
code: string,
source,
context,
preset,
) => {
Expand All @@ -45,10 +51,29 @@ export const transformSyncWithBabel: SyncTransformer<TransformOptions> = (
throw new Error('cannot load babel options');
}

const result = transformSync(code, babelOptions);
const result = transformSync(source, babelOptions);
if (typeof result?.code !== 'string') {
throw new Error('babel transformed source is empty');
}

return result.code;
};

export const transformWithBabelAst: AsyncTransformer<
TransformOptions,
Node
> = async (ast, context, preset) => {
const babelOptions = loadBabelOptions(context, preset?.(context));
if (!babelOptions) {
throw new Error('cannot load babel options');
}

const result = await transformFromAstAsync(ast, undefined, babelOptions);
if (typeof result?.code !== 'string') {
throw new Error('babel transformed source is empty');
}

return result.code;
};

// @TODO: Add transformSyncWithBabelAST
8 changes: 4 additions & 4 deletions packages/transformer/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import type { OnLoadArgs } from 'esbuild';
import type { TransformOptions as BabelTransformOptions } from '@babel/core';
import type { Options as SwcTransformOptions } from '@swc/core';

export type AsyncTransformer<TransformerOptions> = (
code: string,
export type AsyncTransformer<TransformerOptions, Source = string> = (
source: Source,
context: TransformerContext,
preset?: TransformerOptionsPreset<TransformerOptions>,
) => Promise<string>;

export type SyncTransformer<TransformerOptions> = (
code: string,
export type SyncTransformer<TransformerOptions, Source = string> = (
source: Source,
context: TransformerContext,
preset?: TransformerOptionsPreset<TransformerOptions>,
) => string;
Expand Down
3 changes: 2 additions & 1 deletion packages/transformer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@
"esbuild": "^0.19.5"
},
"dependencies": {
"@babel/core": "^7.23.2",
"@babel/core": "^7.25.2",
"@react-native-esbuild/config": "workspace:*",
"@swc/core": "^1.3.95",
"@swc/helpers": "^0.5.3",
"hermes-parser": "^0.23.1",
"md5": "^2.3.0",
"sucrase": "^3.34.0",
"swc-plugin-coverage-instrument": "^0.0.20",
Expand Down
1 change: 1 addition & 0 deletions packages/transformer/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"declaration": true,
"emitDeclarationOnly": true
},
"files": ["../../types/index.d.ts", "types/lib.d.ts"],
"include": ["./lib", "./tests"],
"exclude": ["./dist"]
}
28 changes: 28 additions & 0 deletions packages/transformer/types/lib.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
declare module 'hermes-parser' {
import type { Node } from '@babel/core';

interface HermesParserOptions {
babel?: boolean;
allowReturnOutsideFunction?: boolean;
flow?: 'all' | 'detect';
sourceFilename?: string | null;
sourceType?: 'module' | 'script' | 'unambiguous';
tokens?: boolean;
}

/**
* Returns `Node` when call with `babel: true` option.
*/
type MaybeBabelAstNode = Node;

interface HermesParser {
parse: (code: string, options: HermesParserOptions) => MaybeBabelAstNode;
}

declare function parse(
code: string,
options: HermesParserOptions,
): MaybeBabelAstNode;

export const parse;
}
Loading

0 comments on commit 443e727

Please sign in to comment.