Skip to content

Commit

Permalink
Implement qualifiedName visitor (#126)
Browse files Browse the repository at this point in the history
* Implemented qualifiedName visitor

Most of the tests are skipped because enum, class, namespace constructions not supported yet.

Also modified testHarness runner to be able to join to remotely running rewrite-remote test engine

* Implemented type arguments support for qualified names.
  • Loading branch information
arodionov authored Oct 20, 2024
1 parent a02b659 commit 2cd7147
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 9 deletions.
49 changes: 46 additions & 3 deletions openrewrite/src/javascript/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class JavaScriptParser extends Parser {
const result: SourceFile[] = [];
for (const filePath of program.getRootFileNames()) {
const sourceFile = program.getSourceFile(filePath)!;
const input = new ParserInput(filePath, null, false, () => Buffer.from(ts.sys.readFile(filePath)!));
const input = new ParserInput(filePath, null, false, () => Buffer.from(ts.sys.readFile(filePath)!));
try {
const parsed = new JavaScriptParserVisitor(this, sourceFile, typeChecker).visit(sourceFile) as SourceFile;
result.push(parsed);
Expand Down Expand Up @@ -532,7 +532,28 @@ export class JavaScriptParserVisitor {
}

visitQualifiedName(node: ts.QualifiedName) {
return this.visitUnknown(node);
const fieldAccess = new J.FieldAccess(
randomId(),
this.prefix(node),
Markers.EMPTY,
this.visit(node.left),
new JLeftPadded<J.Identifier>(this.suffix(node.left), this.convert<J.Identifier>(node.right), Markers.EMPTY),
this.mapType(node)
);

const parent = node.parent as ts.TypeReferenceNode;
if (parent.typeArguments) {
return new J.ParameterizedType(
randomId(),
this.prefix(parent),
Markers.EMPTY,
fieldAccess,
this.mapTypeArguments(parent.typeArguments),
this.mapType(parent)
)
} else {
return fieldAccess;
}
}

visitComputedPropertyName(node: ts.ComputedPropertyName) {
Expand Down Expand Up @@ -681,6 +702,10 @@ export class JavaScriptParserVisitor {

visitTypeReference(node: ts.TypeReferenceNode) {
if (node.typeArguments) {
// Temporary check for supported constructions with type arguments
if (ts.isQualifiedName(node.typeName)) {
return this.visit(node.typeName);
}
return this.visitUnknown(node);
}
return this.visit(node.typeName);
Expand Down Expand Up @@ -824,7 +849,7 @@ export class JavaScriptParserVisitor {
const statements: JRightPadded<J.Statement>[] = this.rightPaddedSeparatedList(
[...statementList.getChildren(this.sourceFile)],
ts.SyntaxKind.CommaToken,
(nodes, i) => i == nodes.length -2 && nodes[i + 1].kind == ts.SyntaxKind.CommaToken ? Markers.build([new TrailingComma(randomId(), this.prefix(nodes[i + 1]))]) : Markers.EMPTY
(nodes, i) => i == nodes.length - 2 && nodes[i + 1].kind == ts.SyntaxKind.CommaToken ? Markers.build([new TrailingComma(randomId(), this.prefix(nodes[i + 1]))]) : Markers.EMPTY
);

return new J.Block(
Expand Down Expand Up @@ -1922,6 +1947,24 @@ export class JavaScriptParserVisitor {
return this.mapToContainer(nodes, this.trailingComma(nodes));
}

private mapTypeArguments(nodes: readonly ts.Node[]): JContainer<J.Expression> {
if (nodes.length === 0) {
return JContainer.empty();
}

const args = nodes.map(node =>
this.rightPadded(
this.visit(node),
this.suffix(node),
Markers.EMPTY
))
return new JContainer(
this.prefix(nodes[0]),
args,
Markers.EMPTY
);
}

private trailingComma = (nodes: readonly ts.Node[]) => (ns: readonly ts.Node[], i: number) => {
const last = i === ns.length - 2;
return last ? Markers.build([new TrailingComma(randomId(), this.prefix(nodes[2], false))]) : Markers.EMPTY;
Expand Down
64 changes: 64 additions & 0 deletions openrewrite/test/javascript/parser/qualifiedName.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {connect, disconnect, rewriteRun, typeScript} from '../testHarness';

describe('empty mapping', () => {
beforeAll(() => connect());
afterAll(() => disconnect());

test('globalThis qualified name', () => {
rewriteRun(
//language=typescript
typeScript('const value: globalThis.Number = 1')
);
});

test('globalThis qualified name with generic', () => {
rewriteRun(
//language=typescript
typeScript('const value: globalThis.Promise< string > = null')
);
});

test('globalThis qualified name with comments', () => {
rewriteRun(
//language=typescript
typeScript('const value /*a123*/ : globalThis. globalThis . /*asda*/ globalThis.Promise<string> = null;')
);
});

test.skip('nested class qualified name', () => {
rewriteRun(
//language=typescript
typeScript(`
class OuterClass {
public static InnerClass = class extends Number { };
}
const a: typeof OuterClass.InnerClass.prototype = 1;
`)
);
});

test.skip('namespace qualified name', () => {
rewriteRun(
//language=typescript
typeScript(`
namespace TestNamespace {
export class Test {}
};
const value: TestNamespace.Test = null;
`)
);
});

test.skip('enum qualified name', () => {
rewriteRun(
//language=typescript
typeScript(`
enum Test {
A
};
const val: Test.A = Test.A;
`)
);
});
});
25 changes: 19 additions & 6 deletions openrewrite/test/javascript/testHarness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ export async function connect(): Promise<RemotingContext> {
return new Promise((resolve, reject) => {
const pathToJar = path.resolve(__dirname, '../../../rewrite-test-engine-remote/build/libs/rewrite-test-engine-remote-fat-jar.jar');
console.log(pathToJar);
const randomPort = getRandomInt(50000, 60000);
client = new net.Socket();
client.connect(65432, 'localhost');

getNextPort(randomPort).then(port => {
client.once('error', (err) => {
const randomPort = getRandomInt(50000, 60000);
getNextPort(randomPort).then(port => {
javaTestEngine = spawn('java', ['-jar', pathToJar, port.toString()]);
const errorfn = (data: string) => {
console.error(`stderr: ${data}`);
Expand All @@ -110,7 +113,15 @@ export async function connect(): Promise<RemotingContext> {

javaTestEngine.stdout.once('data', startfn);
javaTestEngine.stderr.on('data', errorfn);
});
});
client.once('connect', () => {
remoting = new RemotingContext();
remoting.connect(client);
PrinterFactory.current = new RemotePrinterFactory(remoting.client!);
resolve(remoting);
});

});
}

Expand All @@ -123,10 +134,12 @@ export async function disconnect(): Promise<void> {
remoting.close();
}

javaTestEngine.once('close', (code: string) => {
resolve()
});
javaTestEngine.kill("SIGKILL");
if (javaTestEngine) {
javaTestEngine.once('close', (code: string) => {
resolve()
});
javaTestEngine.kill("SIGKILL");
}
} else {
resolve();
}
Expand Down

0 comments on commit 2cd7147

Please sign in to comment.