Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transformations with unofficial TypeScript API #1

Merged
merged 4 commits into from
Jan 29, 2017
Merged
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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
"escodegen": "^1.8.1",
"esprima": "^3.1.3",
"flow-runtime": "^0.2.1",
"node-require-fallback": "^0.1.2",
"tcomb": "^3.2.16",
"ts-type-info": "^6.2.2",
"tspoon": "^1.0.254",
"typescript": "^2.1.5"
"typescript": "Microsoft/TypeScript#6c122bcf16c329a21da04d7b5256f20ecc0bbd1d"
}
}
82 changes: 39 additions & 43 deletions src/compiler/Compiler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import * as fs from 'fs';
import * as path from 'path';
import { TranspilerOutput, Visitor, transpile } from 'tspoon';
import { TsRuntimeOptions } from '../options';
import { CompilerResult } from './CompilerResult';
import { CompilerConfig } from './CompilerConfig';
import { FileResult } from './FileResult';
import * as DEFAULT_VISITORS from './visitors/default_visitors';
import * as ts from 'typescript/built/local/typescript';
import CompilerResult from './CompilerResult';
import CompilerConfig from './CompilerConfig';
import FileResult from './FileResult';
import { Transformer, DEFAULT_TRANSFORMERS } from './transformers';

export class Compiler {

Expand All @@ -16,8 +15,21 @@ export class Compiler {
public process(): Promise<CompilerResult> {
const toTransform: Array<Promise<FileResult>> = [];

const transformers: ts.Transformer[] = Object.keys(DEFAULT_TRANSFORMERS).map((key: string) => {
const transformer = new (DEFAULT_TRANSFORMERS as any)[key]();

const transform: ts.Transformer = (context) => (f) => {
for (const substitution of transformer.getSubstitutions()) {
context.enableSubstitution(substitution);
}
context.onSubstituteNode = transformer.process.bind(transformer);
return f;
};
return transform;
});

for (const file of this.config.files) {
toTransform.push(this.transformFile(file));
toTransform.push(this.transformFile(file, transformers));
}

return Promise.all(toTransform)
Expand All @@ -26,56 +38,40 @@ export class Compiler {
config: this.config,
fileResults: results,
};
})
.catch(err => {
console.error(err);
});
}

