JavaScript 및 TypeScript에 대한 매우 강력한 구조적 검색 및 대체를 통해 리팩토링을 자동화합니다.
$<name>
)$$<name>
)$$$<name>
)$Maybe(pattern)
$Or(...)
$And(...)
$Maybe<pattern>
$Or<...>
$And<...>
$Ordered
$Unordered
constructor(backend: Backend, paths: NodePath<any>[] | Match[], options?: { withCaptures?: Match[] })
.find(...)
( Astx
).closest(...)
( Astx
).destruct(...)
( Astx
)FindOptions
FindOptions.where
( { [captureName: string]: (path: Astx) => boolean }
).find(...).replace(...)
( void
).findImports(...)
( Astx
).addImports(...)
( Astx
).removeImports(...)
( boolean
).replaceImport(...).with(...)
( boolean
).remove()
( void
).matched
( this | null
).size()
( number
)[name: `$${string}` | `$$${string}` | `$$$${string}`]
( Astx
).placeholder
( string | undefined
).node
( Node
).path
( NodePath
).code
( string
).stringValue
( string
)[Symbol.iterator]
( Iterator<Astx>
).matches
( Match[]
).match
( Match
).paths
( NodePath[]
).nodes
( Node[]
).some(predicate)
( boolean
).every(predicate)
( boolean
).filter(iteratee)
( Astx
).map<T>(iteratee)
( T[]
).at(index)
( Astx
).withCaptures(...captures)
( Astx
).type
.path
.node
.paths
.nodes
.captures
.pathCaptures
.arrayCaptures
.arrayPathCaptures
.stringCaptures
exports.find
(선택 사항)exports.where
(선택 사항)exports.replace
(선택사항)exports.astx
(선택 사항)exports.onReport
(선택 사항)exports.finish
(선택사항)parser
parserOptions
prettier
간단한 리팩터링은 지루하고 반복적일 수 있습니다. 예를 들어 코드베이스 전체에 다음과 같은 변경을 적용하고 싶다고 가정해 보겠습니다.
// before:
rmdir ( 'old/stuff' )
rmdir ( 'new/stuff' , true )
// after:
rmdir ( 'old/stuff' )
rmdir ( 'new/stuff' , { force : true } )
rmdir
에 대한 여러 호출을 직접 변경하는 것은 짜증나는 일입니다. 정규식 바꾸기를 사용해 볼 수는 있지만 정규식에서 정말 열심히 작업하지 않으면 까다롭고 공백과 줄 바꿈을 잘 허용하지 않습니다. jscodeshift
사용할 수도 있지만 이와 같은 간단한 경우에는 시간이 너무 오래 걸리고 필요 이상으로 어렵게 느껴지기 시작합니다.
이제 더 나은 옵션이 있습니다. astx
사용하여 자신있게 리팩토링할 수 있습니다!
astx
--find ' rmdir($path, $force) '
--replace ' rmdir($path, { force: $force }) '
이는 astx
패턴 의 기본 예입니다. 이는 자리 표시자 및 기타 특수 일치 구성을 포함할 수 있는 JS 또는 TS 코드입니다. astx
패턴과 일치하는 코드를 찾고 $path
및 $force
대신 모든 표현식을 허용합니다. 그런 다음 astx
각 일치 항목을 대체 패턴으로 대체하여 $path
( 'new/stuff'
) 및 $force
( true
)에 대해 캡처한 표현식을 대체합니다.
그러나 이것은 시작에 불과합니다. astx
패턴은 이보다 훨씬 더 복잡하고 강력할 수 있으며 고급 사용 사례의 경우 사용할 수 있는 직관적인 API가 있습니다.
for ( const match of astx . find `rmdir($path, $force)` ) {
const { $path , $force } = match
// do stuff with $path.node, $path.code, etc...
}
Do not access Object.prototype method 'hasOwnProperty' from target object
오류가 많이 발생합니까?
// astx.js
exports . find = `$a.hasOwnProperty($b)`
exports . replace = `Object.hasOwn($a, $b)`
최근 업무상 다음과 같이 변경하고 싶었습니다.
// before
const pkg = OrgPackage ( {
subPackage : [
'services' ,
async ? 'async' : 'blocking' ,
... namespace ,
Names . ServiceType ( { resource , async } ) ,
] ,
} )
// after
const pkg = [
... OrgPackage ( ) ,
'services' ,
async ? 'async' : 'blocking' ,
... namespace ,
Names . ServiceType ( { resource , async } ) ,
]
목록 일치를 사용하면 간단합니다.
// astx.js
exports . find = `OrgPackage({subPackage: [$$p]})`
exports . replace = `[...OrgPackage(), $$p]`
// astx.js
exports . find = `const $id = require('$source')`
exports . replace = `import $id from '$source'`
// astx.js
export const find = `if ($a) { if ($b) $body }`
export const replace = `if ($a && $b) $body`
jscodeshift-add-imports
에는 다음 패턴을 따르는 많은 테스트 사례가 있었습니다.
it ( `leaves existing default imports untouched` , function ( ) {
const code = `import Baz from 'baz'`
const root = j ( code )
const result = addImports ( root , statement `import Foo from 'baz'` )
expect ( result ) . to . deep . equal ( { Foo : 'Baz' } )
expect ( root . toSource ( ) ) . to . equal ( code )
} )
나는 다음과 같이 더 건조하게 만들고 싶었습니다.
it ( `leaves existing default imports untouched` , function ( ) {
testCase ( {
code : `import Baz from 'baz'` ,
add : `import Foo from 'baz'` ,
expectedCode : `import Baz from 'baz'` ,
expectedReturn : { Foo : 'Baz' } ,
} )
} )
위의 변환은 다음과 같습니다. (물론 예상되는 코드가 다른 경우 등을 위해 몇 가지 변형을 실행해야 했습니다.)
exports . find = `
const code = $code
const root = j(code)
const result = addImports(root, statement`$add`)
expect(result).to.deep.equal($expectedReturn)
expect(root.toSource()).to.equal(code)
`
exports . replace = `
testCase({
code: $code,
add: `$add`,
expectedCode: $code,
expectedReturn: $expectedReturn,
})
`
엄청난 노력 끝에 마침내 2022년 12월에 버전 2가 출시되었습니다. 지금은 VSCode 확장 작업을 하고 있습니다. 그 후에는 astx
사용법을 더 잘 설명하는 문서 웹사이트를 만들고 싶습니다.
VSCode 확장은 현재 베타 버전이지만 사용해 보세요!
이것을 만들려고 생각하는 동안 $
캡처 구문에 영감을 준 유사한 도구인 파악을 발견했습니다. 어쨌든 내가 astx
만들기로 결정한 몇 가지 이유가 있습니다.
grasp -e 'setValue($k, $v, true)' -R 'setValueSilently({{k}}, {{v}})' file.js
jscodeshift
와 유사한 API를 원했습니다. astx
의 철학은 다음과 같습니다.
AST의 구조에 대해 알아야 하는 경우 AST Explorer에 코드를 붙여넣습니다.
Astx 찾기 패턴은 자리 표시자 와일드카드나 $Or(A, B)
와 같은 기타 특수 구문을 포함할 수 있는 JavaScript 또는 TypeScript 코드입니다. 일반적으로 와일드카드나 특수 구문이 아닌 패턴 부분은 정확히 일치해야 합니다.
예를 들어, 찾기 패턴 foo($a)
단일 인수를 사용하여 foo
함수에 대한 모든 호출과 일치합니다. 인수는 무엇이든 가능하며 $a
로 캡처 됩니다.
교체 패턴은 찾기 패턴에 의해 자리 표시자가 자리 표시자 이름에 캡처 된 항목으로 대체되고 $Or(A, B)
와 같은 특수 찾기 구문이 교체 패턴에서 특별한 의미가 없다는 점을 제외하면 찾기 패턴과 거의 동일합니다. (미래에는 캡처된 노드에서 일종의 변환을 수행하는 특별한 대체 구성이 있을 수 있습니다.)
예를 들어 찾기 패턴 foo($a)
foo(1 + 2)
와 일치하고 대체 패턴 foo({ value: $a })
foo({ value: 1 + 2 })
코드를 생성합니다.
일반적으로 $
로 시작하는 식별자는 와일드카드처럼 기능하는 자리 표시자 입니다. 자리 표시자에는 세 가지 유형이 있습니다.
$<name>
은 단일 노드("노드 자리 표시자")와 일치합니다.$$<name>
은 연속 노드 목록("배열 자리 표시자")과 일치합니다.$$$<name>
: 다른 모든 형제와 일치합니다("나머지 자리 표시자") <name>
(제공된 경우)은 문자나 숫자로 시작해야 합니다. 그렇지 않으면 식별자가 자리 표시자로 처리되지 않습니다.
나머지 자리 표시자( $$$
)는 정렬된 목록 자리 표시자( $$
)의 형제일 수 없습니다.
자리 표시자가 익명이 아닌 한 일치하는 노드를 "캡처"합니다. 즉, 교체 패턴에서 동일한 자리 표시자를 사용하여 일치하는 노드를 생성된 교체에 보간할 수 있습니다. Node API에서는 자리 표시자 이름을 통해 캡처된 AST 경로/노드에 액세스할 수도 있습니다.
$<name>
) 이러한 자리 표시자는 단일 노드와 일치합니다. 예를 들어, [$a, $b]
패턴은 두 요소가 있는 배열 표현식과 일치하며 해당 요소는 $a
및 $b
로 캡처됩니다.
$$<name>
) 이러한 자리 표시자는 인접한 노드 목록과 일치합니다. 예를 들어, [1, $$a, 2, $$b]
패턴은 1
첫 번째 요소이고 2
다음 요소인 배열 표현식과 일치합니다. 1
과 처음 2
사이의 모든 요소는 $$a
로 캡처되고 처음 2
이후의 요소는 $$b
로 캡처됩니다.
$$$<name>
) 이러한 자리 표시자는 다른 항목과 일치하지 않는 나머지 형제 항목과 일치합니다. 예를 들어, [1, $$$a, 2]
패턴은 모든 인덱스에 요소 1
과 2
있는 배열 표현식과 일치합니다. 다른 모든 요소( 1
및 2
의 추가 발생 포함)는 $$$a
로 캡처됩니다.
이름이 없는 자리 표시자를 사용하여 노드를 캡처하지 않고 일치시킬 수 있습니다. $
임의의 단일 노드와 일치하고, $$
인접한 노드 목록과 일치하며, $$$
다른 모든 형제와 일치합니다.
동일한 캡처 자리 표시자를 두 번 이상 사용하는 경우 후속 위치는 자리 표시자의 첫 번째 발생에 대해 캡처된 위치와 일치해야 합니다.
예를 들어, 다음 패턴 foo($a, $a, $b, $b)
는 foo(1, 1, {foo: 1}, {foo: 1})
에만 일치합니다.
foo ( 1 , 1 , { foo : 1 } , { foo : 1 } ) // match
foo ( 1 , 2 , { foo : 1 } , { foo : 1 } ) // no match
foo ( 1 , 1 , { foo : 1 } , { bar : 1 } ) // no match
참고 : 배열 캡처 자리 표시자( $$a
) 및 나머지 캡처 자리 표시자( $$$a
)는 현재 역참조를 지원하지 않습니다.
ObjectExpression
(객체 리터럴이라고도 함) 패턴은 순서에 관계없이 동일한 속성을 가진 코드의 모든 ObjectExpression
과 일치합니다. 누락된 속성이나 추가 속성이 있는 경우 일치하지 않습니다. 예를 들어, { foo: 1, bar: $bar }
는 { foo: 1, bar: 2 }
또는 { bar: 'hello', foo: 1 }
와 일치하지만 { foo: 1 }
또는 { foo: 1, bar: 2, baz: 3 }
하지 않습니다. { foo: 1, bar: 2, baz: 3 }
.
...$$captureName
사용하여 추가 속성을 일치시킬 수 있습니다. 예를 들어 { foo: 1, ...$$rest }
는 { foo: 1 }
, { foo: 1, bar: 2 }
, { foo: 1, bar: 2, ...props }
과 일치합니다. { foo: 1, bar: 2, ...props }
등. 추가 속성은 match.arrayCaptures
/ match.arrayPathCaptures
에 캡처되며 대체 표현식으로 확산될 수 있습니다. 예를 들어 astx.find`{ foo: 1, ...$$rest }`.replace`{ bar: 1, ...$$rest }`
{ foo: 1, qux: {}, ...props }
를 변환합니다. { foo: 1, qux: {}, ...props }
{ bar: 1, qux: {}, ...props }
로 변환합니다.
/^$$[a-z0-9]+$/i
형식이 아닌 스프레드 속성은 캡처 자리 표시자가 아닙니다. 예를 들어 { ...foo }
{ ...foo }
에만 일치합니다. 그리고 { ...$_$foo }
{ ...$$foo }
만 일치합니다(선두 $_
$
의 이스케이프입니다).
현재는 특정 순서로 속성을 일치시킬 수 있는 방법이 없지만 나중에 추가될 수 있습니다.
AST에 노드 목록이 있는 대부분의 경우 $$
로 시작하는 자리 표시자를 사용하여 여러 요소를 일치시킬 수 있습니다. 예를 들어, [$$before, 3, $$after]
요소 3
을 포함하는 모든 배열 표현식과 일치합니다. 처음 3
이전의 요소는 $$before
에 캡처되고 처음 3
이후의 요소는 $$after
에 캡처됩니다.
이는 블록 문에서도 작동합니다. 예를 들어, function foo() { $$before; throw new Error('test'); $$after; }
throw new Error('test')
를 포함하는 function foo()
와 일치하며 해당 throw 문 앞과 뒤의 문은 각각 $$before
및 $$after
에 캡처됩니다.
어떤 경우에는 목록 일치가 기본적으로 정렬되고 어떤 경우에는 정렬되지 않습니다. 예를 들어 아래 표에 표시된 것처럼 ObjectExpression
속성 일치는 기본적으로 순서가 지정되지 않습니다. $$
자리 표시자 또는 특별한 $Ordered
자리 표시자를 사용하면 순서 일치가 강제됩니다. $$$
자리 표시자 또는 특별한 $Unordered
자리 표시자를 사용하면 순서가 지정되지 않은 일치가 강제됩니다.
$$$
로 시작하는 자리 표시자를 사용하는 경우 "나머지" 캡처로 처리되며 일치 표현식의 다른 모든 요소는 순서 없이 일치됩니다. 예를 들어 import {a, b, $$$rest} from 'foo'
import {c, b, d, e, a} from 'foo'
와 일치하며 지정자 c
, d
및 e
를 $$$rest
자리표시자.
나머지 자리 표시자( $$$
)는 정렬된 목록 자리 표시자( $$
)의 형제일 수 없습니다.
TODO로 표시된 일부 항목은 실제로 작동하지만 테스트되지 않았습니다.
유형 | 목록 일치를 지원합니까? | 기본적으로 순서가 지정되어 있지 않습니까? | 메모 |
---|---|---|---|
ArrayExpression.elements | ✅ | ||
ArrayPattern.elements | ✅ | ||
BlockStatement.body | ✅ | ||
CallExpression.arguments | ✅ | ||
Class(Declaration/Expression).implements | ✅ | ✅ | |
ClassBody.body | ✅ | ✅ | |
ComprehensionExpression.blocks | TODO | ||
DeclareClass.body | TODO | ✅ | |
DeclareClass.implements | TODO | ✅ | |
DeclareExportDeclaration.specifiers | TODO | ✅ | |
DeclareInterface.body | TODO | ||
DeclareInterface.extends | TODO | ||
DoExpression.body | TODO | ||
ExportNamedDeclaration.specifiers | ✅ | ✅ | |
Function.decorators | TODO | ||
Function.params | ✅ | ||
FunctionTypeAnnotation/TSFunctionType.params | ✅ | ||
GeneratorExpression.blocks | TODO | ||
ImportDeclaration.specifiers | ✅ | ✅ | |
(TS)InterfaceDeclaration.body | TODO | ✅ | |
(TS)InterfaceDeclaration.extends | TODO | ✅ | |
IntersectionTypeAnnotation/TSIntersectionType.types | ✅ | ✅ | |
JSX(Element/Fragment).children | ✅ | ||
JSX(Opening)Element.attributes | ✅ | ✅ | |
MethodDefinition.decorators | TODO | ||
NewExpression.arguments | ✅ | ||
ObjectExpression.properties | ✅ | ✅ | |
ObjectPattern.decorators | TODO | ||
ObjectPattern.properties | ✅ | ✅ | |
(ObjectTypeAnnotation/TSTypeLiteral).properties | ✅ | ✅ | 하나의 속성과 일치하려면 $a: $ 사용하고, 여러 속성과 일치하려면 $$a: $ 또는 $$$a: $ 사용합니다. |
Program.body | ✅ | ||
Property.decorators | TODO | ||
SequenceExpression | ✅ | ||
SwitchCase.consequent | ✅ | ||
SwitchStatement.cases | TODO | ||
TemplateLiteral.quasis/expressions | ❓ 구문을 생각해낼 수 있는지 잘 모르겠습니다. | ||
TryStatement.guardedHandlers | TODO | ||
TryStatement.handlers | TODO | ||
TSFunctionType.parameters | ✅ | ||
TSCallSignatureDeclaration.parameters | TODO | ||
TSConstructorType.parameters | TODO | ||
TSConstructSignatureDeclaration.parameters | TODO | ||
TSDeclareFunction.params | TODO | ||
TSDeclareMethod.params | TODO | ||
EnumDeclaration.body/TSEnumDeclaration.members | TODO | ✅ | |
TSIndexSignature.parameters | TODO | ||
TSMethodSignature.parameters | TODO | ||
TSModuleBlock.body | TODO | ||
TSTypeLiteral.members | ✅ | ✅ | |
TupleTypeAnnotation/TSTupleType.types | ✅ | ||
(TS)TypeParameterDeclaration.params | ✅ | ||
(TS)TypeParameterInstantiation.params | ✅ | ||
UnionTypeAnnotation/TSUnionType.types | ✅ | ✅ | |
VariableDeclaration.declarations | ✅ | ||
WithStatement.body | 누가 with 문을 사용합니까? |
'$foo'
와 같은 자리 표시자인 문자열은 모든 문자열과 일치하고 해당 내용을 match.stringCaptures.$foo
에 캡처합니다. 식별자와 동일한 이스케이프 규칙이 적용됩니다. 이는 `$foo`
와 같은 템플릿 리터럴 및 doSomething`$foo`
와 같은 태그가 지정된 템플릿 리터럴에도 적용됩니다.
이는 import 문 작업에 도움이 될 수 있습니다. 예를 들어 require 문을 가져오기로 변환을 참조하세요.
패턴의 빈 주석( /**/
)은 일치를 위한 노드를 "추출"합니다. 예를 들어 const x = { /**/ $key: $value }
패턴은 ObjectProperty
노드를 $key: $value
와 일치시킵니다.
파서는 $key: $value
자체를 구문 분석할 수 없거나 const x x: number
const x: number = 1
와 같은 다른 것과 달리 ObjectProperty
의미한다는 것을 알 수 없으므로 /**/
를 사용하면 이 문제를 해결하려면. 이를 사용하여 그 자체로 유효한 표현식이나 문이 아닌 모든 노드 유형을 일치시킬 수 있습니다. 예를 들어 type T = /**/ Array<number>
Array<number>
유형 주석과 일치합니다.
/**/
교체 패턴에서도 작동합니다.
$Maybe(pattern)
주어진 표현식과 일치하거나 해당 위치에 노드가 없습니다. 예를 들어, let $a = $Maybe(2)
는 let foo = 2
및 let foo
(초기화 도구 없음)와 일치하지만 let foo = 3
과는 일치하지 않습니다.
$Or(...)
주어진 패턴 중 하나 이상과 일치하는 노드를 일치시킵니다. 예를 들어 $Or(foo($$args), {a: $value})
foo
및 객체 리터럴에 대한 호출과 a
속성만 일치시킵니다.
$And(...)
주어진 패턴과 모두 일치하는 노드를 일치시킵니다. 이는 주어진 자리 표시자에 캡처할 수 있는 노드 유형을 좁히는 데 주로 유용합니다. 예를 들어, let $a = $And($init, $a + $b)
는 이니셜라이저가 $a + $b
와 일치하는 let
선언과 일치하고 이니셜라이저를 $init
로 캡처합니다.
$Maybe<pattern>
지정된 유형 주석과 일치하거나 해당 위치에 노드가 없습니다. 예를 들어 let $a: $Maybe<number>
let foo: number
및 let foo
(유형 주석 없음)와 일치하지만 let foo: string``let foo: string
일치하지 않습니다.
$Or<...>
지정된 유형 주석 중 하나 이상과 일치하는 노드와 일치합니다. 예를 들어 let $x: $Or<number[], string[]>
은 number[]
또는 string[]
유형의 let
선언과 일치합니다.
$And<...>
주어진 모든 유형 주석과 일치하는 노드와 일치합니다. 이는 주어진 자리 표시자에 캡처할 수 있는 노드 유형을 좁히는 데 주로 유용합니다. 예를 들어, let $a: $And<$type, $elem[]>
유형 주석이 $elem[]
과 일치하는 let
선언과 일치하고 유형 주석을 $type
으로 캡처합니다.
$Ordered
패턴이 형제 노드와 동일한 순서로 일치하도록 강제합니다.
$Unordered
패턴이 어떤 순서로든 형제 노드와 일치하도록 강제합니다.
import { NodePath } from 'astx'
이는 ast-types
와 동일한 NodePath
인터페이스이며 메소드 유형 정의가 일부 개선되었습니다. astx
향후 다양한 파서를 지원하기 위해 ast-types
사용하여 코드를 탐색합니다.
import { Astx } from 'astx'
constructor(backend: Backend, paths: NodePath<any>[] | Match[], options?: { withCaptures?: Match[] })
backend
사용되는 파서/생성기 구현입니다.
paths
Astx
메소드가 검색/작동할 NodePath
또는 Match
지정합니다.
.find(...)
( Astx
) 이 인스턴스의 시작 경로 내에서 지정된 패턴과 일치하는 항목을 찾고 일치 항목이 포함된 Astx
인스턴스를 반환합니다.
변환 함수에 전달된 초기 인스턴스에서 astx.find('foo($$args)')
호출하면 파일 내에서 foo
에 대한 모든 호출을 찾아 새 Astx
인스턴스에 해당 일치 항목을 반환합니다.
반환된 인스턴스의 메서드는 일치하는 경로에서만 작동합니다.
예를 들어 astx.find('foo($$args)').find('$a + $b')
수행하면 두 번째 find
호출은 foo($$args)
와 일치하는 항목 내에서 $a + $b
만 검색합니다. foo($$args)
파일의 어느 곳이 아니라.
.find
메소드나 태그된 템플릿 리터럴로 호출할 수 있습니다.
.find`pattern`
.find(pattern: string | string[] | Node | Node[] | NodePath | NodePath[] | ((wrapper: Astx) => boolean), options?: FindOptions)
패턴을 문자열로 제공하는 경우 유효한 표현식 또는 명령문이어야 합니다. 그렇지 않으면 이미 구문 분석했거나 구성한 유효한 AST 노드여야 합니다. 태그가 지정된 템플릿 리터럴에서 문자열, AST 노드, AST 노드 배열 및 Astx
인스턴스를 보간할 수 있습니다.
예를 들어 astx.find`${t.identifier('foo')} + 3`
수행할 수 있습니다.
또는 다음을 수행하여 여러 명령문을 일치시킬 수 있습니다.
astx . find `
const $a = $b;
$$c;
const $d = $a + $e;
`
이는 (예를 들어) const foo = 1; const bar = foo + 5;
문과 일치합니다. const foo = 1; const bar = foo + 5;
, 그 사이에 임의의 수의 명령문이 있습니다.
.closest(...)
( Astx
) .find()
와 비슷하지만 하위 항목으로 내려가는 대신 AST 상위 항목을 검색합니다. 주어진 패턴과 일치하는 각 입력 경로의 가장 가까운 둘러싸는 노드를 찾습니다.
.destruct(...)
( Astx
) .find()
와 비슷하지만 패턴에 대해 입력 경로의 하위 항목을 테스트하지 않습니다. 패턴과 일치하는 입력 경로만 결과에 포함됩니다.
FindOptions
다음과 같은 선택적 속성을 가진 객체:
FindOptions.where
( { [captureName: string]: (path: Astx) => boolean }
) 노드 캡처 조건. 예를 들어 찾기 패턴이 $a()
인 경우 { where: { $a: astx => /foo|bar/.test(astx.node.name) } }
를 가질 수 있으며 이는 인수가 없는 호출에만 일치합니다. foo
또는 bar
에.
.find(...).replace(...)
( void
) root
내에서 지정된 패턴과 일치하는 항목을 찾아 바꿉니다.
.replace
호출할 수 있는 방법에는 여러 가지가 있습니다. 위에서 설명한 방법으로 .find
호출할 수 있습니다.
.find(...).replace`replacement`
.find(...).replace(replacement: string | string | Node | Node[])
.find(...).replace(replacement: (match: Astx, parse: ParsePattern) => string)
.find(...).replace(replacement: (match: Astx, parse: ParsePattern) => Node | Node[])
대체 항목을 문자열로 제공하는 경우 유효한 표현식이나 문이어야 합니다. 이미 구문 분석했거나 구성한 AST 노드로 교체를 제공할 수 있습니다. 또는 각 일치 항목에 대해 호출되고 문자열이나 Node | Node[]
(두 번째 인수로 제공된 parse
태그 템플릿 문자열 함수를 사용하여 코드를 문자열로 구문 분석할 수 있습니다. 예를 들어, 인수가 없는 모든 함수 호출에서 함수 이름을 대문자로 바꿀 수 있습니다( foo(); bar()
다음과 같습니다). FOO(); BAR()
):
astx
.find`$fn()`
.replace(({ captures: { $fn } }) => `${$fn.name.toUpperCase()}()`)
.findImports(...)
( Astx
) 추가 지정자를 허용하고 유형 가져오기가 요청된 경우 동일한 이름의 값 가져오기와 일치하는 가져오기를 찾기 위한 .find()
의 편리한 버전입니다.
예를 들어 .findImports`import $a from 'a'`
import A, { b, c } from 'a'
또는 import { default as a } from 'a'
와 일치하여 $a
캡처하는 반면 .find`import $a from 'a'`
이러한 경우 중 어느 것과도 일치하지 않습니다.
패턴에는 import 문만 포함되어야 합니다.
.addImports(...)
( Astx
) .findImports()
와 비슷하지만 발견되지 않은 모든 가져오기를 추가합니다. 예를 들어 소스 코드가 다음과 같습니다.
import { foo , type bar as qux } from 'foo'
import 'g'
그리고 수술
const { $bar } = astx . addImports `
import type { bar as $bar } from 'foo'
import FooDefault from 'foo'
import * as g from 'g'
`
출력은 다음과 같습니다.
import FooDefault , { foo , type bar as qux } from 'foo'
import * as g from 'g'
$bar
는 식별자 qux
캡처합니다.
.removeImports(...)
( boolean
) .findImports()
와 동일한 형식의 import 문을 사용하지만 지정된 모든 지정자를 제거합니다.
.replaceImport(...).with(...)
( boolean
)단일 가져오기 지정자를 다른 지정자로 바꿉니다. 예를 들어 입력이 주어지면
import { Match , Route , Location } from 'react-router-dom'
import type { History } from 'history'
그리고 작동
astx . replaceImport `
import { Location } from 'react-router-dom'
` . with `
import type { Location } from 'history'
`
출력은 다음과 같습니다.
import { Match , Route } from 'react-router-dom'
import type { History , Location } from 'history'
찾기 및 바꾸기 패턴에는 모두 단일 지정자가 있는 단일 import 문이 포함되어야 합니다.
.remove()
( void
) 이 Astx
인스턴스의 .find()
또는 집중 캡처에서 일치 항목을 제거합니다.
.matched
( this | null
) 일치하는 항목이 하나 이상 있으면 이 Astx
인스턴스를 반환하고, 그렇지 않으면 null
반환합니다.
.find()
, .closest()
및 .destruct()
는 항상 Astx
인스턴스를 반환하므로 일치하는 항목이 없더라도 정의된 값만 원하는 경우 .find(...).matched
사용할 수 있습니다. 적어도 한 번은 일치했습니다.
.size()
( number
) 이 인스턴스를 반환한 .find()
또는 .closest()
호출에서 일치하는 항목 수를 반환합니다.
[name: `$${string}` | `$$${string}` | `$$$${string}`]
( Astx
) 주어진 name
가진 캡처에 초점을 맞춘 Astx
인스턴스를 가져옵니다.
예를 들어 다음을 수행할 수 있습니다.
for ( const { $v } of astx . find `process.env.$v` ) {
report ( $v . code )
}
.placeholder
( string | undefined
)이 인스턴스가 나타내는 자리 표시자의 이름입니다. 예를 들어:
const match = astx . find `function $fn($$params) { $$body }`
console . log ( match . placeholder ) // undefined
const { $fn , $$params } = match
console . log ( $fn . placeholder ) // $fn
console . log ( $$params . placeholder ) // $$params
.node
( Node
)첫 번째 일치 항목의 첫 번째 노드를 반환합니다. 일치하는 항목이 없으면 오류가 발생합니다.
.path
( NodePath
)첫 번째 일치 항목의 첫 번째 경로를 반환합니다. 일치하는 항목이 없으면 오류가 발생합니다.
.code
( string
)첫 번째 일치 항목의 첫 번째 노드에서 코드를 생성합니다. 일치하는 항목이 없으면 오류가 발생합니다.
.stringValue
( string
)포커스 캡처가 문자열 캡처인 경우 첫 번째 노드의 문자열 값을 반환합니다. 일치하는 항목이 없으면 오류가 발생합니다.
[Symbol.iterator]
( Iterator<Astx>
) 각 일치 항목을 반복하여 각 일치 항목에 대해 Astx
인스턴스를 반환합니다.
.matches
( Match[]
) 이 인스턴스를 반환한 .find()
또는 .closest()
호출에서 일치 항목을 가져옵니다.
.match
( Match
) 이 인스턴스를 반환한 .find()
또는 .closest()
호출에서 첫 번째 일치 항목을 가져옵니다.
일치하는 항목이 없으면 오류가 발생합니다.
.paths
( NodePath[]
) .find()
및 .closest()
가 검색할 경로를 반환합니다. 이 인스턴스가 .find()
또는 .closest()
에 의해 반환된 경우 검색 패턴과 일치하는 노드의 경로입니다.
.nodes
( Node[]
) .find()
및 .closest()
가 검색할 노드를 반환합니다. 이 인스턴스가 .find()
또는 .closest()
에 의해 반환된 경우 검색 패턴과 일치하는 노드입니다.
.some(predicate)
( boolean
) predicate
하나 이상의 일치 항목에 대해 true를 반환하지 않는 한 false
반환합니다.
iteratee
match: Astx, index: number, parent: Astx
로 호출되고 true
또는 false
반환하는 함수입니다.
.every(predicate)
( boolean
) true
반환합니다. unelss predicate
하나 이상의 일치 항목에 대해 false를 반환합니다.
iteratee
match: Astx, index: number, parent: Astx
로 호출되고 true
또는 false
반환하는 함수입니다.
.filter(iteratee)
( Astx
)일치 항목을 필터링합니다.
iteratee
match: Astx, index: number, parent: Astx
로 호출되고 true
또는 false
반환하는 함수입니다. iteratee
true
반환하는 일치 항목만 결과에 포함됩니다.
.map<T>(iteratee)
( T[]
)일치하는 항목을 매핑합니다.
iteratee
match: Astx, index: number, parent: Astx
로 호출되고 결과 배열에 포함할 값을 반환하는 함수입니다.
.at(index)
( Astx
) 주어진 index
에서 일치하는 항목을 선택합니다.
.withCaptures(...captures)
( Astx
) 이 인스턴스에 존재하는 캡처 외에 지정된 ...captures
캡처의 캡처를 포함하는 Astx
인스턴스를 반환합니다.
다음 종류의 인수를 전달할 수 있습니다.
Astx
인스턴스 - 인스턴스의 모든 캡처가 포함됩니다.Astx[placeholder]
인스턴스 - 지정된 placeholder
에 대한 캡처가 포함됩니다.{ $name: Astx[placeholder] }
- 지정된 placeholder
에 대한 캡처, $name
으로 이름 변경됨.Match
import { type Match } from 'astx'
.type
일치 유형: 'node'
또는 'nodes'
.
.path
일치하는 노드의 NodePath
. type
이 'nodes'
이면 paths[0]
이 됩니다.
.node
일치하는 Node
. type
이 'nodes'
이면 이는 nodes[0]
됩니다.
.paths
일치하는 노드의 NodePaths
.
.nodes
일치하는 Node
s.
.captures
일치 패턴의 자리 표시자에서 캡처된 Node
입니다. 예를 들어 패턴이 foo($bar)
인 경우 .captures.$bar
첫 번째 인수의 Node
됩니다.
.pathCaptures
일치 패턴의 자리 표시자에서 캡처된 NodePath
입니다. 예를 들어 패턴이 foo($bar)
인 경우 .pathCaptures.$bar
첫 번째 인수의 NodePath
됩니다.
.arrayCaptures
일치 패턴의 배열 자리 표시자에서 캡처된 Node[]
입니다. 예를 들어 패턴이 foo({ ...$bar })
인 경우 .arrayCaptures.$bar
객체 속성의 Node[]
가 됩니다.
.arrayPathCaptures
일치 패턴의 배열 자리 표시자에서 캡처된 NodePath[]
입니다. 예를 들어 패턴이 foo({ ...$bar })
인 경우 .pathArrayCaptures.$bar
객체 속성의 NodePath[]
가 됩니다.
.stringCaptures
일치 패턴의 문자열 자리 표시자에서 캡처된 문자열 값입니다. 예를 들어 패턴이 import foo from '$foo'
인 경우 stringCaptures.$foo
가져오기 경로가 됩니다.
jscodeshift
와 마찬가지로 .ts
또는 .js
파일에서 변환을 수행하는 코드를 넣을 수 있습니다( -t
CLI 옵션으로 다른 파일을 지정하지 않는 한 작업 디렉터리의 기본값은 astx.ts
또는 astx.js
입니다).
변환 파일 API는 jscodeshift
와 약간 다릅니다. 다음과 같은 내보내기가 가능합니다.
exports.find
(선택 사항)변환 중인 파일에서 찾을 패턴의 코드 문자열 또는 AST 노드입니다.
exports.where
(선택 사항) exports.find
의 캡처 자리 표시자에 대한 조건입니다. 자세한 내용은 FindOptions.where
( { [captureName: string]: (path: NodePath<any>) => boolean }
)를 참조하세요.
exports.replace
(선택사항) exports.find
일치 항목을 대체할 코드 문자열, AST 노드 또는 대체 함수입니다.
함수 인수는 .find().replace()
에 설명된 것과 동일합니다.
exports.astx
(선택 사항) Astx
API를 사용하여 임의 변환을 수행하는 함수입니다. 다음 속성을 가진 객체로 호출됩니다.
file
( string
) - 변환되는 파일의 경로source
( string
) - 변환되는 파일의 소스 코드astx
( Astx
) - Astx
API 인스턴스t
( AstTypes
) - 선택한 파서에 대한 ast-types
정의expression
- 코드를 표현식으로 구문 분석하기 위한 태그가 지정된 템플릿 리터럴statement
- 코드를 명령문으로 구문 분석하기 위한 태그가 지정된 템플릿 리터럴statements
- 코드를 명령문 배열로 구문 분석하기 위한 태그가 지정된 템플릿 리터럴report
( (message: unknown) => void
)mark
( (...matches: Astx[]) => void
) - 주어진 일치 항목을 vscode-astx 등의 일치 목록에 표시하도록 표시합니다. jscodeshift
와 달리 변환 함수는 비동기식일 수 있으며 변환된 코드를 반환할 필요는 없지만 string
반환할 수 있습니다. 파일을 건너뛰려면 null
반환할 수도 있습니다.
exports.onReport
(선택 사항) exports.astx
함수에서 report(x)
호출하면 onReport({ file, report: x })
사용하여 호출됩니다.
여러 작업자 스레드를 사용하는 경우 상위 프로세스에서 onReport
호출되므로 보고서 메시지는 직렬화 가능한 값이어야 합니다. 이를 통해 변환은 모든 작업자로부터 보고서를 수집할 수 있습니다(그리고 잠재적으로 finish
에서 해당 작업을 수행할 수 있습니다).
onReport
Promise
를 반환하면 대기하게 됩니다.
exports.finish
(선택사항)이는 모든 입력 파일에 대해 변환이 실행된 후에 호출됩니다.
여러 작업자 스레드를 사용하는 경우 상위 프로세스에서 finish
호출됩니다. onReport
와 finish
함께 사용하면 각 입력 파일에서 정보를 수집하고 마지막에 일종의 결합된 출력을 생성할 수 있습니다.
finish
Promise
를 반환하면 대기됩니다.
astx
다음 위치에서 구성을 지원합니다( cosmiconfig
통해):
astx
속성.astxrc
파일.astxrc.json
, .astxrc.yaml
, .astxrc.yml
, .astxrc.js
또는 .astxrc.cjs
파일astx.config.js
또는 astx.config.cjs
CommonJS 모듈코드베이스가 더 예쁘게 형식화되어 있는 경우 먼저 다음을 시도해 보는 것이 좋습니다.
{
"parser" : " babel/auto " ,
"parserOptions" : {
"preserveFormat" : " generatorHack "
}
}
(또는 CLI 옵션으로)
--parser babel/auto --parserOptions '{"preserveFormat": "generatorHack"}'
이것이 실패하면 parser: 'recast/babel/auto'
나 /auto
구문 분석기가 아닌 구문 분석기를 사용해 볼 수 있습니다.
귀하의 마일리지는 recast
에 따라 달라질 수 있습니다. JS와 TS의 새로운 구문 기능을 사용하여 신속하게 최신 상태를 유지할 수 없으며 잘못된 구문이 너무 많이 출력되는 것을 보았습니다.
이제부터 @babel/generator
또는 prettier
를 사용하여 수정되지 않은 노드에 대해 원본 소스를 그대로 사용하는 후크와 함께 수정된 AST를 인쇄하는 신뢰할 수 있는 솔루션을 개발할 것입니다.
parser
사용할 파서입니다. 옵션:
babel/auto
(기본값)babel
( babel/auto
보다 빠르지만 대신 기본 구문 분석 옵션을 사용하므로, parserOptions
구성해야 할 수도 있음)recast/babel
recast/babel/auto
babel/auto
babel 구성이 있는 경우 구문 분석 옵션을 자동으로 결정합니다. babel
고정된 구문 분석 옵션을 대신 사용하므로 babel/auto
보다 빠르지만, parserOptions
구성해야 할 수도 있습니다. recast/babel(/auto)
옵션은 형식을 유지하기 위해 recast
사용합니다. 일부 파일에서 잘못된 출력 구문을 recast
경우가 있으므로 주의해서 사용하세요.
parserOptions
파서에 전달할 옵션입니다. 현재 이것은 단지 @babel/parser
옵션과 다음 추가 옵션입니다:
preserveFormat
(적용 대상: babel
, babel/auto
) preserveFormat: 'generatorHack'
내부 @babel/generator
API를 하이재킹하여 변경되지 않은 모든 노드의 형식을 보존하기 위해 실험적인 해킹을 사용합니다.prettier
false
인 경우 변환된 소스 코드의 형식을 다시 지정하기 위해 prettier
사용하지 마세요. 기본값은 true
입니다.
Astx에는 변환을 수행하기 위한 CLI가 포함되어 있습니다. CLI는 주어진 파일을 처리한 다음 변경될 내용의 차이점을 인쇄하고 변경 사항을 작성할지 확인하라는 메시지를 표시합니다.
기본적으로 프로젝트에 설치된 버전과 프로젝트의 babel 구성(있는 경우)을 사용하여 babel로 구문 분석합니다. recast
사용하여 출력에서 형식을 유지하려는 경우 --parser recast/babel
전달할 수 있지만 출력에서 구문 오류가 가끔 표시됩니다.
jscodeshift
와 달리 prettier
프로젝트에 설치된 경우 변환된 코드의 형식이 prettier
로 지정됩니다.
Usage:
astx -f <code> [<files...>] [<directories...>]
Searches for the -f pattern in the given files and directories
and prints out the matches in context
astx -f <code> -r <code> [<files...>] [<directories...>]
Quick search and replace in the given files and directories
(make sure to quote code)
Example:
astx -f 'rmdir($path, $force)' -r 'rmdir($path, { force: $force })' src
astx -t <transformFile> [<files ...>] [<directories ...>]
Applies a transform file to the given files and directories
astx [<files ...>] [<directories ...>]
Applies the default transform file (astx.ts or astx.js in working directory)
to the given files and directories
Options:
--help Show help [boolean]
--version Show version number [boolean]
-t, --transform path to the transform file. Can be either a local path or
url. Defaults to ./astx.ts or ./astx.js if --find isn't
given
--parser parser to use (options: babel, babel/auto, recast/babel,
recast/babel/auto) [string]
--parserOptions options for parser [string]
-f, --find search pattern [string]
-r, --replace replace pattern [string]
-y, --yes don't ask for confirmation before writing changes
[boolean]
--gitignore ignore gitignored files [boolean] [default: true]
--workers number of worker threads to use [number]