Skip to content
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
10 changes: 8 additions & 2 deletions benches/un-undefined.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@ void 99;
const main = async () => {
await suite(
title,
...([10, 100, 1000, 5000].map((count) => {
...([10, 100, 1000].map((count) => {
const source = snippet.repeat(count)
return add(`items=${count}`, async () => {
return add(`jscodeshift=${count}`, async () => {
await runTransformationRules({ path: '', source }, [title])
})
})),
...([10, 100, 1000, 5000].map((count) => {
const source = snippet.repeat(count)
return add(`ast-grep=${count}`, async () => {
await runTransformationRules({ path: '', source }, [`${title}.grep`])
})
})),
cycle(),
complete(),
save({
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"lint:fix": "eslint src --fix"
},
"dependencies": {
"@ast-grep/napi": "^0.18.1",
"fs-extra": "^11.2.0",
"globby": "^11.1.0",
"picocolors": "^1.0.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/unminify.worker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
import { runDefaultTransformationRules } from '@wakaru/unminify'
import { runTransformationRules, transformationRuleIds } from '@wakaru/unminify/nodejs'
import fsa from 'fs-extra'
import { ThreadWorker } from 'poolifier'
import type { UnminifyWorkerParams } from './types'
Expand All @@ -13,7 +13,7 @@ export async function unminify(data?: UnminifyWorkerParams) {
const source = await fsa.readFile(inputPath, 'utf-8')
const fileInfo = { path: inputPath, source }

const { code, timing } = await runDefaultTransformationRules(fileInfo, { moduleMeta, moduleMapping })
const { code, timing } = await runTransformationRules(fileInfo, transformationRuleIds, { moduleMeta, moduleMapping })
await fsa.ensureFile(outputPath)
await fsa.writeFile(outputPath, code, 'utf-8')

Expand Down
3 changes: 3 additions & 0 deletions packages/cli/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export default defineConfig({
'process.env.NODE_DEBUG': 'undefined',
},
minify: true,
external: [
'@ast-grep/napi',
],
noExternal: [
'jscodeshift',
'ast-types',
Expand Down
6 changes: 3 additions & 3 deletions packages/playground/src/atoms/rule.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { transformationRules } from '@wakaru/unminify'
import { transformationRuleIds, transformationRules } from '@wakaru/unminify'
import { atom } from 'jotai/vanilla'
import { atomWithStorage } from 'jotai/vanilla/utils'
import { KEY_DISABLED_RULES, KEY_RULE_ORDER } from '../const'
Expand All @@ -11,7 +11,7 @@ export const prettifyRules = [

export const allRulesAtom = atom(() => transformationRules)

export const ruleOrderAtom = atomWithStorage<string[]>(KEY_RULE_ORDER, transformationRules.map(rule => rule.id))
export const ruleOrderAtom = atomWithStorage<string[]>(KEY_RULE_ORDER, transformationRuleIds)

export const orderedRulesAtom = atom((get) => {
const ruleOrder = get(ruleOrderAtom)
Expand Down Expand Up @@ -57,5 +57,5 @@ export const toggleRuleAtom = atom(null, (get, set, ruleId: string) => {

export const resetRulesAtom = atom(null, (_get, set) => {
set(disabledRuleIdsAtom, [])
set(ruleOrderAtom, transformationRules.map(rule => rule.id))
set(ruleOrderAtom, transformationRuleIds)
})
3 changes: 3 additions & 0 deletions packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"sideEffects": false,
"exports": {
"./array": "./src/array.ts",
"./astGrepRule": "./src/astGrepRule.ts",
"./jscodeshift": "./src/jscodeshift.ts",
"./rule": "./src/rule.ts",
"./runner": "./src/runner.ts",
Expand All @@ -33,9 +34,11 @@
"pathe": "^1.1.2"
},
"devDependencies": {
"@ast-grep/napi": "^0.18.1",
"@types/jscodeshift": "^0.11.11",
"ast-types": "^0.16.1",
"jscodeshift": "^0.15.2",
"magic-string": "^0.30.5",
"typescript": "^5.3.3",
"zod": "^3.22.4"
}
Expand Down
102 changes: 102 additions & 0 deletions packages/shared/src/astGrepRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { type SgNode, js } from '@ast-grep/napi'
import MagicString from 'magic-string'
import type { BaseTransformationRule } from './rule'
import type { Transform } from 'jscodeshift'
import type { ZodSchema, z } from 'zod'

export type AstGrepTransformation<Schema extends ZodSchema = ZodSchema> = (root: SgNode, s: MagicString, params: z.infer<Schema>) => MagicString | void

export class AstGrepTransformationRule<Schema extends ZodSchema = ZodSchema> implements BaseTransformationRule {
type = 'ast-grep' as const

id: string

name: string

tags: string[]

schema?: ZodSchema

transform: AstGrepTransformation<Schema>

constructor({
name, tags = [], transform, schema,
}: {
name: string
tags?: string[]
transform: AstGrepTransformation<Schema>
schema?: ZodSchema
},
) {
this.id = name
this.name = name
this.tags = tags
this.transform = transform
this.schema = schema
}

execute({
source, filename, params,
}: {
source: string
filename: string
params: z.infer<Schema>
}) {
try {
const ast = js.parse(source)
const root = ast.root()
const s = new MagicString(source)
const resultS = this.transform(root, s, params)
return resultS ? resultS.toString() : source
}
catch (err: any) {
console.error(`\nError running rule ${this.name} on ${filename}`, err)
return source
}
}

toJSCodeshiftTransform(): Transform {
const transform: Transform = (file, _api, options) => {
const { source } = file
const params = options as z.infer<Schema>
return this.execute({ source, filename: file.path, params })
}
return transform
}

withId(id: string) {
const rule = this.clone()
rule.id = id
return rule
}

private clone() {
return new AstGrepTransformationRule({
name: this.name,
tags: this.tags,
transform: this.transform,
schema: this.schema,
})
}
}

export const createAstGrepTransformationRule = <Schema extends ZodSchema = ZodSchema>(
{
name,
tags = [],
transform,
schema,
}: {
name: string
tags?: string[]
transform: AstGrepTransformation<Schema>
schema?: ZodSchema
},
): AstGrepTransformationRule<Schema> => {
return new AstGrepTransformationRule({
name,
tags,
transform,
schema,
})
}
4 changes: 3 additions & 1 deletion packages/shared/src/rule.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { AstGrepTransformationRule } from './astGrepRule'
import type { JSCodeshiftTransformationRule } from './jscodeshiftRule'
import type { StringTransformationRule } from './stringRule'
import type { ModuleMapping, ModuleMeta } from './types'
Expand Down Expand Up @@ -28,7 +29,7 @@ export interface JSCodeshiftTransform {
}

export interface BaseTransformationRule {
type: 'jscodeshift' | 'string' | 'rule-set'
type: 'jscodeshift' | 'string' | 'ast-grep' | 'rule-set'
/**
* The unique id of the rule
*/
Expand All @@ -55,6 +56,7 @@ export interface BaseTransformationRule {
export type TransformationRule<Schema extends ZodSchema = ZodSchema> =
| JSCodeshiftTransformationRule<Schema>
| StringTransformationRule<Schema>
| AstGrepTransformationRule<Schema>
| MergedTransformationRule

export class MergedTransformationRule implements BaseTransformationRule {
Expand Down
20 changes: 20 additions & 0 deletions packages/shared/src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,26 @@ export async function executeTransformationRules<P extends Record<string, any>>(
currentRoot = null
break
}
case 'ast-grep': {
const stopMeasure1 = timing.startMeasure(filePath, 'jscodeshift-print')
currentSource ??= currentRoot?.toSource() ?? source
stopMeasure1()

try {
const stopMeasure2 = timing.startMeasure(filePath, rule.id)
currentSource = rule.execute({
source: currentSource,
filename: filePath,
params,
}) ?? currentSource
stopMeasure2()
}
catch (err: any) {
console.error(`\nError running rule ${rule.id} on ${filePath}`, err)
}
currentRoot = null
break
}
default: {
throw new Error(`Unsupported rule type ${rule.type} from ${rule.id}`)
}
Expand Down
4 changes: 4 additions & 0 deletions packages/unminify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
"author": "Pionxzh",
"license": "MIT",
"sideEffects": false,
"exports": {
".": "./src/index.ts",
"./nodejs": "./src/nodejs.ts"
},
"main": "src/index.ts",
"bin": "dist/cli.cjs",
"files": [
Expand Down
2 changes: 1 addition & 1 deletion packages/unminify/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { executeTransformationRules } from '@wakaru/shared/runner'
import { transformationRules } from './transformations'
import type { FileInfo } from 'jscodeshift'

export * from './transformations'
export { transformationRules, transformationRuleIds } from './transformations'

export function runDefaultTransformationRules<P extends Record<string, any>>(
fileInfo: FileInfo,
Expand Down
22 changes: 22 additions & 0 deletions packages/unminify/src/nodejs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { nonNullable } from '@wakaru/shared/array'
import { executeTransformationRules } from '@wakaru/shared/runner'
import { transformationRules } from './transformations/node'
import type { FileInfo } from 'jscodeshift'

export { transformationRules, transformationRuleIds } from './transformations'

export function runDefaultTransformationRules<P extends Record<string, any>>(
fileInfo: FileInfo,
params: P = {} as any,
) {
return executeTransformationRules(fileInfo.source, fileInfo.path, transformationRules, params)
}

export function runTransformationRules<P extends Record<string, any>>(
fileInfo: FileInfo,
ruleIds: string[],
params: P = {} as any,
) {
const rules = ruleIds.map(id => transformationRules.find(rule => rule.id === id)).filter(nonNullable)
return executeTransformationRules(fileInfo.source, fileInfo.path, rules, params)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { defineInlineTest } from '@wakaru/test-utils'
import transform from '../un-boolean.grep'

const inlineTest = defineInlineTest(transform)

inlineTest('transform !0 to true and !1 to false',
`
let a = !1;
const b = !0;

var obj = {
value: !0
};
`,
`
let a = false;
const b = true;

var obj = {
value: true
};
`,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { defineInlineTest } from '@wakaru/test-utils'
import transform from '../un-esmodule-flag.grep'

const inlineTest = defineInlineTest(transform)

inlineTest('remove es module helper from ES5+',
`
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(module.exports, "__esModule", {
value: !0
});
`,
`
`,
)

inlineTest('remove es module helper from ES3',
`
exports.__esModule = !0;
exports.__esModule = true;
exports["__esModule"] = true;
module.exports.__esModule = !0;
module.exports.__esModule = true;
module.exports["__esModule"] = true;
`,
`
`,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { defineInlineTest } from '@wakaru/test-utils'
import transform from '../un-infinity.grep'

const inlineTest = defineInlineTest(transform)

inlineTest('transform {number} / 0 to Infinity',
`
0 / 0;
1 / 0;
-1 / 0;
99 / 0;

'0' / 0;
'1' / 0;
'-1' / 0;
'99' / 0;

x / 0;

[0 / 0, 1 / 0]
`,
`
0 / 0;
Infinity;
-Infinity;
99 / 0;

'0' / 0;
'1' / 0;
'-1' / 0;
'99' / 0;

x / 0;

[0 / 0, Infinity]
`,
)
Loading