codemodsquad / astx Goto Github PK
View Code? Open in Web Editor NEWSuper powerful structural search and replace for JavaScript and TypeScript to automate your refactoring
License: MIT License
Super powerful structural search and replace for JavaScript and TypeScript to automate your refactoring
License: MIT License
This testcase demonstrates the issue
import { TransformOptions } from '../../src'
import { astxTestcase } from '../astxTestcase'
astxTestcase({
file: __filename,
input: `
class Connection extends Model<ConnectionAttributes, ConnectionInitAttributes> {
declare Channels: Array<ConnectionChannel>;
static Channels: Association.HasMany<
Connection,
ConnectionChannelAttributes,
ConnectionChannelInitAttributes,
ConnectionChannel
> = null
}
`,
astx: ({ astx }: TransformOptions): void => {
for (const {
$$body,
} of astx.find`class $C extends Model<$$A> { $$body }`()) {
$$body.find`class X { /**/ static $a: Association.HasMany<$$p> = $Maybe($i)}`()
// this replace has no effect
.replace`class X { /**/ declare static $a: any; }`()
}
},
expected: `
class Connection extends Model<ConnectionAttributes, ConnectionInitAttributes> {
declare Channels: Array<ConnectionChannel>;
declare static Channels: any;
}
`,
})
Hello.
I think this tool is the best thing since sliced bread. However, it is a bit unconfrotable to have to install it globally and then run it from the command line.
I think an VSCode extension wrapping this library will be awesome.
I am not sure if it will be worth wrapping this entire library or just cherry pick some components. For example, things that are not going to be needed are:
So maybe it is possible to leverage the power of astx as a separate package?
Hello
Today I tried running the cli on a typescript project, and I'm getting type errors on some features that are not the standard. For example imports rather than requires, type imports, etc.
Is the cli supposed to find the ts-config.json/babelrc ? If not, is it possible to provide it? I took a look at the code and doesn't seem to be an option for this.
Regards
I'm using 2.0.0-beta.5
. If I have this file.js
module.exports = () => {
return global.rules.find(
(rule) =>
typeof rule.loader === 'string' && /babel-loader/.test(rule.loader)
)
}
And run this bash script
#!/usr/bin/env bash
read -r -d '' find <<'EOF'
module.exports = () => {
$$functionBody
}
EOF
read -r -d '' replace <<'EOF'
module.exports = {
fn() {
$$functionBody
}
}
EOF
astx -y -f "$find" -r "$replace" file.js
I get this error
==========================================
file.js
==========================================
TypeError: Cannot read property 'raw' of undefined
at genericPrintNoParens (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:677:47)
at genericPrint (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:123:30)
at print (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:77:15)
at /path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:49:41
at Object.printComments (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/comments.js:281:22)
at print (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:55:31)
at /path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:49:41
at FastPath.call (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/fast-path.js:125:18)
at genericPrintNoParens (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:200:29)
at genericPrint (/path/to/astx/lib/node_modules/astx/node_modules/recast/lib/printer.js:123:30)
0 files changed
0 files unchanged
1 file errored```
Unfortunately babel doesn't put leadingComments
on x
in this case...
Repro instructions:
cat <<EOF >auction_test.ts && npx astx --parser ts \
-f 'setFakeServerHandler(() => Promise.resolve($response));' \
-r 'const fakeServerHandler = jasmine.createSpy<FakeServerHandler>("fakeServerHandler"); fakeServerHandler.withArgs(jasmine.objectContaining<FakeRequest>({url: new URL(biddingLogicUrl1)})).and.resolveTo($response);' \
auction_test.ts
setFakeServerHandler(() =>
Promise.resolve({
headers: javaScriptHeaders,
body: [
"function generateBid() {",
" return { bid: 0.03, render: 'about:blank#1' };",
"}",
].join("\n"),
})
);
EOF
Full output:
npx: installed 291 in 16.171s
==========================================
auction_test.ts
==========================================
TypeError: Received an unexpected value [object Array]
at fromAST (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/node_modules/jscodeshift/src/core.js:70:9)
at core (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/node_modules/jscodeshift/src/core.js:45:5)
at /home/taymon/.npm/_npx/3832/lib/node_modules/astx/replace.js:196:44
at MatchArray.map (<anonymous>)
at generateReplacements (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/replace.js:183:18)
at replaceMatches (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/replace.js:205:22)
at MatchArray.replace (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/Astx.js:75:37)
at transformFn (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/runTransformOnFile.js:133:50)
at _callee2$ (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/runTransformOnFile.js:156:35)
at tryCatch (/home/taymon/.npm/_npx/3832/lib/node_modules/astx/node_modules/regenerator-runtime/runtime.js:63:40)
0 files changed
0 files unchanged
1 file errored
Hello again ๐
When you try to use any parser that is not the default, in my case flow, I get the following error from babel:
SyntaxError: This experimental syntax requires enabling one of the following parser plugin(s): 'flow, typescript' (16:7)
at Parser._raise (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:810:17)
at Parser.raiseWithData (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:803:17)
at Parser.expectOnePlugin (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:9982:18)
at Parser.isExportDefaultSpecifier (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:13785:16)
at Parser.maybeParseExportDefaultSpecifier (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:13686:14)
at Parser.parseExport (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:13639:29)
at Parser.parseStatementContent (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:12657:27)
at Parser.parseStatement (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:12551:17)
at Parser.parseBlockOrModuleBlockBody (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:13140:25)
at Parser.parseBlockBody (/Users/danielo/mega/trabajo/GIT/pento/Pento/client/node_modules/@babel/parser/lib/index.js:13131:10)
I'm using your CLI like this:
npx astx --parser=flow ./src/
How can I "activate" such plugins?
I'm not sure if this is a bug or if I'm just using it incorrectly, but if I have
test.js
/* eslint-disable no-console */
const testLib = require('test-lib')
const funcOne = (foo) => {
console.log('foo', foo)
return testLib(foo)
}
const funcTwo = (bar) => {
console.log('bar', bar)
return testLib(bar)
}
module.exports = (on, config) => {
on('event', () => {
funcOne(config.foo)
funcTwo(config.bar)
})
}
const json = {
"foo": 123,
"bar": true
}
astx.js
exports.find = `
$$header
module.exports = (on, config) => {
$$functionBody
}
const json = { $$json }
`
exports.replace = `
const { func } = require('some-module')
$$header
module.exports = func({
$$json,
events: {
setupEvents(on, config) {
$$functionBody
}
}
})
`
The output of astx -y test.js
is this (everything before module.exports
from the source file seems to be at the top of the output)
/* eslint-disable no-console */
const testLib = require('test-lib')
const funcOne = (foo) => {
console.log('foo', foo)
return testLib(foo)
}
const funcTwo = (bar) => {
console.log('bar', bar)
return testLib(bar)
}
const {
func
} = require("some-module");
/* eslint-disable no-console */
const testLib = require("test-lib");
const funcOne = foo => {
console.log("foo", foo);
return testLib(foo);
};
const funcTwo = bar => {
console.log("bar", bar);
return testLib(bar);
};
module.exports = func({
"foo": 123,
"bar": true,
events: {
setupEvents(on, config) {
on("event", () => {
funcOne(config.foo);
funcTwo(config.bar);
});
}
}
});
But I was expecting something more like this:
const {
func
} = require("some-module");
/* eslint-disable no-console */
const testLib = require("test-lib");
const funcOne = foo => {
console.log("foo", foo);
return testLib(foo);
};
const funcTwo = bar => {
console.log("bar", bar);
return testLib(bar);
};
module.exports = func({
"foo": 123,
"bar": true,
events: {
setupEvents(on, config) {
on("event", () => {
funcOne(config.foo);
funcTwo(config.bar);
});
}
}
});
I'm about to update a hundred files in a large repo, is there any way to bypass the confirmation prompt (via a -y
flag or similar) so that it just applies the changes to all files, that I can then review later, en masse?
$ npx [email protected] -f 'import { Button, ...$rest } from "blah"' **/*.tsx
SyntaxError: `import` can only be used in `import()` or `import.meta`. (1:1)
at instantiate (.../@babel/parser/lib/index.js:72:32)
at constructor (.../@babel/parser/lib/index.js:366:12)
at TypeScriptParserMixin.raise (.../@babel/parser/lib/index.js:3453:19)
at TypeScriptParserMixin.parseExprAtom (.../@babel/parser/lib/index.js:13065:16)
at TypeScriptParserMixin.parseExprAtom (.../@babel/parser/lib/index.js:8174:20)
at TypeScriptParserMixin.parseExprSubscripts (.../@babel/parser/lib/index.js:12785:23)
at TypeScriptParserMixin.parseUpdate (.../@babel/parser/lib/index.js:12764:21)
at TypeScriptParserMixin.parseMaybeUnary (.../@babel/parser/lib/index.js:12734:23)
at TypeScriptParserMixin.parseMaybeUnary (.../@babel/parser/lib/index.js:10933:20)
at TypeScriptParserMixin.parseMaybeUnaryOrPrivate (.../@babel/parser/lib/index.js:12525:61)
Hello.
Thanks for this great project.
I noticed that the compiled output of this package has a problem on it. Despite it is using the requireInterop helper, it still tries to access the default exported property, which is not required:
// getfieldNames.js
function addFieldNames(type) {
var fieldNames = _astTypes["default"].getFieldNames({
type: type
});
That throws an exception because prop default does not exist.
I tested on node 14.
Changing it to this makes it work:
// getfieldNames.js
function addFieldNames(type) {
var fieldNames = _astTypes.getFieldNames({
type: type
});
great work @jedwards1211 here.
which use cases cannot be handled by astx?
have you heard about semgrep? (they have data flow analysis, and built on top of tree-sitter)
also grit.io is building some awesome stuff. their pattern language reminded of your work.
at intuita, we are building a community of codemod champions like you. would love to have you there and exchange notes.
also if interested, we can chat about adding astx support to our codemod.studio (we have visual codemod builder and some LLM helpers to build codemods faster)
Right now astx
uses babel to parse and generate JS and TS. It would be nice to use typescript's own toolchain for parsing and generating. I'm not likely to have time to do this anytime soon, but maybe if enough people upvote this/offer donations...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.