private transformFile(file: string): Promise<FileResult> {
private transformFile(filePath: string, transformers: ts.Transformer[]): Promise<FileResult> {
return new Promise((resolve, reject) => {
fs.readFile(file, this.config.options.encoding, (err, source) => {
fs.readFile(filePath, this.config.options.encoding, (err, source) => {
if (err) {
return reject(`Error reading file ${file}`);
return reject(`Error reading file ${filePath}`);
}

const visitors = Object.keys(DEFAULT_VISITORS).map((key: string) => {
return new (DEFAULT_VISITORS as any)[key]();
});
const fileName = path.basename(filePath);

const transpiler = transpile(source, {
compilerOptions: this.config.options.compilerOptions,
sourceFileName: path.basename(file),
visitors,
});
const f = ts.createSourceFile(
fileName,
source,
this.config.options.compilerOptions.target || ts.ScriptTarget.Latest,
true,
ts.ScriptKind.TS,
);

this.reportFile(transpiler);
const result = ts.emit(f, transformers).result;

resolve({
transpiler,
file,
fileName,
filePath,
result,
});
});
});
}

private reportFile(transpiler: TranspilerOutput): boolean {
if (transpiler.diags) {
for (const d of transpiler.diags) {
const position = d.file.getLineAndCharacterOfPosition(d.start);

const name = d.file.fileName;
const line = position.line + 1;
const character = position.character;
const text = d.messageText;

console.error(`-> ${name}:${line}:${character}:${text}`);
}
}

if (transpiler.halted) {
console.error('Transpiler halted. Exiting now.');
process.exit(1);
}

return !!transpiler.diags;
}

}

export default Compiler;
8 changes: 5 additions & 3 deletions src/compiler/CompilerConfig.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { TsRuntimeOptions } from '../options/TsRuntimeOptions';
import { FileResult } from './FileResult';
import Options from '../options/Options';
import FileResult from './FileResult';

export interface CompilerConfig {
files: string[];
options: TsRuntimeOptions;
options: Options;
}

export default CompilerConfig;
6 changes: 4 additions & 2 deletions src/compiler/CompilerResult.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { FileResult } from './FileResult';
import { CompilerConfig } from './CompilerConfig';
import FileResult from './FileResult';
import CompilerConfig from './CompilerConfig';

export interface CompilerResult {
config: CompilerConfig;
fileResults: FileResult[];
}

export default CompilerResult;
9 changes: 5 additions & 4 deletions src/compiler/FileResult.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TranspilerOutput } from 'tspoon';

export interface FileResult {
transpiler: TranspilerOutput;
file: string;
result: string;
filePath: string;
fileName: string
}

export default FileResult;
File renamed without changes.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export function typeCalls(type: ts.TypeNode): null | any {
return callExpression;
}
default:
throw new Error('Node Type not supported.');
{
const callExpression = utils.ast.getCallExpression('any');
return callExpression;
}
// throw new Error('Node Type not supported.');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import * as utils from '../utils';
export function variableAssignment(name: string, assignment: ts.Expression) {
const text = assignment.getText();
const callExpression = utils.ast.getCallExpression('assert', `_${name}Type`);
// const transpiled = ts.transpileModule(assignment.getText(), {});
// console.log(transpiled);
const toAssert = esprima.parse(assignment.getText()).body.pop();

callExpression.arguments.push((toAssert as any).expression);
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/_archive/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import * as astUtil from './utils/ast';
export const ast = astUtil;
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ export class VariableDeclarationVisitor implements Visitor {
}

public visit(node: ts.VariableDeclaration, context: VisitorContext, traverse: (...visitors: Visitor[]) => void): void {
console.log('-->', node.getText());
const typeDefinition = generate.typeDefinition(node.type, node.name.getText());

if (typeDefinition !== null) {
context.insertLine(node.parent.getStart(), utils.ast.toString(typeDefinition));
console.log(utils.ast.toString(typeDefinition));
}

if (node.initializer !== undefined) {
const assignment = generate.variableAssignment(node.name.getText(), node.initializer);
context.replace(node.getStart(), node.getEnd(), utils.ast.toString(assignment));
console.log(utils.ast.toString(assignment));
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/compiler/_archive/visitors/VariableStatementVisitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as ts from 'typescript';
import { Visitor, VisitorContext } from 'tspoon';
import { VariableDeclarationVisitor } from './VariableDeclarationVisitor';
import * as generate from '../generators';
import * as utils from '../utils';

export class VariableStatementVisitor implements Visitor {

public filter(node: ts.Node): boolean {
return node.kind === ts.SyntaxKind.VariableDeclaration;
}

public visit(node: ts.VariableDeclaration, context: VisitorContext, traverse: (...visitors: Visitor[]) => void): void {
traverse(new VariableDeclarationVisitor());
}

}
2 changes: 2 additions & 0 deletions src/compiler/_archive/visitors/default_visitors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { VariableDeclarationVisitor } from './VariableDeclarationVisitor';
// export { VariableStatementVisitor } from './VariableStatementVisitor';
32 changes: 32 additions & 0 deletions src/compiler/_archive/visitors_new/VariableDeclarationVisitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as ts from 'typescript/built/local/typescript';
import { Visitor } from './Visitor';
import * as generator from '../generator';

export class VariableDeclarationVisitor extends Visitor {

public filter(node: ts.Node): boolean {
return node.kind === ts.SyntaxKind.VariableDeclaration;
}

public visit(node: ts.VariableDeclaration): ts.Node {
if (!node.type) {
return node;
}

const nodeName = node.name.getText();
const def = generator.typeDefinition(node.type, nodeName);

const val = ts.factory.createCall(
ts.factory.createPropertyAccess(ts.factory.createIdentifier(`_${nodeName}Type`), 'assert'),
[],
[node.initializer],
);

const check = ts.factory.updateVariableDeclaration(node, node.name, node.type, val);

const list = ts.factory.createVariableDeclarationList([def, check]);

return list;
}

}
9 changes: 9 additions & 0 deletions src/compiler/_archive/visitors_new/Visitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as ts from 'typescript/built/local/typescript';

export abstract class Visitor {

protected abstract filter(node: ts.Node): boolean;

public abstract visit(node: ts.Node): ts.Node;

}
4 changes: 4 additions & 0 deletions src/compiler/transformers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { Transformer } from './transformers/Transformer';
export { VariableDeclarationTransformer } from './transformers/VariableDeclarationTransformer';
import * as DEFAULT_TRANSFORMERS from './transformers/default_transformers';
export { DEFAULT_TRANSFORMERS };
33 changes: 33 additions & 0 deletions src/compiler/transformers/Transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as ts from 'typescript/built/local/typescript';

export abstract class Transformer {

protected visited: ts.Node[] = [];

protected abstract substitution: ts.SyntaxKind | ts.SyntaxKind[];

public abstract onSubstituteNode(context: ts.EmitContext, node: ts.Node): ts.Node;

public getSubstitutions(): ts.SyntaxKind[] {
return !Array.isArray(this.substitution) ? [this.substitution] : this.substitution;
}

public getVisited() {
return this.visited;
}

public process(context: ts.EmitContext, node: ts.Node): ts.Node {
if (this.visited.indexOf(node) !== -1) {
return node;
}

this.visited.push(node);

// if (this.getSubstitutions().indexOf(node.kind) === -1) {
// return node;
// }

return this.onSubstituteNode(context, node);
}

}
58 changes: 58 additions & 0 deletions src/compiler/transformers/VariableDeclarationTransformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as ts from 'typescript/built/local/typescript';
import { Transformer } from './Transformer';
import { generator } from '../utils';

export class VariableDeclarationTransformer extends Transformer {

protected substitution = ts.SyntaxKind.VariableDeclarationList;

public onSubstituteNode(context: ts.EmitContext, node: ts.VariableDeclarationList): ts.Node {
const declarations: ts.VariableDeclaration[] = [];

for (const declaration of node.declarations) {
declarations.push(...this.processDeclaration(declaration));
}

return ts.factory.updateVariableDeclarationList(node, declarations);
}

private processDeclaration(node: ts.VariableDeclaration): ts.VariableDeclaration[] {
if (!node.type) {
return [node];
}

if (node.parent.flags === ts.NodeFlags.Const) {
return this.processConstDeclaration(node);
}

return this.processLetDeclaration(node);
}

private processLetDeclaration(node: ts.VariableDeclaration): ts.VariableDeclaration[] {
const nodeName = node.name.getText();
const typeDefinition = generator.createTypeDefinition(node.type, `_${nodeName}Type`);

if (!node.initializer) {
return [typeDefinition, node];
}

const initializer = generator.createTypeCall(`_${nodeName}Type`, 'assert', [node.initializer]);
const assignment = ts.factory.updateVariableDeclaration(node, node.name, node.type, initializer);

return [typeDefinition, assignment];
}

private processConstDeclaration(node: ts.VariableDeclaration): ts.VariableDeclaration[] {
const nodeName = node.name.getText();
const typeCalls = generator.createTypeCalls(node.type);

const initializer = ts.factory.createCall(
ts.factory.createPropertyAccess(typeCalls, 'assert'), [], [node.initializer],
);

const assignment = ts.factory.updateVariableDeclaration(node, node.name, node.type, initializer);

return [assignment];
}

}
1 change: 1 addition & 0 deletions src/compiler/transformers/default_transformers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { VariableDeclarationTransformer } from './VariableDeclarationTransformer';
4 changes: 2 additions & 2 deletions src/compiler/utils.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import * as astUtil from './utils/ast';
export const ast = astUtil;
import * as generator from './utils/generator';
export { generator };
Loading