การค้นหาโครงสร้างที่ทรงพลังเป็นพิเศษและแทนที่ 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
ด้วยมือจะแย่มาก คุณสามารถลองใช้การแทนที่ regex ได้ แต่มันยุ่งยากและไม่ยอมให้มีช่องว่างและการแบ่งบรรทัดอย่างดีเว้นแต่คุณจะทำงานหนักที่ regex คุณสามารถใช้ 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,
})
`
ในที่สุดฉันก็ได้เวอร์ชัน 2 เปิดตัวเมื่อเดือนธันวาคม 2565 หลังจากการทำงานหนักมากมาย ตอนนี้ฉันกำลังทำงานกับส่วนขยาย VSCode หลังจากนั้นฉันต้องการสร้างเว็บไซต์เอกสารที่แสดงวิธีใช้ astx
ได้ดียิ่งขึ้น
ขณะนี้ส่วนขยาย VSCode อยู่ในช่วงเบต้า แต่ลองดูสิ!
ในขณะที่ฉันกำลังคิดที่จะทำสิ่งนี้ ฉันค้นพบ grasp ซึ่งเป็นเครื่องมือที่คล้ายกันซึ่งเป็นแรงบันดาลใจให้กับไวยากรณ์ $
capture มีสาเหตุหลายประการที่ฉันตัดสินใจสร้าง astx
ต่อไป:
grasp -e 'setValue($k, $v, true)' -R 'setValueSilently({{k}}, {{v}})' file.js
jscodeshift
ที่ฉันสามารถใช้ใน JS สำหรับกรณีการใช้งานขั้นสูงที่อาจไม่สะดวกหรือเป็นไปไม่ได้ใน Grasp ดังนั้นปรัชญาของ astx
คือ:
วางโค้ดของคุณลงใน AST Explorer หากคุณต้องการเรียนรู้เกี่ยวกับโครงสร้างของ AST
รูปแบบการค้นหา Astx เป็นเพียงโค้ด JavaScript หรือ TypeScript ที่อาจมี wildcard ตัวยึดตำแหน่ง หรือโครงสร้างพิเศษอื่นๆ เช่น $Or(A, B)
โดยทั่วไปแล้ว บางส่วนของรูปแบบที่ไม่ใช่สัญลักษณ์แทนหรือโครงสร้างพิเศษจะต้องตรงกันทุกประการ
ตัวอย่างเช่น รูปแบบการค้นหา foo($a)
จะจับคู่การเรียกฟังก์ชัน foo
ด้วยอาร์กิวเมนต์เดียว อาร์กิวเมนต์สามารถทำอะไรก็ได้และถูก จับ เป็น $a
รูปแบบการแทนที่แทบจะเหมือนกันในการค้นหารูปแบบ ยกเว้นว่าตัวยึดตำแหน่งจะถูกแทนที่ด้วยสิ่งที่ ถูกบันทึก ลงในชื่อตัวยึดตำแหน่งด้วยรูปแบบการค้นหา และโครงสร้างการค้นหาแบบพิเศษ เช่น $Or(A, B)
จะไม่มีความหมายพิเศษในรูปแบบการแทนที่ (ในอนาคต อาจมีโครงสร้างการแทนที่พิเศษที่ทำการเปลี่ยนแปลงบางอย่างบนโหนดที่ถูกจับ)
ตัวอย่างเช่น รูปแบบการค้นหา foo($a)
ตรงกับ foo(1 + 2)
ดังนั้นรูปแบบการแทนที่ foo({ value: $a })
จะสร้างโค้ด foo({ value: 1 + 2 })
โดยทั่วไปแล้ว ตัวระบุที่ขึ้นต้นด้วย $
คือ ตัวยึดตำแหน่ง ที่ทำงานเหมือนกับไวด์การ์ด ตัวยึดตำแหน่งมีสามประเภท:
$<name>
ตรงกับโหนดเดียวใด ๆ ("ตัวยึดตำแหน่งโหนด")$$<name>
ตรงกับรายการโหนดที่ต่อเนื่องกัน ("ตัวยึดตำแหน่งอาร์เรย์")$$$<name>
: จับคู่พี่น้องคนอื่นๆ ทั้งหมด ("rest placeholder") <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
(หรือที่เรียกว่า object literal) จะจับคู่ ObjectExpression
ใดๆ ในโค้ดของคุณด้วยคุณสมบัติเดียวกันไม่ว่าจะเรียงลำดับอย่างไร จะไม่ตรงกันหากมีคุณสมบัติขาดหายไปหรือเพิ่มเติม ตัวอย่างเช่น { foo: 1, bar: $bar }
จะจับคู่ { foo: 1, bar: 2 }
หรือ { bar: 'hello', foo: 1 }
แต่ไม่ใช่ { foo: 1 }
หรือ { foo: 1, bar: 2, baz: 3 }
คุณสามารถจับคู่คุณสมบัติเพิ่มเติมได้โดยใช้ ...$$captureName
เช่น { foo: 1, ...$$rest }
จะจับคู่ { foo: 1 }
, { foo: 1, bar: 2 }
, { foo: 1, bar: 2, ...props }
ฯลฯ คุณสมบัติเพิ่มเติมจะถูกบันทึกไว้ใน match.arrayCaptures
/ match.arrayPathCaptures
และสามารถแพร่กระจายในนิพจน์การแทนที่ได้ ตัวอย่างเช่น astx.find`{ foo: 1, ...$$rest }`.replace`{ bar: 1, ...$$rest }`
จะเปลี่ยน { 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; }
จะจับคู่ function foo()
ที่มี throw new Error('test')
และคำสั่งก่อนและหลังคำสั่ง Throw นั้นจะถูกบันทึกเป็น $$before
และ $$after
ตามลำดับ
ในบางกรณี การจับคู่รายการจะถูกเรียงลำดับตามค่าเริ่มต้น และในบางกรณีก็จะไม่มีการเรียงลำดับ ตัวอย่างเช่น การจับคู่คุณสมบัติ ObjectExpression
จะไม่เรียงลำดับตามค่าเริ่มต้น ดังที่แสดงในตารางด้านล่าง การใช้ตัวยึดตำแหน่ง $$
หรือตัวยึดตำแหน่งพิเศษ $Ordered
จะบังคับให้มีการจับคู่แบบเรียงลำดับ การใช้ตัวยึดตำแหน่ง $$$
หรือตัวยึดตำแหน่ง $Unordered
แบบพิเศษจะบังคับให้จับคู่แบบไม่เรียงลำดับ
หากคุณใช้ตัวยึดตำแหน่งที่ขึ้นต้นด้วย $$$
จะถือเป็นการจับภาพ "พักผ่อน" และองค์ประกอบอื่นๆ ทั้งหมดของนิพจน์การจับคู่จะถูกจับคู่โดยไม่เรียงลำดับ ตัวอย่างเช่น import {a, b, $$$rest} from 'foo'
จะจับคู่ import {c, b, d, e, a} from 'foo'
โดยใส่ตัวระบุ c
, d
และ e
ลงใน $$$rest
ตัวยึดตำแหน่ง $$$rest
ตัวยึดตำแหน่งที่เหลือ ( $$$
) ต้องไม่เหมือนกับตัวยึดตำแหน่งรายการสั่งซื้อ ( $$
)
บางรายการที่มีเครื่องหมาย TODO อาจใช้งานได้จริง แต่ยังไม่ผ่านการทดสอบ
พิมพ์ | รองรับการจับคู่รายการ? | ไม่มีการเรียงลำดับตามค่าเริ่มต้น? | หมายเหตุ |
---|---|---|---|
ArrayExpression.elements | |||
ArrayPattern.elements | |||
BlockStatement.body | |||
CallExpression.arguments | |||
Class(Declaration/Expression).implements | |||
ClassBody.body | |||
ComprehensionExpression.blocks | สิ่งที่ต้องทำ | ||
DeclareClass.body | สิ่งที่ต้องทำ | ||
DeclareClass.implements | สิ่งที่ต้องทำ | ||
DeclareExportDeclaration.specifiers | สิ่งที่ต้องทำ | ||
DeclareInterface.body | สิ่งที่ต้องทำ | ||
DeclareInterface.extends | สิ่งที่ต้องทำ | ||
DoExpression.body | สิ่งที่ต้องทำ | ||
ExportNamedDeclaration.specifiers | |||
Function.decorators | สิ่งที่ต้องทำ | ||
Function.params | |||
FunctionTypeAnnotation/TSFunctionType.params | |||
GeneratorExpression.blocks | สิ่งที่ต้องทำ | ||
ImportDeclaration.specifiers | |||
(TS)InterfaceDeclaration.body | สิ่งที่ต้องทำ | ||
(TS)InterfaceDeclaration.extends | สิ่งที่ต้องทำ | ||
IntersectionTypeAnnotation/TSIntersectionType.types | |||
JSX(Element/Fragment).children | |||
JSX(Opening)Element.attributes | |||
MethodDefinition.decorators | สิ่งที่ต้องทำ | ||
NewExpression.arguments | |||
ObjectExpression.properties | |||
ObjectPattern.decorators | สิ่งที่ต้องทำ | ||
ObjectPattern.properties | |||
(ObjectTypeAnnotation/TSTypeLiteral).properties | ใช้ $a: $ เพื่อจับคู่หนึ่งคุณสมบัติ $$a: $ หรือ $$$a: $ เพื่อจับคู่หลายรายการ | ||
Program.body | |||
Property.decorators | สิ่งที่ต้องทำ | ||
SequenceExpression | |||
SwitchCase.consequent | |||
SwitchStatement.cases | สิ่งที่ต้องทำ | ||
TemplateLiteral.quasis/expressions | ❓ ไม่แน่ใจว่าฉันสามารถคิดไวยากรณ์ได้หรือไม่ | ||
TryStatement.guardedHandlers | สิ่งที่ต้องทำ | ||
TryStatement.handlers | สิ่งที่ต้องทำ | ||
TSFunctionType.parameters | |||
TSCallSignatureDeclaration.parameters | สิ่งที่ต้องทำ | ||
TSConstructorType.parameters | สิ่งที่ต้องทำ | ||
TSConstructSignatureDeclaration.parameters | สิ่งที่ต้องทำ | ||
TSDeclareFunction.params | สิ่งที่ต้องทำ | ||
TSDeclareMethod.params | สิ่งที่ต้องทำ | ||
EnumDeclaration.body/TSEnumDeclaration.members | สิ่งที่ต้องทำ | ||
TSIndexSignature.parameters | สิ่งที่ต้องทำ | ||
TSMethodSignature.parameters | สิ่งที่ต้องทำ | ||
TSModuleBlock.body | สิ่งที่ต้องทำ | ||
TSTypeLiteral.members | |||
TupleTypeAnnotation/TSTupleType.types | |||
(TS)TypeParameterDeclaration.params | |||
(TS)TypeParameterInstantiation.params | |||
UnionTypeAnnotation/TSUnionType.types | |||
VariableDeclaration.declarations | |||
WithStatement.body | ใครใช้กับงบ... |
สตริงที่เป็นเพียงตัวยึดตำแหน่งเช่น '$foo'
จะจับคู่สตริงใดๆ และบันทึกเนื้อหาลงใน match.stringCaptures.$foo
กฎการ Escape เดียวกันนี้ใช้กับตัวระบุ นอกจากนี้ยังใช้ได้กับตัวอักษรเทมเพลต เช่น `$foo`
และตัวอักษรเทมเพลตที่ติดแท็ก เช่น doSomething`$foo`
ซึ่งจะมีประโยชน์สำหรับการทำงานกับคำสั่งนำเข้า ตัวอย่างเช่น ดูการแปลงต้องมีคำสั่งในการนำเข้า
ความคิดเห็นที่ว่างเปล่า ( /**/
) ในรูปแบบจะ "แยก" โหนดสำหรับการจับคู่ ตัวอย่างเช่น รูปแบบ const x = { /**/ $key: $value }
จะจับคู่โหนด ObjectProperty
กับ $key: $value
โปรแกรมแยกวิเคราะห์จะไม่สามารถแยกวิเคราะห์ $key: $value
ด้วยตัวเองหรือรู้ว่าคุณหมายถึง ObjectProperty
ซึ่งตรงข้ามกับสิ่งที่แตกต่างเช่น x: number
ใน const x: number = 1
ดังนั้นการใช้ /**/
ช่วยให้คุณ เพื่อแก้ไขปัญหานี้ คุณสามารถใช้สิ่งนี้เพื่อจับคู่โหนดประเภทใดก็ได้ที่ไม่ใช่นิพจน์หรือคำสั่งที่ถูกต้อง ตัวอย่างเช่น 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)
จะจับคู่การประกาศ let
โดยที่ตัวเริ่มต้นตรงกับ $a + $b
และจับตัวเริ่มต้นเป็น $init
$Maybe<pattern>
จับคู่คำอธิบายประกอบประเภทที่กำหนดหรือไม่มีโหนดแทนที่ ตัวอย่างเช่น let $a: $Maybe<number>
จะจับคู่ let foo: number
และ let foo
(โดยไม่มีประเภทคำอธิบายประกอบ) แต่จะไม่ let foo: string``let foo: string
$Or<...>
จับคู่โหนดที่ตรงกับคำอธิบายประกอบประเภทที่กำหนดอย่างน้อยหนึ่งรายการ ตัวอย่างเช่น let $x: $Or<number[], string[]>
จะตรง let
การประกาศของประเภท number[]
หรือ string[]
$And<...>
จับคู่โหนดที่ตรงกับคำอธิบายประกอบประเภทที่กำหนดทั้งหมด สิ่งนี้มีประโยชน์เป็นส่วนใหญ่ในการจำกัดประเภทของโหนดที่สามารถบันทึกลงในตัวยึดตำแหน่งที่กำหนดให้แคบลง ตัวอย่างเช่น let $a: $And<$type, $elem[]>
จะจับคู่การประกาศ let
โดยที่คำอธิบายประกอบประเภทตรงกับ $elem[]
และบันทึกคำอธิบายประกอบประเภทเป็น $type
$Ordered
บังคับให้รูปแบบจับคู่โหนดพี่น้องในลำดับเดียวกัน
$Unordered
บังคับให้รูปแบบจับคู่โหนดพี่น้องในลำดับใดก็ได้
import { NodePath } from 'astx'
นี่เป็นอินเทอร์เฟซ NodePath
เดียวกันกับ ast-types
โดยมีการปรับปรุงคำจำกัดความประเภทวิธีการบางอย่าง astx
ใช้ ast-types
เพื่อสำรวจโค้ด โดยหวังว่าจะรองรับ parsers ต่างๆ ในอนาคต
import { Astx } from 'astx'
constructor(backend: Backend, paths: NodePath<any>[] | Match[], options?: { withCaptures?: Match[] })
backend
คือการใช้งาน parser/generator ที่ใช้งานอยู่
paths
ระบุ NodePath
s หรือ Match
es ที่คุณต้องการให้เมธอด Astx
ค้นหา/ดำเนินการ
.find(...)
( Astx
) ค้นหารายการที่ตรงกันสำหรับรูปแบบที่กำหนดภายในเส้นทางเริ่มต้นของอินสแตนซ์นี้ และส่งคืนอินสแตนซ์ Astx
ที่มีรายการที่ตรงกัน
หากคุณเรียก astx.find('foo($$args)')
บนอินสแตนซ์เริ่มต้นที่ส่งไปยังฟังก์ชันการแปลงของคุณ มันจะค้นหาการเรียก foo
ทั้งหมดภายในไฟล์ และส่งคืนรายการที่ตรงกันเหล่านั้นในอินสแตนซ์ Astx
ใหม่
วิธีการบนอินสแตนซ์ที่ส่งคืนจะทำงานบนเส้นทางที่ตรงกันเท่านั้น
ตัวอย่างเช่น หากคุณทำ astx.find('foo($$args)').find('$a + $b')
การ find
ครั้งที่สองจะค้นหาเฉพาะ $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;
โดยมีข้อความจำนวนเท่าใดก็ได้ระหว่างกัน
.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
replace ได้ คุณสามารถเรียก .find
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'`
จะไม่ตรงกับกรณีใดกรณีหนึ่งเหล่านี้
รูปแบบต้องมีเฉพาะคำสั่งนำเข้าเท่านั้น
.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()
แต่ลบตัวระบุที่กำหนดทั้งหมดออก
.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'
รูปแบบการค้นหาและแทนที่ต้องมีคำสั่งนำเข้าเดียวพร้อมตัวระบุเดียว
.remove()
( void
) ลบการจับคู่ออกจาก .find()
หรือการจับภาพที่โฟกัสใน Astx
ซ์ Astx นี้
.matched
( this | null
) ส่งคืนอินสแตนซ์ Astx
นี้หากมีการจับคู่อย่างน้อย 1 รายการ มิฉะนั้นจะส่งคืน null
เนื่องจาก .find()
, .closest()
และ .destruct()
ส่งคืนอินสแตนซ์ Astx
เสมอ แม้ว่าจะไม่มีรายการที่ตรงกัน คุณสามารถใช้ .find(...).matched
หากคุณต้องการเฉพาะค่าที่กำหนดเมื่อมี มีอย่างน้อยหนึ่งนัด
.size()
( number
) ส่งกลับจำนวนรายการที่ตรงกันจากการเรียก .find()
หรือ .closest()
ที่ส่งคืนอินสแตนซ์นี้
[name: `$${string}` | `$$${string}` | `$$$${string}`]
( Astx
) รับอินสแตนซ์ Astx
ที่เน้นไปที่การจับภาพด้วย name
ที่กำหนด
ตัวอย่างเช่น คุณสามารถทำสิ่งต่อไปนี้
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
) ส่งคืน false
เว้นแต่ predicate
จะส่งกลับค่าความจริงสำหรับการจับคู่อย่างน้อยหนึ่งรายการ
iteratee
เป็นฟังก์ชันที่จะถูกเรียกพร้อมกับ match: Astx, index: number, parent: Astx
และส่งคืนค่า true
หรือ false
.every(predicate)
( boolean
) ส่งกลับ predicate
unelss true
ส่งกลับค่าเท็จสำหรับการแข่งขันอย่างน้อยหนึ่งรายการ
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
) ส่งคืนอินสแตนซ์ Astx
ที่มีการจับจาก ...captures
กำหนด นอกเหนือจากการจับที่มีอยู่ในอินสแตนซ์นี้
คุณสามารถส่งผ่านอาร์กิวเมนต์ประเภทต่อไปนี้ได้:
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
ที่ตรงกัน
.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
(ค่าเริ่มต้นคือ astx.ts
หรือ astx.js
ในไดเร็กทอรีการทำงาน เว้นแต่คุณจะระบุไฟล์อื่นด้วยตัวเลือก -t
CLI)
API ไฟล์การแปลงแตกต่างจาก jscodeshift
เล็กน้อย คุณสามารถมีการส่งออกต่อไปนี้:
exports.find
(ไม่บังคับ)สตริงโค้ดหรือโหนด AST ของรูปแบบที่จะค้นหาในไฟล์ที่กำลังแปลง
exports.where
(ไม่บังคับ) โดยที่เงื่อนไขในการจับตัวยึดตำแหน่งใน exports.find
ดู FindOptions.where
( { [captureName: string]: (path: NodePath<any>) => boolean }
) สำหรับข้อมูลเพิ่มเติม
exports.replace
(ไม่บังคับ) สตริงโค้ด โหนด AST หรือฟังก์ชันแทนที่เพื่อแทนที่รายการที่ตรงกันของ exports.find
ด้วย
อาร์กิวเมนต์ของฟังก์ชันเหมือนกับที่อธิบายไว้ใน .find().replace()
exports.astx
(ไม่จำเป็น) ฟังก์ชันสำหรับดำเนินการแปลงตามอำเภอใจโดยใช้ Astx
API มันถูกเรียกด้วยวัตถุที่มีคุณสมบัติดังต่อไปนี้:
file
( string
) - เส้นทางไปยังไฟล์ที่กำลังแปลงsource
( string
) - ซอร์สโค้ดของไฟล์ที่กำลังแปลงastx
( Astx
) - อินสแตนซ์ Astx
APIt
( AstTypes
) - คำจำกัดความ ast-types
สำหรับตัวแยกวิเคราะห์ที่เลือกexpression
- แท็กเทมเพลตลิเทอรัลสำหรับการแยกวิเคราะห์โค้ดเป็นนิพจน์statement
- ติดแท็กตัวอักษรเทมเพลตสำหรับการแยกวิเคราะห์โค้ดเป็นคำสั่งstatements
- ติดแท็กตัวอักษรเทมเพลตสำหรับการแยกวิเคราะห์โค้ดเป็นอาร์เรย์ของคำสั่งreport
( (message: unknown) => void
)mark
( (...matches: Astx[]) => void
) - ทำเครื่องหมายการแข่งขันที่กำหนดให้แสดงในรายการการแข่งขันของ vscode-astx ฯลฯ ฟังก์ชันการแปลงของคุณสามารถเป็นแบบอะซิงก์ได้ ซึ่งต่างจาก jscodeshift
ตรงที่ไม่จำเป็นต้องส่งคืนโค้ดที่แปลงแล้ว แต่คุณสามารถส่งคืน string
ได้ คุณยังสามารถคืน null
เพื่อข้ามไฟล์ได้
exports.onReport
(ไม่บังคับ) หาก call report(x)
ของคุณจากฟังก์ชัน exports.astx
สิ่งนี้จะถูกเรียกด้วย onReport({ file, report: x })
หากคุณใช้เธรดผู้ปฏิบัติงานหลายเธรด onReport
จะถูกเรียกในกระบวนการหลัก ดังนั้นข้อความรายงานจะต้องเป็นค่าที่ทำให้เป็นอนุกรมได้ ซึ่งช่วยให้สามารถแปลงร่างเพื่อรวบรวมรายงานจากผู้ปฏิบัติงานทั้งหมด (และจากนั้นอาจดำเนินการบางอย่างกับพวกเขาใน finish
)
หาก onReport
ส่งคืน Promise
ก็จะถูกรอ
exports.finish
(ไม่จำเป็น)สิ่งนี้จะถูกเรียกหลังจากรันการแปลงไฟล์อินพุตทั้งหมดแล้ว
หากคุณใช้เธรดผู้ปฏิบัติงานหลายเธรด finish
จะถูกเรียกในกระบวนการพาเรนต์ คุณสามารถใช้ onReport
และ finish
พร้อมกันเพื่อรวบรวมข้อมูลจากไฟล์อินพุตแต่ละไฟล์ และสร้างเอาต์พุตรวมบางประเภทในตอนท้าย
หาก finish
การส่งคืน Promise
ก็จะรอ
astx
รองรับการกำหนดค่าในตำแหน่งต่อไปนี้ (ผ่าน cosmiconfig
):
astx
ใน package.json.astxrc
ในรูปแบบ JSON หรือ YAML.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'
หรือ non- /auto
parsers
ระยะทางของคุณอาจแตกต่างกันไปตาม recast
พวกเขาไม่สามารถอัปเดตฟีเจอร์ไวยากรณ์ใหม่ใน JS และ TS ได้เร็วพอ และฉันเห็นว่ามันแสดงไวยากรณ์ที่ไม่ถูกต้องหลายครั้งเกินไป
จากนี้ไป ฉันจะทำงานกับโซลูชันที่เชื่อถือได้โดยใช้ @babel/generator
หรือ prettier
เพื่อพิมพ์ AST ที่แก้ไข โดยมี hook เพื่อใช้คำต่อคำแหล่งที่มาดั้งเดิมสำหรับโหนดที่ไม่ได้แก้ไข
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
ตัวเลือกที่จะส่งผ่านไปยัง parser ตอนนี้เป็นเพียงตัวเลือก @babel/parser
บวกกับตัวเลือกเพิ่มเติมต่อไปนี้:
preserveFormat
(ใช้กับ: babel
, babel/auto
) preserveFormat: 'generatorHack'
ใช้แฮ็คทดลองเพื่อรักษารูปแบบของโหนดที่ไม่เปลี่ยนแปลงทั้งหมดโดยการแย่งชิง @babel/generator
API ภายในprettier
หากเป็น false
อย่าพยายามใช้ prettier
เพื่อฟอร์แมตซอร์สโค้ดที่แปลงใหม่ ค่าเริ่มต้นเป็น true
Astx มี CLI สำหรับการดำเนินการแปลง CLI จะประมวลผลไฟล์ที่กำหนด จากนั้นพิมพ์ส่วนต่างของสิ่งที่จะเปลี่ยนแปลง และแจ้งให้คุณยืนยันว่าคุณต้องการเขียนการเปลี่ยนแปลง
มันจะแยกวิเคราะห์ด้วย Babel ตามค่าเริ่มต้นโดยใช้เวอร์ชันที่ติดตั้งในโปรเจ็กต์ของคุณและการกำหนดค่า Babel ของโปรเจ็กต์ของคุณ หากมี คุณสามารถส่ง --parser recast/babel
ได้ หากคุณต้องการใช้ recast
เพื่อพยายามรักษาการจัดรูปแบบในเอาต์พุต แต่บางครั้งฉันเห็นข้อผิดพลาดทางไวยากรณ์ในเอาต์พุต
ต่างจาก 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]