Socket
Socket
Sign inDemoInstall

tspoon

Package Overview
Dependencies
Maintainers
9
Versions
410
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tspoon - npm Package Compare versions

Comparing version 1.0.61 to 1.0.62

10

dist/src/apply-visitor.js
"use strict";
var ts = require("typescript");
var ts = require('typescript');
var configuration_1 = require('./configuration');
var traverse_ast_1 = require('./traverse-ast');
var mutable_source_code_1 = require('./mutable-source-code');
var transpiler_context_1 = require("./transpiler-context");
var chainable_hosts_1 = require("./chainable-hosts");
var transformer_1 = require("./transformer");
var transpiler_context_1 = require('./transpiler-context');
var chainable_hosts_1 = require('./chainable-hosts');
var transformer_1 = require('./transformer');
function applyVisitor(source, visitor) {
var ast = ts.createSourceFile("test.ts", source, configuration_1.defaultCompilerOptions.target, true);
var ast = ts.createSourceFile('test.ts', source, configuration_1.defaultCompilerOptions.target, true);
return applyVisitorOnAst(ast, visitor);

@@ -12,0 +12,0 @@ }

@@ -8,5 +8,5 @@ "use strict";

var ts = require('typescript');
var transformer_1 = require("./transformer");
var hosts_base_1 = require("./hosts-base");
var configuration_1 = require("./configuration");
var transformer_1 = require('./transformer');
var hosts_base_1 = require('./hosts-base');
var configuration_1 = require('./configuration');
var normalizePath = ts['normalizePath'];

@@ -13,0 +13,0 @@ var getDirectoryPath = ts['getDirectoryPath'];

@@ -21,3 +21,2 @@ "use strict";

HostBase.prototype.writeFile = function (name, text, writeByteOrderMark) { };
///
HostBase.prototype.useCaseSensitiveFileNames = function () {

@@ -30,9 +29,9 @@ return false;

HostBase.prototype.getCurrentDirectory = function () {
return "";
return '';
};
HostBase.prototype.getNewLine = function () {
return "\n";
return '\n';
};
HostBase.prototype.getDefaultLibFileName = function (options) {
return "lib.d.ts";
return 'lib.d.ts';
};

@@ -39,0 +38,0 @@ HostBase.prototype.getCancellationToken = function () {

@@ -1,2 +0,1 @@

/// <reference path="../typings/main.d.ts" />
"use strict";

@@ -9,4 +8,4 @@ var __extends = (this && this.__extends) || function (d, b) {

var ts = require('typescript');
var hosts_base_1 = require("./hosts-base");
var configuration_1 = require("./configuration");
var hosts_base_1 = require('./hosts-base');
var configuration_1 = require('./configuration');
function fileExtensionIs(path, extension) {

@@ -13,0 +12,0 @@ var pathLen = path.length;

@@ -1,2 +0,2 @@

/// <reference path="../typings/main.d.ts" />
/// <reference path='../typings/main.d.ts' />
"use strict";

@@ -6,10 +6,10 @@ var transpile_1 = require('./transpile');

exports.validateAll = transpile_1.validateAll;
var apply_visitor_1 = require("./apply-visitor");
var apply_visitor_1 = require('./apply-visitor');
exports.applyVisitor = apply_visitor_1.applyVisitor;
exports.applyVisitorOnAst = apply_visitor_1.applyVisitorOnAst;
exports.applyVisitorOnHostedSource = apply_visitor_1.applyVisitorOnHostedSource;
var hosts_1 = require("./hosts");
var hosts_1 = require('./hosts');
exports.MultipleFilesHost = hosts_1.MultipleFilesHost;
var traverse_ast_1 = require("./traverse-ast");
var traverse_ast_1 = require('./traverse-ast');
exports.traverseAst = traverse_ast_1.traverseAst;
//# sourceMappingURL=index.js.map

@@ -1,2 +0,1 @@

/// <reference path="../typings/main.d.ts" />
"use strict";

@@ -8,4 +7,4 @@ var __extends = (this && this.__extends) || function (d, b) {

};
var ts = require('typescript');
var source_map_1 = require('source-map');
var ts = require('typescript');
var MagicString = require('magic-string');

@@ -12,0 +11,0 @@ var MappedAction = (function () {

"use strict";
var transpiler_context_1 = require("./transpiler-context");
var transpiler_context_1 = require('./transpiler-context');
var traverse_ast_1 = require('./traverse-ast');
var mutable_source_code_1 = require("./mutable-source-code");
var mutable_source_code_1 = require('./mutable-source-code');
var VisitorBasedTransformer = (function () {

@@ -6,0 +6,0 @@ function VisitorBasedTransformer(visitors, languageServiceProvider) {

@@ -1,13 +0,12 @@

/// <reference path="../typings/main.d.ts" />
"use strict";
var ts = require('typescript');
var hosts_1 = require('./hosts');
var traverse_ast_1 = require('./traverse-ast');
var mutable_source_code_1 = require('./mutable-source-code');
var ts = require('typescript');
var transpiler_context_1 = require("./transpiler-context");
var configuration_1 = require("./configuration");
var chainable_hosts_1 = require("./chainable-hosts");
var chainable_hosts_2 = require("./chainable-hosts");
var hosts_base_1 = require("./hosts-base");
var chainable_hosts_3 = require("./chainable-hosts");
var transpiler_context_1 = require('./transpiler-context');
var configuration_1 = require('./configuration');
var chainable_hosts_1 = require('./chainable-hosts');
var chainable_hosts_2 = require('./chainable-hosts');
var hosts_base_1 = require('./hosts-base');
var chainable_hosts_3 = require('./chainable-hosts');
function getParserErrors(sourceFile) {

@@ -14,0 +13,0 @@ // We're accessing here an internal property. It would be more legit to access it through

@@ -1,7 +0,6 @@

/// <reference path="../typings/main.d.ts" />
"use strict";
var mutable_source_code_1 = require('./mutable-source-code');
var mutable_source_code_2 = require("./mutable-source-code");
var mutable_source_code_3 = require("./mutable-source-code");
var mutable_source_code_4 = require("./mutable-source-code");
var mutable_source_code_2 = require('./mutable-source-code');
var mutable_source_code_3 = require('./mutable-source-code');
var mutable_source_code_4 = require('./mutable-source-code');
var TranspilerContext = (function () {

@@ -8,0 +7,0 @@ function TranspilerContext(_fileName, langServiceProvider) {

@@ -1,11 +0,10 @@

import * as ts from 'typescript';
import {RawSourceMap, Visitor} from "./index";
import {RawSourceMap, Visitor} from './index';
export interface HostBase extends ts.CompilerHost {}
export class HostBase implements HostBase {}
export interface HostBase extends ts.CompilerHost { }
export class HostBase implements HostBase { }
export class ChainableHost extends HostBase {
setSource(source: ts.CompilerHost): void;
setSource(source: ts.CompilerHost): void;
}

@@ -16,30 +15,29 @@

export class AstCacheHost extends ChainableHost {
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile;
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile;
}
export class TransformationHost extends ChainableHost {
constructor(visitors: Visitor[], languageServiceProvider?: () => ts.LanguageService);
getSourceMap(fileName: string): RawSourceMap;
translateDiagnostic(diagnostic: ts.Diagnostic): ts.Diagnostic;
constructor(visitors: Visitor[], languageServiceProvider?: () => ts.LanguageService);
getSourceMap(fileName: string): RawSourceMap;
translateDiagnostic(diagnostic: ts.Diagnostic): ts.Diagnostic;
}
export interface SemanticHost extends ts.LanguageServiceHost, ts.CompilerHost, ts.DocumentRegistry {
getCancellationToken(): ts.CancellationToken;
getNewLine(): string;
useCaseSensitiveFileNames();
getCancellationToken(): ts.CancellationToken;
getNewLine(): string;
useCaseSensitiveFileNames();
}
export class SemanticHost extends ChainableHost {
constructor(files: string[], compilerOptions?: ts.CompilerOptions);
constructor(files: string[], compilerOptions?: ts.CompilerOptions);
}
export class MultipleFilesHost extends HostBase {
constructor(resolutionHosts: ts.ModuleResolutionHost[], compilerOptions?: ts.CompilerOptions)
getSyntacticErrors(): ts.Diagnostic[];
constructor(resolutionHosts: ts.ModuleResolutionHost[], compilerOptions?: ts.CompilerOptions)
getSyntacticErrors(): ts.Diagnostic[];
}
export class SingleFileHost extends HostBase {
constructor(ast: ts.SourceFile);
public output: string;
public sourceMap: RawSourceMap;
constructor(ast: ts.SourceFile);
public output: string;
public sourceMap: RawSourceMap;
}

@@ -1,20 +0,20 @@

import * as ts from "typescript";
import * as ts from 'typescript';
interface StartOfSourceMap {
file?: string;
sourceRoot?: string;
file?: string;
sourceRoot?: string;
}
export interface RawSourceMap extends StartOfSourceMap {
version: string;
sources: Array<string>;
names: Array<string>;
sourcesContent?: string;
mappings: string;
version: string;
sources: Array<string>;
names: Array<string>;
sourcesContent?: string;
mappings: string;
}
export interface Replacement {
start: number;
end: number;
str: string;
start: number;
end: number;
str: string;
}

@@ -36,10 +36,10 @@

export interface VisitorContext {
fileName: string;
halted: boolean;
insertLine(position: number, str: string): void;
replace(start: number, end: number, str: string): void;
fastAppend(str: string): void;
fastRewrite(start: number, str: string): void;
reportDiag(node: ts.Node, category: ts.DiagnosticCategory, message: string, halt?: boolean): void;
getLanguageService(): ts.LanguageService;
fileName: string;
halted: boolean;
insertLine(position: number, str: string): void;
replace(start: number, end: number, str: string): void;
fastAppend(str: string): void;
fastRewrite(start: number, str: string): void;
reportDiag(node: ts.Node, category: ts.DiagnosticCategory, message: string, halt?: boolean): void;
getLanguageService(): ts.LanguageService;
}

@@ -49,3 +49,3 @@

filter(node: ts.Node): boolean;
visit(node: ts.Node, context: VisitorContext, traverse: (...visitors: Visitor[])=> void): void;
visit(node: ts.Node, context: VisitorContext, traverse: (...visitors: Visitor[]) => void): void;
}

@@ -56,5 +56,5 @@

export interface ApplyVisitorResult {
file: ts.SourceFile,
code: string;
diags: ts.Diagnostic[];
file: ts.SourceFile,
code: string;
diags: ts.Diagnostic[];
}

@@ -69,5 +69,5 @@

export interface ValidatorConfig {
resolutionHosts?: ts.ModuleResolutionHost[];
visitors?: Visitor[];
mutators?: Visitor[];
resolutionHosts?: ts.ModuleResolutionHost[];
visitors?: Visitor[];
mutators?: Visitor[];
}

@@ -74,0 +74,0 @@

{
"private": false,
"name": "tspoon",
"version": "1.0.61",
"version": "1.0.62",
"description": "see README.md",

@@ -12,3 +12,3 @@ "main": "./dist/src/index.js",

"scripts": {
"clean": "rm -rf dist && mkdir dist",
"clean": "rimraf dist && mkdir dist",
"pretest": "npm run build",

@@ -54,4 +54,4 @@ "test": "npm run test:node",

"raw-loader": "0.5.1",
"rimraf": "2.5.2",
"source-map-support": "0.4.0",
"tsd": "0.6.5",
"typings": "0.7.12",

@@ -62,3 +62,3 @@ "webpack": "1.12.14",

"dependencies": {
"lodash": "4.7.0",
"lodash": "4.8.2",
"magic-string": "0.10.2",

@@ -65,0 +65,0 @@ "source-map": "0.5.3",

@@ -1,11 +0,10 @@

import * as ts from "typescript";
import * as ts from 'typescript';
import {defaultCompilerOptions} from './configuration';
import {traverseAst} from './traverse-ast';
import {Visitor} from './visitor';
import {Action, MutableSourceCode} from './mutable-source-code';
import {TranspilerContext} from './transpiler-context';
import {SemanticHost} from './chainable-hosts';
import {VisitorBasedTransformer, CodeTransformer} from './transformer';
import { defaultCompilerOptions } from './configuration';
import { traverseAst } from './traverse-ast';
import { Visitor } from "./visitor";
import { Action, MutableSourceCode } from './mutable-source-code';
import { TranspilerContext } from "./transpiler-context";
import {SemanticHost} from "./chainable-hosts";
import {VisitorBasedTransformer, CodeTransformer} from "./transformer";
export interface ApplyVisitorResult {

@@ -20,3 +19,3 @@ file: ts.SourceFile,

const ast = ts.createSourceFile("test.ts", source, defaultCompilerOptions.target, true);
const ast = ts.createSourceFile('test.ts', source, defaultCompilerOptions.target, true);
return applyVisitorOnAst(ast, visitor);

@@ -26,14 +25,13 @@ }

export function applyVisitorOnHostedSource(file: string, visitors: Visitor[], host: ts.CompilerHost): string {
const langService = host instanceof SemanticHost ? ts.createLanguageService(host, host) : null;
const transformer: CodeTransformer = new VisitorBasedTransformer(visitors, () => langService);
const ast: ts.SourceFile = host.getSourceFile(file, defaultCompilerOptions.target);
if(ast) {
const mutableSourceCode: MutableSourceCode = transformer.transform(ast);
return mutableSourceCode.code;
} else {
return null;
}
const langService = host instanceof SemanticHost ? ts.createLanguageService(host, host) : null;
const transformer: CodeTransformer = new VisitorBasedTransformer(visitors, () => langService);
const ast: ts.SourceFile = host.getSourceFile(file, defaultCompilerOptions.target);
if (ast) {
const mutableSourceCode: MutableSourceCode = transformer.transform(ast);
return mutableSourceCode.code;
} else {
return null;
}
}
export function applyVisitorOnAst(ast: ts.SourceFile, visitor: Visitor): ApplyVisitorResult {

@@ -40,0 +38,0 @@

@@ -1,2 +0,1 @@

export default function binarySearch(array: number[], value: number): number {

@@ -3,0 +2,0 @@ let low = 0;

@@ -1,10 +0,10 @@

import {chainHosts} from "./hosts-base";
import * as ts from 'typescript';
import {CodeTransformer, VisitorBasedTransformer} from "./transformer";
import {ChainableHost} from "./hosts-base";
import {MutableSourceCode} from "./mutable-source-code";
import {chainHosts} from './hosts-base';
import {CodeTransformer, VisitorBasedTransformer} from './transformer';
import {ChainableHost} from './hosts-base';
import {MutableSourceCode} from './mutable-source-code';
import RawSourceMap = SourceMap.RawSourceMap;
import {defaultCompilerOptions} from "./configuration";
import {MultipleFilesHost} from "./hosts";
import {Visitor} from "./visitor";
import {defaultCompilerOptions} from './configuration';
import {MultipleFilesHost} from './hosts';
import {Visitor} from './visitor';

@@ -16,14 +16,14 @@ const normalizePath: { (path: string): string } = ts['normalizePath'];

export class AstCacheHost extends ChainableHost {
private cache: { [fileName: string]: ts.SourceFile } = {};
private cache: { [fileName: string]: ts.SourceFile } = {};
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
const cachedAst: ts.SourceFile = this.cache[fileName];
if(!cachedAst) {
const ast = this.source.getSourceFile(fileName, languageVersion, onError);
this.cache[fileName] = ast;
return ast;
} else {
return cachedAst;
}
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
const cachedAst: ts.SourceFile = this.cache[fileName];
if (!cachedAst) {
const ast = this.source.getSourceFile(fileName, languageVersion, onError);
this.cache[fileName] = ast;
return ast;
} else {
return cachedAst;
}
}

@@ -33,101 +33,101 @@ }

export class TransformationHost extends ChainableHost {
private transformations: { [fileName: string]: MutableSourceCode } = {};
private transformer: CodeTransformer;
private transformations: { [fileName: string]: MutableSourceCode } = {};
private transformer: CodeTransformer;
constructor(visitors: Visitor[], languageServiceProvider: () => ts.LanguageService = () => null) {
super();
this.transformer = new VisitorBasedTransformer(visitors, languageServiceProvider);
}
constructor(visitors: Visitor[], languageServiceProvider: () => ts.LanguageService = () => null) {
super();
this.transformer = new VisitorBasedTransformer(visitors, languageServiceProvider);
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
const ast: ts.SourceFile = super.getSourceFile(fileName, languageVersion, onError);
if(ast) {
const transformation = this.transformer.transform(ast);
this.transformations[ast.fileName] = transformation;
return transformation.ast;
} else {
return null;
}
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
const ast: ts.SourceFile = super.getSourceFile(fileName, languageVersion, onError);
if (ast) {
const transformation = this.transformer.transform(ast);
this.transformations[ast.fileName] = transformation;
return transformation.ast;
} else {
return null;
}
}
getSourceMap(fileName: string): RawSourceMap {
const transformation: MutableSourceCode = this.transformations[fileName];
if(transformation) {
return transformation.sourceMap;
} else {
return null;
}
}
getSourceMap(fileName: string): RawSourceMap {
const transformation: MutableSourceCode = this.transformations[fileName];
if (transformation) {
return transformation.sourceMap;
} else {
return null;
}
}
translateDiagnostic(diagnostic: ts.Diagnostic): ts.Diagnostic {
const transformation = this.transformations[diagnostic.file.fileName];
return transformation ? transformation.translateDiagnostic(diagnostic) : diagnostic;
}
translateDiagnostic(diagnostic: ts.Diagnostic): ts.Diagnostic {
const transformation = this.transformations[diagnostic.file.fileName];
return transformation ? transformation.translateDiagnostic(diagnostic) : diagnostic;
}
}
export class SemanticHost extends ChainableHost implements ts.LanguageServiceHost, ts.CompilerHost, ts.DocumentRegistry {
constructor(
private files: string[],
private compilerOptions: ts.CompilerOptions = defaultCompilerOptions
) {
super();
}
constructor(
private files: string[],
private compilerOptions: ts.CompilerOptions = defaultCompilerOptions
) {
super();
}
getProjectVersion():string {
return null;
}
getProjectVersion(): string {
return null;
}
getScriptFileNames():string[]{
return this.files.slice();
}
getScriptFileNames(): string[] {
return this.files.slice();
}
getScriptVersion(fileName:string):string{
return null;
}
getScriptVersion(fileName: string): string {
return null;
}
getScriptSnapshot(fileName:string):ts.IScriptSnapshot{
return ts.ScriptSnapshot.fromString(this.readFile(fileName));
}
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
return ts.ScriptSnapshot.fromString(this.readFile(fileName));
}
getLocalizedDiagnosticMessages():any{
return null;
}
getLocalizedDiagnosticMessages(): any {
return null;
}
getCompilationSettings():ts.CompilerOptions{
return this.compilerOptions;
}
getCompilationSettings(): ts.CompilerOptions {
return this.compilerOptions;
}
log(s:string):void {
}
log(s: string): void {
}
trace(s:string):void {
}
trace(s: string): void {
}
error(s:string):void {
}
error(s: string): void {
}
resolveModuleNames(moduleNames:string[], containingFile:string):ts.ResolvedModule[]{
const containingDir: string = getDirectoryPath(containingFile);
return moduleNames.map((moduleName: string) => {
const resolvedBase: string = normalizePath(combinePaths(containingDir, moduleName));
return {
resolvedFileName: this.tryResolveFileName(resolvedBase + '.tsx') || this.tryResolveFileName(resolvedBase + '.ts'),
isExternalLibraryImport: false
}
});
}
resolveModuleNames(moduleNames: string[], containingFile: string): ts.ResolvedModule[] {
const containingDir: string = getDirectoryPath(containingFile);
return moduleNames.map((moduleName: string) => {
const resolvedBase: string = normalizePath(combinePaths(containingDir, moduleName));
return {
resolvedFileName: this.tryResolveFileName(resolvedBase + '.tsx') || this.tryResolveFileName(resolvedBase + '.ts'),
isExternalLibraryImport: false
}
});
}
private tryResolveFileName(candidate: string): string {
return this.source.fileExists(candidate) ? candidate : null;
}
private tryResolveFileName(candidate: string): string {
return this.source.fileExists(candidate) ? candidate : null;
}
directoryExists(directoryName:string):boolean{
return null;
}
directoryExists(directoryName: string): boolean {
return null;
}
acquireDocument(fileName: string, compilationSettings: ts.CompilerOptions, scriptSnapshot: ts.IScriptSnapshot, version: string): ts.SourceFile {
return this.source.getSourceFile(fileName, compilationSettings.target);
}
acquireDocument(fileName: string, compilationSettings: ts.CompilerOptions, scriptSnapshot: ts.IScriptSnapshot, version: string): ts.SourceFile {
return this.source.getSourceFile(fileName, compilationSettings.target);
}
/**

@@ -145,5 +145,5 @@ * Request an updated version of an already existing SourceFile with a given fileName

*/
updateDocument(fileName: string, compilationSettings: ts.CompilerOptions, scriptSnapshot: ts.IScriptSnapshot, version: string): ts.SourceFile {
return this.source.getSourceFile(fileName, compilationSettings.target);
}
updateDocument(fileName: string, compilationSettings: ts.CompilerOptions, scriptSnapshot: ts.IScriptSnapshot, version: string): ts.SourceFile {
return this.source.getSourceFile(fileName, compilationSettings.target);
}
/**

@@ -158,9 +158,8 @@ * Informs the DocumentRegistry that a file is not needed any longer.

*/
releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void {
releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void {
}
reportStats(): string {
return '';
}
}
reportStats(): string {
return '';
}
}
import * as ts from 'typescript';
import { Visitor } from "./visitor";
import {Visitor} from './visitor';
export const defaultCompilerOptions: ts.CompilerOptions = {
module: ts.ModuleKind.CommonJS,
jsx: ts.JsxEmit.React,
target: ts.ScriptTarget.ES5,
experimentalDecorators: true,
noEmitHelpers: true,
sourceMap: true,
preserveConstEnums : true,
inlineSources : true,
emitDecoratorMetadata: false
module: ts.ModuleKind.CommonJS,
jsx: ts.JsxEmit.React,
target: ts.ScriptTarget.ES5,
experimentalDecorators: true,
noEmitHelpers: true,
sourceMap: true,
preserveConstEnums: true,
inlineSources: true,
emitDecoratorMetadata: false
};

@@ -5,44 +5,41 @@ import * as ts from 'typescript';

// Most likely to be overridded
// Most likely to be overridded
fileExists(fileName: string): boolean {
return false;
}
fileExists(fileName: string): boolean {
return false;
}
readFile(fileName: string): string {
return null;
}
readFile(fileName: string): string {
return null;
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
return null;
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
return null;
}
writeFile(name:string, text:string, writeByteOrderMark: boolean) {}
writeFile(name: string, text: string, writeByteOrderMark: boolean) { }
useCaseSensitiveFileNames() {
return false;
}
///
getCanonicalFileName(fileName: string) {
return fileName;
}
useCaseSensitiveFileNames() {
return false;
}
getCurrentDirectory(): string {
return '';
}
getCanonicalFileName(fileName: string) {
return fileName;
}
getNewLine(): string {
return '\n';
}
getCurrentDirectory(): string {
return "";
}
getDefaultLibFileName(options: ts.CompilerOptions): string {
return 'lib.d.ts';
}
getNewLine(): string {
return "\n";
}
getDefaultLibFileName(options:ts.CompilerOptions): string {
return "lib.d.ts";
}
getCancellationToken(): ts.CancellationToken {
return null;
}
getCancellationToken(): ts.CancellationToken {
return null;
}
}

@@ -52,34 +49,34 @@

export class ChainableHost extends HostBase {
protected source: ts.CompilerHost = null;
protected source: ts.CompilerHost = null;
setSource(source: ts.CompilerHost): void {
if(this.source === null) {
this.source = source;
} else {
throw new Error(`A chainable host can be connected to a source only once. It looks like you're trying to include the same instance in multiple chains.`);
}
}
setSource(source: ts.CompilerHost): void {
if (this.source === null) {
this.source = source;
} else {
throw new Error(`A chainable host can be connected to a source only once. It looks like you're trying to include the same instance in multiple chains.`);
}
}
fileExists(fileName: string): boolean {
return this.source.fileExists(fileName);
}
fileExists(fileName: string): boolean {
return this.source.fileExists(fileName);
}
readFile(fileName: string): string {
return this.source.readFile(fileName);
}
readFile(fileName: string): string {
return this.source.readFile(fileName);
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
return this.source.getSourceFile(fileName, languageVersion, onError);
}
getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void): ts.SourceFile {
return this.source.getSourceFile(fileName, languageVersion, onError);
}
writeFile(name:string, text:string, writeByteOrderMark: boolean) {
this.source.writeFile(name, text, writeByteOrderMark);
}
writeFile(name: string, text: string, writeByteOrderMark: boolean) {
this.source.writeFile(name, text, writeByteOrderMark);
}
}
export function chainHosts(host0: ts.CompilerHost, ...chainableHosts: ChainableHost[]): ts.CompilerHost {
return chainableHosts.reduce((acc: ts.CompilerHost, chainableHost: ChainableHost) => {
chainableHost.setSource(acc);
return chainableHost;
}, host0 as ChainableHost);
return chainableHosts.reduce((acc: ts.CompilerHost, chainableHost: ChainableHost) => {
chainableHost.setSource(acc);
return chainableHost;
}, host0 as ChainableHost);
}

@@ -1,107 +0,100 @@

/// <reference path="../typings/main.d.ts" />
import * as ts from 'typescript';
import {HostBase} from "./hosts-base";
import {defaultCompilerOptions} from "./configuration";
import {HostBase} from './hosts-base';
import {defaultCompilerOptions} from './configuration';
function fileExtensionIs(path: string, extension: string): boolean {
let pathLen = path.length;
let extLen = extension.length;
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
let pathLen = path.length;
let extLen = extension.length;
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
}
export class MultipleFilesHost extends HostBase implements ts.CompilerHost {
private syntacticErrors: ts.Diagnostic[] = [];
private syntacticErrors: ts.Diagnostic[] = [];
constructor(
private _resolutionHosts: ts.ModuleResolutionHost[],
private _compilerOptions: ts.CompilerOptions = defaultCompilerOptions
) {
super();
}
constructor(
private _resolutionHosts: ts.ModuleResolutionHost[],
private _compilerOptions: ts.CompilerOptions = defaultCompilerOptions
) {
super();
}
fileExists(fileName: string): boolean{
return this._resolutionHosts.some(host => host.fileExists(fileName));
}
fileExists(fileName: string): boolean {
return this._resolutionHosts.some(host => host.fileExists(fileName));
}
readFile(fileName: string): string {
return this._resolutionHosts.reduce<string>(
(acc:string, host: ts.ModuleResolutionHost) => (!acc && host.fileExists(fileName))
? host.readFile(fileName)
: acc,
null);
}
readFile(fileName: string): string {
return this._resolutionHosts.reduce<string>(
(acc: string, host: ts.ModuleResolutionHost) => (!acc && host.fileExists(fileName))
? host.readFile(fileName)
: acc,
null);
}
getSourceFile(fileName: string): ts.SourceFile {
const source = this.readFile(fileName);
if(source) {
const ast: ts.SourceFile = ts.createSourceFile(fileName, source, this._compilerOptions.target, true);
const syntacticErors = this.getParserErrors(ast);
if(syntacticErors.length>0) {
this.syntacticErrors.push(...syntacticErors);
return null;
} else {
return ast;
}
} else {
return null;
}
}
getSourceFile(fileName: string): ts.SourceFile {
const source = this.readFile(fileName);
if (source) {
const ast: ts.SourceFile = ts.createSourceFile(fileName, source, this._compilerOptions.target, true);
const syntacticErors = this.getParserErrors(ast);
if (syntacticErors.length > 0) {
this.syntacticErrors.push(...syntacticErors);
return null;
} else {
return ast;
}
} else {
return null;
}
}
getSyntacticErrors(): ts.Diagnostic[] {
return this.syntacticErrors;
}
getSyntacticErrors(): ts.Diagnostic[] {
return this.syntacticErrors;
}
private getParserErrors(sourceFile: ts.SourceFile): ts.Diagnostic[] {
// We're accessing here an internal property. It would be more legit to access it through
// ts.Program.getSyntacticDiagsnostics(), but we want to bail out ASAP.
return sourceFile['parseDiagnostics'];
}
private getParserErrors(sourceFile: ts.SourceFile): ts.Diagnostic[] {
// We're accessing here an internal property. It would be more legit to access it through
// ts.Program.getSyntacticDiagsnostics(), but we want to bail out ASAP.
return sourceFile['parseDiagnostics'];
}
}
export class SingleFileHost extends HostBase implements ts.CompilerHost {
private _output: string = '';
private _map: string = null;
private _output: string = '';
private _map: string = null;
constructor(private _ast: ts.SourceFile) {
super();
}
constructor(private _ast: ts.SourceFile) {
super();
}
public get output(): string {
return this._output;
}
public get output(): string {
return this._output;
}
public get sourceMap(): SourceMap.RawSourceMap {
return JSON.parse(this._map);
}
public get sourceMap(): SourceMap.RawSourceMap {
return JSON.parse(this._map);
}
fileExists(fileName: string): boolean{
return fileName === this._ast.fileName;
}
fileExists(fileName: string): boolean {
return fileName === this._ast.fileName;
}
readFile(fileName: string): string{
if(fileName === this._ast.fileName) {
return this._ast.text;
}
}
readFile(fileName: string): string {
if (fileName === this._ast.fileName) {
return this._ast.text;
}
}
getSourceFile(fileName: string): ts.SourceFile {
if(fileName === this._ast.fileName) {
return this._ast;
}
}
getSourceFile(fileName: string): ts.SourceFile {
if (fileName === this._ast.fileName) {
return this._ast;
}
}
writeFile(name:string, text:string, writeByteOrderMark: boolean) {
if(fileExtensionIs(name, 'map')) {
this._map = text;
} else {
this._output = text;
}
}
writeFile(name: string, text: string, writeByteOrderMark: boolean) {
if (fileExtensionIs(name, 'map')) {
this._map = text;
} else {
this._output = text;
}
}
}

@@ -1,8 +0,7 @@

/// <reference path="../typings/main.d.ts" />
/// <reference path='../typings/main.d.ts' />
export { transpile, TranspilerOutput, TranspilerConfig, ValidatorConfig, validateAll } from './transpile';
export { Visitor, VisitorContext } from "./visitor";
export { applyVisitor, applyVisitorOnAst, applyVisitorOnHostedSource } from "./apply-visitor";
export { MultipleFilesHost } from "./hosts";
export { traverseAst } from "./traverse-ast";
export {transpile, TranspilerOutput, TranspilerConfig, ValidatorConfig, validateAll} from './transpile';
export {Visitor, VisitorContext} from './visitor';
export {applyVisitor, applyVisitorOnAst, applyVisitorOnHostedSource} from './apply-visitor';
export {MultipleFilesHost} from './hosts';
export {traverseAst} from './traverse-ast';

@@ -1,17 +0,14 @@

/// <reference path="../typings/main.d.ts" />
import { RawSourceMap, SourceMapConsumer, SourceMapGenerator, MappedPosition } from 'source-map';
import * as ts from 'typescript';
import {RawSourceMap, SourceMapConsumer, SourceMapGenerator, MappedPosition} from 'source-map';
import * as traverse from './traverse-ast';
import MagicString = require('magic-string');
import binarySearch from "./binary-search";
import binarySearch from './binary-search';
export abstract class MappedAction {
abstract execute(ast: ts.SourceFile, magicString: MagicString): ts.SourceFile;
abstract getStart(): number;
abstract execute(ast: ts.SourceFile, magicString: MagicString): ts.SourceFile;
abstract getStart(): number;
}
export abstract class FastAction {
abstract execute(ast: ts.SourceFile): ts.SourceFile;
abstract execute(ast: ts.SourceFile): ts.SourceFile;
}

@@ -22,57 +19,57 @@

export class ReplaceAction extends MappedAction {
constructor(private start: number, private end: number, private str: string) {
super();
}
execute(ast: ts.SourceFile, magicString: MagicString): ts.SourceFile {
magicString.overwrite(this.start, this.end, this.str);
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(this.start, this.end);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
return ast.update(magicString.toString(), textChangeRange);
}
constructor(private start: number, private end: number, private str: string) {
super();
}
execute(ast: ts.SourceFile, magicString: MagicString): ts.SourceFile {
magicString.overwrite(this.start, this.end, this.str);
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(this.start, this.end);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
return ast.update(magicString.toString(), textChangeRange);
}
getStart(): number {
return this.start;
}
getStart(): number {
return this.start;
}
}
export class InsertAction extends MappedAction {
constructor(private start: number, private str: string) {
super();
}
execute(ast: ts.SourceFile, magicString: MagicString): ts.SourceFile {
magicString.insert(this.start, this.str);
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(this.start, this.start);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
return ast.update(magicString.toString(), textChangeRange);
}
constructor(private start: number, private str: string) {
super();
}
execute(ast: ts.SourceFile, magicString: MagicString): ts.SourceFile {
magicString.insert(this.start, this.str);
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(this.start, this.start);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
return ast.update(magicString.toString(), textChangeRange);
}
getStart(): number {
return this.start;
}
getStart(): number {
return this.start;
}
}
export class FastAppendAction extends FastAction {
constructor(private str: string) {
super();
}
constructor(private str: string) {
super();
}
execute(ast: ts.SourceFile): ts.SourceFile {
const start = ast.text.length - 1;
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(start, start);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
return ast.update(ast.text + this.str, textChangeRange);
}
execute(ast: ts.SourceFile): ts.SourceFile {
const start = ast.text.length - 1;
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(start, start);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
return ast.update(ast.text + this.str, textChangeRange);
}
}
export class FastRewriteAction extends FastAction {
constructor(private start: number, private str: string) {
super();
}
constructor(private start: number, private str: string) {
super();
}
execute(ast: ts.SourceFile): ts.SourceFile {
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(this.start, this.start + this.str.length);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
const newText = ast.text.slice(0,this.start) + this.str + ast.text.slice(this.start + this.str.length);
return ast.update(newText, textChangeRange);
}
execute(ast: ts.SourceFile): ts.SourceFile {
const textSpan: ts.TextSpan = ts.createTextSpanFromBounds(this.start, this.start + this.str.length);
const textChangeRange: ts.TextChangeRange = ts.createTextChangeRange(textSpan, this.str.length);
const newText = ast.text.slice(0, this.start) + this.str + ast.text.slice(this.start + this.str.length);
return ast.update(newText, textChangeRange);
}
}

@@ -84,94 +81,93 @@

private _ast: ts.SourceFile;
private magicString: MagicString;
private originalText: string;
private origLineStarts: number[];
private _sourceMap: RawSourceMap;
private _ast: ts.SourceFile;
private magicString: MagicString;
private originalText: string;
private origLineStarts: number[];
private _sourceMap: RawSourceMap;
constructor(ast: ts.SourceFile) {
this._ast = ast;
this.originalText = ast.text;
this.origLineStarts = ast.getLineStarts();
}
constructor(ast: ts.SourceFile) {
this._ast = ast;
this.originalText = ast.text;
this.origLineStarts = ast.getLineStarts();
}
get ast(): ts.SourceFile {
return this._ast;
}
get ast(): ts.SourceFile {
return this._ast;
}
execute(actionList: Array<Action>): void {
const fastActions = <FastAction[]>actionList.filter(action => action instanceof FastAction);
fastActions.forEach((action: FastAction) => {
this._ast = action.execute(this._ast);
});
this.magicString = new MagicString(this._ast.text);
execute(actionList: Array<Action>): void {
const fastActions = <FastAction[]>actionList.filter(action => action instanceof FastAction);
fastActions.forEach((action: FastAction) => {
this._ast = action.execute(this._ast);
});
this.magicString = new MagicString(this._ast.text);
const sortedActions = actionList
.filter(action => action instanceof MappedAction)
.sort(compareActions);
sortedActions.forEach((action: Action) => {
this._ast = action.execute(this._ast, this.magicString);
});
}
const sortedActions = actionList
.filter(action => action instanceof MappedAction)
.sort(compareActions);
sortedActions.forEach((action: Action) => {
this._ast = action.execute(this._ast, this.magicString);
});
}
get sourceMap(): RawSourceMap {
if(!this.magicString) {
this.magicString = new MagicString(this._ast.text);
}
if(!this._sourceMap) {
this._sourceMap = this.magicString.generateMap({ source: this._ast.fileName, hires: true });
}
return this._sourceMap;
}
get sourceMap(): RawSourceMap {
if (!this.magicString) {
this.magicString = new MagicString(this._ast.text);
}
if (!this._sourceMap) {
this._sourceMap = this.magicString.generateMap({ source: this._ast.fileName, hires: true });
}
return this._sourceMap;
}
get code(): string {
return this._ast.text;
}
get code(): string {
return this._ast.text;
}
translateMap(from: RawSourceMap): RawSourceMap {
const originalText = this.originalText;
const intermediateAst = this._ast;
translateMap(from: RawSourceMap): RawSourceMap {
const originalText = this.originalText;
const intermediateAst = this._ast;
const mapConsumer = new SourceMapConsumer(this.sourceMap);
const mapConsumer = new SourceMapConsumer(this.sourceMap);
var fromSMC = new SourceMapConsumer(from);
var resultMap = new SourceMapGenerator();
resultMap.setSourceContent(intermediateAst.fileName, originalText);
var fromSMC = new SourceMapConsumer(from);
var resultMap = new SourceMapGenerator();
resultMap.setSourceContent(intermediateAst.fileName, originalText);
fromSMC.eachMapping(mapping => {
var originalPosition: MappedPosition = mapConsumer.originalPositionFor({ line: mapping.originalLine, column: mapping.originalColumn });
if(originalPosition.line != null) {
resultMap.addMapping({
source: intermediateAst.fileName,
name: mapping.name,
generated: {
line: mapping.generatedLine,
column: mapping.generatedColumn
},
original: originalPosition
});
}
});
this._sourceMap = <RawSourceMap>resultMap.toJSON();
return resultMap.toJSON();
}
fromSMC.eachMapping(mapping => {
var originalPosition: MappedPosition = mapConsumer.originalPositionFor({ line: mapping.originalLine, column: mapping.originalColumn });
if (originalPosition.line != null) {
resultMap.addMapping({
source: intermediateAst.fileName,
name: mapping.name,
generated: {
line: mapping.generatedLine,
column: mapping.generatedColumn
},
original: originalPosition
});
}
});
this._sourceMap = <RawSourceMap>resultMap.toJSON();
return resultMap.toJSON();
}
translateDiagnostic(diag: ts.Diagnostic): ts.Diagnostic {
const sourceMap: RawSourceMap = this.sourceMap;
const cosumer: SourceMapConsumer = new SourceMapConsumer(sourceMap);
const start: ts.LineAndCharacter = diag.file.getLineAndCharacterOfPosition(diag.start);
const startPos: MappedPosition = cosumer.originalPositionFor({ line: start.line + 1, column: start.character });
if(startPos.line === null) {
return diag;
} else {
return {
file: diag.file,
start: diag.file.getPositionOfLineAndCharacter(startPos.line -1, startPos.column),
length: diag.length,
messageText: diag.messageText,
category: diag.category,
code: diag.code
};
}
}
translateDiagnostic(diag: ts.Diagnostic): ts.Diagnostic {
const sourceMap: RawSourceMap = this.sourceMap;
const cosumer: SourceMapConsumer = new SourceMapConsumer(sourceMap);
const start: ts.LineAndCharacter = diag.file.getLineAndCharacterOfPosition(diag.start);
const startPos: MappedPosition = cosumer.originalPositionFor({ line: start.line + 1, column: start.character });
if (startPos.line === null) {
return diag;
} else {
return {
file: diag.file,
start: diag.file.getPositionOfLineAndCharacter(startPos.line - 1, startPos.column),
length: diag.length,
messageText: diag.messageText,
category: diag.category,
code: diag.code
};
}
}
}
import * as ts from 'typescript';
import {Visitor} from "./visitor";
import {TranspilerContext} from "./transpiler-context";
import { traverseAst } from './traverse-ast';
import {MutableSourceCode} from "./mutable-source-code";
import {Visitor} from './visitor';
import {TranspilerContext} from './transpiler-context';
import {traverseAst} from './traverse-ast';
import {MutableSourceCode} from './mutable-source-code';
export interface CodeTransformer {
transform(ast: ts.SourceFile): MutableSourceCode;
transform(ast: ts.SourceFile): MutableSourceCode;
}
export class VisitorBasedTransformer implements CodeTransformer {
constructor(private visitors: Visitor[], private languageServiceProvider: () => ts.LanguageService) {}
constructor(private visitors: Visitor[], private languageServiceProvider: () => ts.LanguageService) { }
transform(ast: ts.SourceFile): MutableSourceCode {
const context: TranspilerContext = new TranspilerContext(ast.fileName, this.languageServiceProvider);
this.visitors.forEach((visitor) => {
context.halted || traverseAst(ast, visitor, context);
});
transform(ast: ts.SourceFile): MutableSourceCode {
const context: TranspilerContext = new TranspilerContext(ast.fileName, this.languageServiceProvider);
this.visitors.forEach((visitor) => {
context.halted || traverseAst(ast, visitor, context);
});
if(context.halted) {
return null;
} else {
const mutable = new MutableSourceCode(ast);
mutable.execute(context.actions);
return mutable;
}
}
if (context.halted) {
return null;
} else {
const mutable = new MutableSourceCode(ast);
mutable.execute(context.actions);
return mutable;
}
}
}

@@ -1,15 +0,13 @@

/// <reference path="../typings/main.d.ts" />
import { SingleFileHost, MultipleFilesHost } from './hosts';
import { traverseAst } from './traverse-ast';
import { MutableSourceCode } from './mutable-source-code';
import { RawSourceMap } from 'source-map';
import { Visitor } from './visitor';
import * as ts from 'typescript';
import { TranspilerContext } from "./transpiler-context";
import { defaultCompilerOptions } from "./configuration";
import {SemanticHost} from "./chainable-hosts";
import {TransformationHost} from "./chainable-hosts";
import {chainHosts} from "./hosts-base";
import {AstCacheHost} from "./chainable-hosts";
import {SingleFileHost, MultipleFilesHost} from './hosts';
import {traverseAst} from './traverse-ast';
import {MutableSourceCode} from './mutable-source-code';
import {RawSourceMap} from 'source-map';
import {Visitor} from './visitor';
import {TranspilerContext} from './transpiler-context';
import {defaultCompilerOptions} from './configuration';
import {SemanticHost} from './chainable-hosts';
import {TransformationHost} from './chainable-hosts';
import {chainHosts} from './hosts-base';
import {AstCacheHost} from './chainable-hosts';

@@ -23,33 +21,33 @@ /**

*/
code: string,
code: string,
/**
* a raw sourcemap object representing all changes made from the supplied source to the transpiled code (visitors and typescript alike)
*/
sourceMap: RawSourceMap,
sourceMap: RawSourceMap,
/**
* diagnostics produced by Typescript or the visitors
*/
diags: ts.Diagnostic[],
diags: ts.Diagnostic[],
/**
* did the transpilation fail
*/
halted: boolean
halted: boolean
}
export interface TranspilerConfig {
sourceFileName: string;
compilerOptions?: ts.CompilerOptions;
visitors: Visitor[];
sourceFileName: string;
compilerOptions?: ts.CompilerOptions;
visitors: Visitor[];
}
export interface ValidatorConfig {
resolutionHosts?: ts.ModuleResolutionHost[];
visitors?: Visitor[];
mutators?: Visitor[];
resolutionHosts?: ts.ModuleResolutionHost[];
visitors?: Visitor[];
mutators?: Visitor[];
}
function getParserErrors(sourceFile: ts.SourceFile): ts.Diagnostic[] {
// We're accessing here an internal property. It would be more legit to access it through
// ts.Program.getSyntacticDiagsnostics(), but we want to bail out ASAP.
return sourceFile['parseDiagnostics'];
// We're accessing here an internal property. It would be more legit to access it through
// ts.Program.getSyntacticDiagsnostics(), but we want to bail out ASAP.
return sourceFile['parseDiagnostics'];
}

@@ -61,110 +59,109 @@

// The context may contain compiler options and a list of visitors.
// If it doesn't, we use the default as defined in ./configuration.ts
// The context may contain compiler options and a list of visitors.
// If it doesn't, we use the default as defined in ./configuration.ts
const compilerOptions = config.compilerOptions || defaultCompilerOptions;
const compilerOptions = config.compilerOptions || defaultCompilerOptions;
// First we initialize a SourceFile object with the given source code
// First we initialize a SourceFile object with the given source code
const fileName: string = config.sourceFileName;
const fileName: string = config.sourceFileName;
// Then we let TypeScript parse it into an AST
// Then we let TypeScript parse it into an AST
const ast = ts.createSourceFile(fileName, content, compilerOptions.target, true);
const parserErrors = getParserErrors(ast);
if(parserErrors.length>0) {
return {
code: null,
diags: parserErrors,
halted: true,
sourceMap: null
}
}
const ast = ts.createSourceFile(fileName, content, compilerOptions.target, true);
const parserErrors = getParserErrors(ast);
if (parserErrors.length > 0) {
return {
code: null,
diags: parserErrors,
halted: true,
sourceMap: null
}
}
// The context contains code modifications and diagnostics
// The context contains code modifications and diagnostics
let context: TranspilerContext = new TranspilerContext(ast.fileName);
let context: TranspilerContext = new TranspilerContext(ast.fileName);
// We execute the various visitors, each traversing the AST and generating
// lines to be pushed into the code and diagbostic messages.
// If one of the visitors halts the transilation process we return the halted object.
// We execute the various visitors, each traversing the AST and generating
// lines to be pushed into the code and diagbostic messages.
// If one of the visitors halts the transilation process we return the halted object.
config.visitors.some((visitor) => {
traverseAst(ast, visitor, context);
return context.halted;
});
config.visitors.some((visitor) => {
traverseAst(ast, visitor, context);
return context.halted;
});
if(context.halted) {
return {
code: null,
sourceMap: null,
diags: context.diags,
halted: true
};
}
if (context.halted) {
return {
code: null,
sourceMap: null,
diags: context.diags,
halted: true
};
}
// Now, we mutate the code with the resulting list of strings to be pushed
// Now, we mutate the code with the resulting list of strings to be pushed
const mutable = new MutableSourceCode(ast);
mutable.execute(context.actions);
const mutable = new MutableSourceCode(ast);
mutable.execute(context.actions);
// This intermediate code has to be transpiled by TypeScript
// This intermediate code has to be transpiled by TypeScript
const compilerHost = new SingleFileHost(mutable.ast);
const program: ts.Program = ts.createProgram([fileName], compilerOptions, compilerHost);
const emitResult = program.emit();
const compilerHost = new SingleFileHost(mutable.ast);
const program: ts.Program = ts.createProgram([fileName], compilerOptions, compilerHost);
const emitResult = program.emit();
emitResult.diagnostics.forEach((d: ts.Diagnostic) => {
context.pushDiag(mutable.translateDiagnostic(d));
});
emitResult.diagnostics.forEach((d: ts.Diagnostic) => {
context.pushDiag(mutable.translateDiagnostic(d));
});
// If TypeScript did not complete the transpilation, we return the halted object
// If TypeScript did not complete the transpilation, we return the halted object
if(emitResult.emitSkipped) {
return {
code: null,
sourceMap: null,
diags: context.diags,
halted: true
};
}
if (emitResult.emitSkipped) {
return {
code: null,
sourceMap: null,
diags: context.diags,
halted: true
};
}
// If we got here, it means we have final source code to return
// If we got here, it means we have final source code to return
const finalCode: string = compilerHost.output;
const intermediateSourceMap = compilerHost.sourceMap;
const finalCode: string = compilerHost.output;
const intermediateSourceMap = compilerHost.sourceMap;
// The resulting sourcemap maps the final code to the intermediate code,
// but we want a sourcemap that maps the final code to the original code,
// so...
// The resulting sourcemap maps the final code to the intermediate code,
// but we want a sourcemap that maps the final code to the original code,
// so...
const finalSourceMap: RawSourceMap = intermediateSourceMap ? mutable.translateMap(intermediateSourceMap) : null;
const finalSourceMap: RawSourceMap = intermediateSourceMap ? mutable.translateMap(intermediateSourceMap) : null;
// Now we return the final code and the final sourcemap
// Now we return the final code and the final sourcemap
return {
code: finalCode,
sourceMap: finalSourceMap,
diags: context.diags,
halted: false
};
return {
code: finalCode,
sourceMap: finalSourceMap,
diags: context.diags,
halted: false
};
}
export function validateAll(files: string[], config: ValidatorConfig): ts.Diagnostic[] {
let langService: ts.LanguageService;
const sourceHost = new MultipleFilesHost(config.resolutionHosts, defaultCompilerOptions);
const astCache = new AstCacheHost();
const cachedSource: ts.CompilerHost = chainHosts(sourceHost, astCache);
const semanticHost = <SemanticHost>chainHosts(cachedSource, new SemanticHost(files, defaultCompilerOptions));
const langServiceProvider = () => langService
? langService
: langService = ts.createLanguageService(semanticHost, semanticHost);
const transformHost = new TransformationHost(config.mutators || [], langServiceProvider);
const program: ts.Program = ts.createProgram(files, defaultCompilerOptions, chainHosts(cachedSource, transformHost));
const diags: ts.Diagnostic[] = [].concat(
sourceHost.getSyntacticErrors(),
program.getSemanticDiagnostics()
);
return diags.map(diagnostic => transformHost.translateDiagnostic(diagnostic));
let langService: ts.LanguageService;
const sourceHost = new MultipleFilesHost(config.resolutionHosts, defaultCompilerOptions);
const astCache = new AstCacheHost();
const cachedSource: ts.CompilerHost = chainHosts(sourceHost, astCache);
const semanticHost = <SemanticHost>chainHosts(cachedSource, new SemanticHost(files, defaultCompilerOptions));
const langServiceProvider = () => langService
? langService
: langService = ts.createLanguageService(semanticHost, semanticHost);
const transformHost = new TransformationHost(config.mutators || [], langServiceProvider);
const program: ts.Program = ts.createProgram(files, defaultCompilerOptions, chainHosts(cachedSource, transformHost));
const diags: ts.Diagnostic[] = [].concat(
sourceHost.getSyntacticErrors(),
program.getSemanticDiagnostics()
);
return diags.map(diagnostic => transformHost.translateDiagnostic(diagnostic));
}

@@ -1,79 +0,77 @@

/// <reference path="../typings/main.d.ts" />
import { MutableSourceCode, Action, ReplaceAction } from './mutable-source-code';
import { Visitor, VisitorContext } from './visitor';
import * as ts from 'typescript';
import {FastAppendAction} from "./mutable-source-code";
import {FastRewriteAction} from "./mutable-source-code";
import {InsertAction} from "./mutable-source-code";
import {MutableSourceCode, Action, ReplaceAction} from './mutable-source-code';
import {Visitor, VisitorContext} from './visitor';
import {FastAppendAction} from './mutable-source-code';
import {FastRewriteAction} from './mutable-source-code';
import {InsertAction} from './mutable-source-code';
export class TranspilerContext implements VisitorContext {
private _halted = false;
private _actions: Action[] = [];
private _diags: ts.Diagnostic[] = [];
private _halted = false;
private _actions: Action[] = [];
private _diags: ts.Diagnostic[] = [];
constructor(private _fileName: string, private langServiceProvider: () => ts.LanguageService = null) {}
constructor(private _fileName: string, private langServiceProvider: () => ts.LanguageService = null) { }
isHalted(): boolean {
return this._halted;
}
isHalted(): boolean {
return this._halted;
}
insertLine(position: number, str: string): void {
this._actions.push(new InsertAction(position, str + '\n'));
}
insertLine(position: number, str: string): void {
this._actions.push(new InsertAction(position, str + '\n'));
}
replace(start: number, end: number, str: string): void {
this._actions.push(new ReplaceAction(start, end, str ));
}
replace(start: number, end: number, str: string): void {
this._actions.push(new ReplaceAction(start, end, str));
}
fastAppend(str: string): void {
this._actions.push(new FastAppendAction(str));
}
fastAppend(str: string): void {
this._actions.push(new FastAppendAction(str));
}
fastRewrite(start: number, str: string): void {
this._actions.push(new FastRewriteAction(start, str));
}
fastRewrite(start: number, str: string): void {
this._actions.push(new FastRewriteAction(start, str));
}
reportDiag(node: ts.Node, category: ts.DiagnosticCategory, message: string, halt?: boolean): void {
let diagnostic: ts.Diagnostic = {
file: node.getSourceFile(),
start: node.getStart(),
length: node.getEnd() - node.getStart(),
messageText: message,
category: category,
code: 0
};
this._diags.push(diagnostic);
this._halted = this._halted || halt;
}
reportDiag(node: ts.Node, category: ts.DiagnosticCategory, message: string, halt?: boolean): void {
let diagnostic: ts.Diagnostic = {
file: node.getSourceFile(),
start: node.getStart(),
length: node.getEnd() - node.getStart(),
messageText: message,
category: category,
code: 0
};
this._diags.push(diagnostic);
this._halted = this._halted || halt;
}
pushDiag(diagnostic: ts.Diagnostic): void {
this._diags.push(diagnostic);
}
pushDiag(diagnostic: ts.Diagnostic): void {
this._diags.push(diagnostic);
}
get actions(): Action[] {
return this._actions;
}
get actions(): Action[] {
return this._actions;
}
get diags(): ts.Diagnostic[] {
return this._diags;
}
get diags(): ts.Diagnostic[] {
return this._diags;
}
get halted(): boolean {
return this._halted;
}
get halted(): boolean {
return this._halted;
}
get fileName(): string {
return this._fileName;
}
get fileName(): string {
return this._fileName;
}
getLanguageService(): ts.LanguageService {
if(this.langServiceProvider) {
return this.langServiceProvider();
} else {
return null;
}
getLanguageService(): ts.LanguageService {
if (this.langServiceProvider) {
return this.langServiceProvider();
} else {
return null;
}
}
}
}
import * as ts from 'typescript';
import { Visitor, VisitorContext } from './visitor';
import {Visitor, VisitorContext} from './visitor';
function descend(node: ts.Node, context: VisitorContext) {
return function visit(...visitors: Visitor[]): void {
visitors.forEach(visitor => {
traverseAst(node, visitor, context);
});
}
return function visit(...visitors: Visitor[]): void {
visitors.forEach(visitor => {
traverseAst(node, visitor, context);
});
}
}

@@ -15,11 +15,11 @@

function traverse(node: ts.Node) {
if(visitor.filter(node)) {
visitor.visit(node, context, descend(node, context));
return context.halted || ts.forEachChild(node, traverse);
}
return ts.forEachChild(node, traverse);
}
function traverse(node: ts.Node) {
if (visitor.filter(node)) {
visitor.visit(node, context, descend(node, context));
return context.halted || ts.forEachChild(node, traverse);
}
return ts.forEachChild(node, traverse);
}
return traverse(root);
return traverse(root);
}
import * as ts from 'typescript';
import {Action} from "./mutable-source-code";
import {Action} from './mutable-source-code';

@@ -8,7 +8,7 @@ /**

export interface VisitorContext {
fileName: string;
fileName: string;
/**
* was the transpilation declared as failed by any previous visitor
*/
halted: boolean;
halted: boolean;
/**

@@ -19,3 +19,3 @@ * add a text line at given position

*/
insertLine(position: number, str: string): void;
insertLine(position: number, str: string): void;
/**

@@ -27,3 +27,3 @@ * replace a piece of text in the code with a given new text

*/
replace(start: number, end: number, str: string): void;
replace(start: number, end: number, str: string): void;
/**

@@ -36,8 +36,8 @@ * report transpilation diagnostics

*/
reportDiag(node: ts.Node, category: ts.DiagnosticCategory, message: string, halt?: boolean): void;
reportDiag(node: ts.Node, category: ts.DiagnosticCategory, message: string, halt?: boolean): void;
fastAppend(str: string): void;
fastRewrite(start: number, str: string): void;
fastAppend(str: string): void;
fastRewrite(start: number, str: string): void;
getLanguageService(): ts.LanguageService;
getLanguageService(): ts.LanguageService;
}

@@ -53,3 +53,3 @@

*/
filter(node: ts.Node) : boolean;
filter(node: ts.Node): boolean;
/**

@@ -60,3 +60,3 @@ * perform visitor logic on given node

*/
visit(node: ts.Node, context: VisitorContext, traverse: (...visitors: Visitor[])=> void): void;
visit(node: ts.Node, context: VisitorContext, traverse: (...visitors: Visitor[]) => void): void;
}

@@ -1,10 +0,4 @@

/**
* Created by gadig on 9/24/15.
*/
/// <reference path="../typings/main.d.ts" />
import * as SourceMap from 'source-map';
import * as _ from 'lodash';
import * as ts from "typescript";
import * as ts from 'typescript';

@@ -14,3 +8,3 @@ export function findCodePosition(code: string, snippet: string): SourceMap.Position {

var lineNo = _.findIndex(lines, (line) => _.includes(line, snippet));
if(lineNo > -1) {
if (lineNo > -1) {
var column = (lineNo > -1) && lines[lineNo].indexOf(snippet);

@@ -26,5 +20,5 @@ return {

export function findCodeRange(code: string, snippet: string): ts.TextRange {
export function findCodeRange(code: string, snippet: string): ts.TextRange {
var pos = code.indexOf(snippet);
return pos < 0 ? null : { pos, end: pos + snippet.length };
}
import ts = require('typescript');
function printMessage(messageText:string | ts.DiagnosticMessageChain):string {
if(messageText["messageText"]) {
return printMessage((<ts.DiagnosticMessageChain>messageText).messageText);
} else {
return messageText.toString();
}
function printMessage(messageText: string | ts.DiagnosticMessageChain): string {
if (messageText['messageText']) {
return printMessage((<ts.DiagnosticMessageChain>messageText).messageText);
} else {
return messageText.toString();
}
}

@@ -13,6 +13,6 @@

export function printDiagnostic(diagnostic: ts.Diagnostic) {
const linePos: ts.LineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
const message: string = printMessage(diagnostic.messageText);
return `${diagnostic.file.fileName} -> ${linePos.line + 1}:${linePos.character} ${message}`;
const linePos: ts.LineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
const message: string = printMessage(diagnostic.messageText);
return `${diagnostic.file.fileName} -> ${linePos.line + 1}:${linePos.character} ${message}`;
}

@@ -1,3 +0,1 @@

/// <reference path="../typings/main.d.ts" />
import {getModuleLoader, Dependency} from './mocks/module-loaders';

@@ -7,8 +5,8 @@

export function evaluateModuleExports(source: string, dependencies: Dependency[] = []) :Object{
const moduleLoader = getModuleLoader();
dependencies.forEach(d => {
moduleLoader.addDependency(d);
});
return moduleLoader.load(source);
export function evaluateModuleExports(source: string, dependencies: Dependency[] = []): Object {
const moduleLoader = getModuleLoader();
dependencies.forEach(d => {
moduleLoader.addDependency(d);
});
return moduleLoader.load(source);
}

@@ -1,18 +0,18 @@

/// <reference path="../typings/main.d.ts" />
/// <reference path='../typings/main.d.ts' />
import * as chai from 'chai';
import typecheck from './matchers/typecheck';
import * as chai from 'chai';
chai.use(typecheck);
export { findCodePosition, findCodeRange } from './code-positions';
export { evaluateModuleExports } from './evaluate-module';
export {findCodePosition, findCodeRange} from './code-positions';
export {evaluateModuleExports} from './evaluate-module';
// This is a loader for debugging purposes when running node tests (not from webpack bundle)
if(require.extensions) {
require.extensions['.ts'] = function (module, fileName) {
var content = require('fs').readFileSync(fileName).toString();
var code = 'module.exports = ' + JSON.stringify(content) + ';';
return module._compile(code, fileName);
};
if (require.extensions) {
require.extensions['.ts'] = function(module, fileName) {
var content = require('fs').readFileSync(fileName).toString();
var code = 'module.exports = ' + JSON.stringify(content) + ';';
return module._compile(code, fileName);
};
}

@@ -1,17 +0,16 @@

/// <reference path="../typings/main.d.ts" />
/// <reference path='../typings/main.d.ts' />
declare module Chai {
interface Assertion {
pass(): Assertion;
fail(): Matchers.TypeCheckFailure;
}
interface Assertion {
pass(): Assertion;
fail(): Matchers.TypeCheckFailure;
}
}
declare module Matchers {
interface TypeCheckFailure {
withMessage(messageMatch: string | RegExp): TypeCheckFailure;
withMessageCount(expectedCount: number): TypeCheckFailure;
and: TypeCheckFailure;
}
interface TypeCheckFailure {
withMessage(messageMatch: string | RegExp): TypeCheckFailure;
withMessageCount(expectedCount: number): TypeCheckFailure;
and: TypeCheckFailure;
}
}

@@ -1,3 +0,1 @@

/// <reference path="../../typings/main.d.ts" />
import {expect} from 'chai';

@@ -8,64 +6,63 @@ import {printDiagnostic} from '../diagnostics-utils';

class TypecheckFailure implements Matchers.TypeCheckFailure {
constructor(private assertion: Chai.AssertStatic, private diags: ts.Diagnostic[]) {}
constructor(private assertion: Chai.AssertStatic, private diags: ts.Diagnostic[]) { }
get and(): TypecheckFailure {
return this;
}
get and(): TypecheckFailure {
return this;
}
withMessage(messageMatch:string|RegExp): Matchers.TypeCheckFailure {
let isMatch;
if(messageMatch instanceof RegExp) {
isMatch = this.diags.some(diag => {
const messageText = printDiagnostic(diag);
return !!(messageText.match(messageMatch))
});
} else if(typeof messageMatch === 'string') {
isMatch = this.diags.some(diag => !!(diag.messageText && diag.messageText === messageMatch))
}
expect(isMatch).to.equal(true, `Expected some of the typechecker messages to match ${messageMatch}.
withMessage(messageMatch: string | RegExp): Matchers.TypeCheckFailure {
let isMatch;
if (messageMatch instanceof RegExp) {
isMatch = this.diags.some(diag => {
const messageText = printDiagnostic(diag);
return !!(messageText.match(messageMatch))
});
} else if (typeof messageMatch === 'string') {
isMatch = this.diags.some(diag => !!(diag.messageText && diag.messageText === messageMatch))
}
expect(isMatch).to.equal(true, `Expected some of the typechecker messages to match ${messageMatch}.
Actual errors:
${printErrors(this.diags)}
`)
return this;
}
return this;
}
withMessageCount(expectedCount:number): Matchers.TypeCheckFailure {
expect(this.diags.length)
.to.equal(expectedCount,
`Expected to fail with ${expectedCount} errors, but got ${this.diags.length}.
withMessageCount(expectedCount: number): Matchers.TypeCheckFailure {
expect(this.diags.length)
.to.equal(expectedCount,
`Expected to fail with ${expectedCount} errors, but got ${this.diags.length}.
Actual errors:
${printErrors(this.diags)}
`);
return this;
}
return this;
}
}
function printErrors(diags: ts.Diagnostic[]): string {
return diags.map<string>(printDiagnostic).join('\n');
return diags.map<string>(printDiagnostic).join('\n');
}
export default function (chai, util) {
chai.Assertion.addMethod('pass', function () {
expect(this._obj).to.be.an('Array');
this.empty;
});
export default function(chai, util) {
chai.Assertion.addMethod('pass', function() {
expect(this._obj).to.be.an('Array');
this.empty;
});
chai.Assertion.addMethod('fail', function () {
expect(this._obj).to.be.an('Array');
this.not.empty;
const diags: ts.Diagnostic[] = <ts.Diagnostic[]>this._obj;
return new TypecheckFailure(this, diags);
});
chai.Assertion.addMethod('fail', function() {
expect(this._obj).to.be.an('Array');
this.not.empty;
const diags: ts.Diagnostic[] = <ts.Diagnostic[]>this._obj;
return new TypecheckFailure(this, diags);
});
chai.Assertion.addMethod('pass', function () {
this.an('Array');
this.assert(this._obj.length === 0,
`Expected to get 0 validation errors, but got, but got ${this._obj.length}:
chai.Assertion.addMethod('pass', function() {
this.an('Array');
this.assert(this._obj.length === 0,
`Expected to get 0 validation errors, but got, but got ${this._obj.length}:
${printErrors(this._obj)}
`,
'Expected to get validation errors, but got, but got none.'
);
});
'Expected to get validation errors, but got, but got none.'
);
});
}

@@ -1,16 +0,14 @@

/// <reference path="../../typings/main.d.ts" />
export interface Dependency {
depName : string;
exportName : string;
value : any;
depName: string;
exportName: string;
value: any;
}
export interface ModuleLoader {
addDependency(dependency: Dependency): void;
load(source:string):Object;
addDependency(dependency: Dependency): void;
load(source: string): Object;
}
export function getModuleLoader(): ModuleLoader {
return new CommonJSMockLoader();
return new CommonJSMockLoader();
}

@@ -22,13 +20,13 @@

function __decorate(decorators, target, key, desc) {
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
}
function __extends(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}

@@ -38,18 +36,18 @@

class CommonJSMockLoader implements ModuleLoader{
private _dependencies = {};
class CommonJSMockLoader implements ModuleLoader {
private _dependencies = {};
addDependency({depName, exportName, value}) {
this._dependencies[depName] = this._dependencies[depName] || {};
if(exportName === 'default') {
this._dependencies[depName] = value;
}
this._dependencies[depName][exportName] = value;
}
addDependency({depName, exportName, value}) {
this._dependencies[depName] = this._dependencies[depName] || {};
if (exportName === 'default') {
this._dependencies[depName] = value;
}
this._dependencies[depName][exportName] = value;
}
load(source:string):Object {
let Module = {
exports: {}
};
const testFn = new Function(`
load(source: string): Object {
let Module = {
exports: {}
};
const testFn = new Function(`
return function loadModuleCjs(require, exports, module, __decorate, __extends) {

@@ -59,5 +57,5 @@ ${source}

`);
testFn()(moduleName => this._dependencies[moduleName], Module.exports, Module, __decorate, __extends);
return Module.exports;
}
testFn()(moduleName => this._dependencies[moduleName], Module.exports, Module, __decorate, __extends);
return Module.exports;
}
}

@@ -5,11 +5,11 @@ import * as ts from 'typescript';

constructor(private mockFileName: string, private mockContent: string){}
constructor(private mockFileName: string, private mockContent: string) { }
fileExists(fileName:string):boolean {
return this.mockFileName === fileName;
}
fileExists(fileName: string): boolean {
return this.mockFileName === fileName;
}
readFile(fileName:string):string {
return this.mockFileName === fileName ? this.mockContent : null;
}
readFile(fileName: string): string {
return this.mockFileName === fileName ? this.mockContent : null;
}
}

@@ -6,40 +6,40 @@ import {expect} from 'chai';

describe('poc example', function () {
let sourceCode, configNoVisitors, configWithVisitors;
before(() => {
sourceCode = require('../../examples/poc/src.ts'); // the path is relative to tspoon/dist/test
configNoVisitors = {
sourceFileName: 'src.ts',
visitors: []
};
configWithVisitors = {
sourceFileName: 'src.ts',
visitors: [visitor]
};
});
describe('poc example', function() {
let sourceCode, configNoVisitors, configWithVisitors;
before(() => {
sourceCode = require('../../examples/poc/src.ts'); // the path is relative to tspoon/dist/test
configNoVisitors = {
sourceFileName: 'src.ts',
visitors: []
};
configWithVisitors = {
sourceFileName: 'src.ts',
visitors: [visitor]
};
});
it('is transpiled', function () {
let transpilerOut = tspoon.transpile(sourceCode, configWithVisitors);
expect(transpilerOut.halted).not.to.be.ok;
expect(transpilerOut.code).to.be.ok;
expect(transpilerOut.sourceMap).to.be.ok;
});
it('is transpiled', function() {
let transpilerOut = tspoon.transpile(sourceCode, configWithVisitors);
expect(transpilerOut.halted).not.to.be.ok;
expect(transpilerOut.code).to.be.ok;
expect(transpilerOut.sourceMap).to.be.ok;
});
it('is transpiled correctly without visitors', function () {
let transpilerOut = tspoon.transpile(sourceCode, configNoVisitors);
let TwoNames = evaluateModuleExports(transpilerOut.code)['TwoNames'];
let instance = new TwoNames();
expect(transpilerOut.diags).to.be.empty;
expect(transpilerOut.halted).not.to.be.ok;
expect(instance.publicName, 'publicName').to.eql('Doe');
expect(instance.privateName, 'privateName').to.eql('John');
});
it('is transpiled correctly without visitors', function() {
let transpilerOut = tspoon.transpile(sourceCode, configNoVisitors);
let TwoNames = evaluateModuleExports(transpilerOut.code)['TwoNames'];
let instance = new TwoNames();
expect(transpilerOut.diags).to.be.empty;
expect(transpilerOut.halted).not.to.be.ok;
expect(instance.publicName, 'publicName').to.eql('Doe');
expect(instance.privateName, 'privateName').to.eql('John');
});
it('is transpiled correctly with visitors and removes fields with no explicit visibility', function () {
let transpilerOut = tspoon.transpile(sourceCode, configWithVisitors);
let TwoNames = evaluateModuleExports(transpilerOut.code)['TwoNames'];
let instance = new TwoNames();
expect(instance.publicName, 'publicName').to.eql('Doe');
expect(instance.privateName, 'privateName').not.to.be.ok;
});
it('is transpiled correctly with visitors and removes fields with no explicit visibility', function() {
let transpilerOut = tspoon.transpile(sourceCode, configWithVisitors);
let TwoNames = evaluateModuleExports(transpilerOut.code)['TwoNames'];
let instance = new TwoNames();
expect(instance.publicName, 'publicName').to.eql('Doe');
expect(instance.privateName, 'privateName').not.to.be.ok;
});
});
import {expect} from 'chai';
import * as tspoon from '../src/index';
import { evaluateModuleExports } from '../test-kit/index';
import {evaluateModuleExports} from '../test-kit/index';
let visitor = require('../../examples/readme/alertProperty.js');
describe('readme example', function () {
let sourceCode, config;
before(() => {
sourceCode = require('../../examples/readme/src.ts'); // the path is relative to tspoon/dist/test
config = {
sourceFileName: 'src.ts',
visitors: [visitor]
};
});
describe('readme example', function() {
let sourceCode, config;
before(() => {
sourceCode = require('../../examples/readme/src.ts'); // the path is relative to tspoon/dist/test
config = {
sourceFileName: 'src.ts',
visitors: [visitor]
};
});
it('is transpiled', function () {
let transpilerOut = tspoon.transpile(sourceCode, config);
expect(transpilerOut.halted).not.to.be.ok;
expect(transpilerOut.code).to.be.ok;
expect(transpilerOut.sourceMap).to.be.ok;
});
it('is transpiled', function() {
let transpilerOut = tspoon.transpile(sourceCode, config);
expect(transpilerOut.halted).not.to.be.ok;
expect(transpilerOut.code).to.be.ok;
expect(transpilerOut.sourceMap).to.be.ok;
});
it('is transpiled correctly with visitors', function () {
let transpilerOut = tspoon.transpile(sourceCode, config);
let TwoNames = evaluateModuleExports(transpilerOut.code)['TwoNames'];
let instance = new TwoNames();
expect(transpilerOut.halted).not.to.be.ok;
expect(instance.publicName, 'publicName').to.eql('Doe');
expect(instance.privateName, 'privateName').to.eql('John');
});
it('is transpiled correctly with visitors', function() {
let transpilerOut = tspoon.transpile(sourceCode, config);
let TwoNames = evaluateModuleExports(transpilerOut.code)['TwoNames'];
let instance = new TwoNames();
expect(transpilerOut.halted).not.to.be.ok;
expect(instance.publicName, 'publicName').to.eql('Doe');
expect(instance.privateName, 'privateName').to.eql('John');
});
it('is transpiled with two diagnostics', function () {
expect(tspoon.transpile(sourceCode, config).diags.length).to.eql(2);
});
it('is transpiled with two diagnostics', function() {
expect(tspoon.transpile(sourceCode, config).diags.length).to.eql(2);
});
});
import {expect} from 'chai';
import * as ts from 'typescript';
import * as tspoon from '../src/index';
import * as ts from 'typescript';
import {ValidatorConfig} from "../src/transpile";
import {VisitorContext} from "../index";
import {Visitor} from "../src/visitor";
import {MockModule} from "../test-kit/mocks/resolution-hosts";
import {ValidatorConfig} from '../src/transpile';
import {VisitorContext} from '../index';
import {Visitor} from '../src/visitor';
import {MockModule} from '../test-kit/mocks/resolution-hosts';
function beforeVariable(varName: string) {
return {
insert(code: string): Visitor {
return {
filter: (node:ts.Node) => {
if (node.kind === ts.SyntaxKind.VariableDeclarationList) {
const declList = <ts.VariableDeclarationList>node;
return declList.declarations.some((decl:ts.VariableDeclaration) => decl.name.getText() === varName);
}
return false;
},
return {
insert(code: string): Visitor {
return {
filter: (node: ts.Node) => {
if (node.kind === ts.SyntaxKind.VariableDeclarationList) {
const declList = <ts.VariableDeclarationList>node;
return declList.declarations.some((decl: ts.VariableDeclaration) => decl.name.getText() === varName);
}
return false;
},
visit: (node:ts.Node, context:VisitorContext) => {
context.insertLine(node.pos, code);
}
}
}
}
visit: (node: ts.Node, context: VisitorContext) => {
context.insertLine(node.pos, code);
}
}
}
}
}
describe('tspoon.validateAll()', function () {
it("lets valid code pass", function () {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', 'export const perfectlyValid: number = 666;'),
new MockModule('index2.ts', 'export const perfectlyValid2: number = 777;')
]
};
expect(tspoon.validateAll(['index.ts', 'index2.ts'], config)).to.pass();
});
describe('tspoon.validateAll()', function() {
it('lets valid code pass', function() {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', 'export const perfectlyValid: number = 666;'),
new MockModule('index2.ts', 'export const perfectlyValid2: number = 777;')
]
};
expect(tspoon.validateAll(['index.ts', 'index2.ts'], config)).to.pass();
});
it("makes invalid code fail", function () {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', 'export const perfectlyValid: number = 666;'),
new MockModule('index2.ts', `// This comment here
it('makes invalid code fail', function() {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', 'export const perfectlyValid: number = 666;'),
new MockModule('index2.ts', `// This comment here
// is just
// to add some lines
export const perfectlyValid: number = 666;
export const perfectlyInvalid: SomeUndefinedType = "HAHAHA";
export const perfectlyInvalid: SomeUndefinedType = 'HAHAHA';
`)
]
};
expect(tspoon.validateAll(['index.ts', 'index2.ts'], config)).to.fail()
.withMessageCount(1)
.withMessage(/index2.ts -> 5:\d+ Cannot find name 'SomeUndefinedType'./);
});
]
};
expect(tspoon.validateAll(['index.ts', 'index2.ts'], config)).to.fail()
.withMessageCount(1)
.withMessage(/index2.ts -> 5:\d+ Cannot find name 'SomeUndefinedType'./);
});
it("lets invalid code that was fixed by a visitor pass", function () {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
it('lets invalid code that was fixed by a visitor pass', function() {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
// This comment here

@@ -65,17 +65,17 @@ // is just

const perfectlyValid: number = 666;
const perfectlyInvalid: SomeUndefinedType = "HAHAHA";
const perfectlyInvalid: SomeUndefinedType = 'HAHAHA';
`)
],
],
mutators: [
beforeVariable('perfectlyInvalid').insert('\ntype SomeUndefinedType = string;')
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.pass();
});
mutators: [
beforeVariable('perfectlyInvalid').insert('\ntype SomeUndefinedType = string;')
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.pass();
});
it("preserves error lines despite the modifications", function () {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', ` // line 1
it('preserves error lines despite the modifications', function() {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', ` // line 1
// This comment here // line 2

@@ -85,102 +85,101 @@ // is just // line 3

const perfectlyValid: number = 666; // line 5
const perfectlyInvalid: SomeUndefinedType = "HAHAHA"; // line 6
const perfectlyInvalid: SomeUndefinedType = 'HAHAHA'; // line 6
`)
],
mutators: [
beforeVariable('perfectlyInvalid').insert('\nconst anotherValidLine: number = 777;')
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.fail()
.withMessageCount(1)
.withMessage(/.* -> 6:\d+ Cannot find name 'SomeUndefinedType'./);
});
],
mutators: [
beforeVariable('perfectlyInvalid').insert('\nconst anotherValidLine: number = 777;')
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.fail()
.withMessageCount(1)
.withMessage(/.* -> 6:\d+ Cannot find name 'SomeUndefinedType'./);
});
it("modifies a dependency of the validated file", function () {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
it('modifies a dependency of the validated file', function() {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
import Product from './Product';
const product: Product = { title: 'Sample' };
`),
new MockModule('Product.ts', `
new MockModule('Product.ts', `
interface Product { title: string; }
const somethingUnrelated: string = 'what?';
`)
],
mutators: [
beforeVariable('somethingUnrelated').insert('export default Product;')
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.pass();
});
],
mutators: [
beforeVariable('somethingUnrelated').insert('export default Product;')
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.pass();
});
it("fails gracefully with syntactically incorrect input", function () {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
it('fails gracefully with syntactically incorrect input', function() {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
import {Product} from './Product';
const product: Product = { title: 'Sample'
`),
new MockModule('Product.ts', `
new MockModule('Product.ts', `
export class Product { title: string; }
const somethingUnrelated: string = 'what?';
`)
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.fail()
.withMessage(/index.ts -> \d+:\d+ '}' expected./);
});
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.fail()
.withMessage(/index.ts -> \d+:\d+ '}' expected./);
});
it("fails gracefully with syntactically incorrect dependency", function () {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
it('fails gracefully with syntactically incorrect dependency', function() {
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('index.ts', `
import {Product} from './Product';
const product: Product = { title: 'Sample' }
`),
new MockModule('Product.ts', `
new MockModule('Product.ts', `
export class Product { title: string; }
const somethingUnrelated: string = 'what?
`)
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.fail()
.withMessage(/Product.ts -> \d+:\d+ Unterminated string literal./);
});
]
};
expect(tspoon.validateAll(['index.ts'], config)).to.fail()
.withMessage(/Product.ts -> \d+:\d+ Unterminated string literal./);
});
it("can access semantic information", function () {
this.timeout(10000);
class MockVisitor implements Visitor {
public realTypeName: string;
it('can access semantic information', function() {
this.timeout(10000);
class MockVisitor implements Visitor {
public realTypeName: string;
filter(node:ts.Node): boolean {
return node.getSourceFile().fileName === 'index.ts' && node.kind === ts.SyntaxKind.VariableDeclaration;
}
filter(node: ts.Node): boolean {
return node.getSourceFile().fileName === 'index.ts' && node.kind === ts.SyntaxKind.VariableDeclaration;
}
visit(node:ts.Node, context:VisitorContext): void {
const ls: ts.LanguageService = context.getLanguageService();
const x = ls.getTypeDefinitionAtPosition(node.getSourceFile().fileName, node.getStart());
this.realTypeName = x[0].name;
}
}
const visitor = new MockVisitor();
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('a.ts', `
visit(node: ts.Node, context: VisitorContext): void {
const ls: ts.LanguageService = context.getLanguageService();
const x = ls.getTypeDefinitionAtPosition(node.getSourceFile().fileName, node.getStart());
this.realTypeName = x[0].name;
}
}
const visitor = new MockVisitor();
const config: ValidatorConfig = {
resolutionHosts: [
new MockModule('a.ts', `
export default class Product {}
`),
new MockModule('index.ts', `
new MockModule('index.ts', `
import {default as SomeClass} from './a';
const a: SomeClass = null;
`),
new MockModule("lib.d.ts", require('typescript/lib/lib.d.ts'))
],
mutators: [
visitor
]
};
tspoon.validateAll(['index.ts'], config);
expect(visitor.realTypeName).to.equal('Product');
});
new MockModule('lib.d.ts', require('typescript/lib/lib.d.ts'))
],
mutators: [
visitor
]
};
tspoon.validateAll(['index.ts'], config);
expect(visitor.realTypeName).to.equal('Product');
});
});

@@ -1,11 +0,11 @@

/// <reference path="../typings/main.d.ts" />
/// <reference path='../typings/main.d.ts' />
require('source-map-support').install();
import "./mutable-source-code.spec";
import "./transpile.spec";
import "./visitor.spec";
import "./transpile.spec";
import "./e2e.validate-all.spec";
import "./e2e.example-poc.spec";
import "./e2e.example-readme.spec";
import './mutable-source-code.spec';
import './transpile.spec';
import './visitor.spec';
import './transpile.spec';
import './e2e.validate-all.spec';
import './e2e.example-poc.spec';
import './e2e.example-readme.spec';

@@ -1,75 +0,68 @@

/// <reference path="../typings/main.d.ts" />
import {expect} from 'chai';
import * as ts from 'typescript';
import {MutableSourceCode} from '../src/mutable-source-code';
import {defaultCompilerOptions} from '../src/configuration';
import {FastAppendAction, FastRewriteAction, ReplaceAction, InsertAction} from '../src/mutable-source-code';
import { expect } from 'chai';
import * as ts from "typescript";
import { MutableSourceCode, } from "../src/mutable-source-code";
import { defaultCompilerOptions } from '../src/configuration';
import {FastAppendAction, FastRewriteAction, ReplaceAction, InsertAction} from "../src/mutable-source-code";
function aSourceMapperFor(source: string): MutableSourceCode {
const ast = ts.createSourceFile("test.ts", source, defaultCompilerOptions.target, true);
return new MutableSourceCode(ast);
const ast = ts.createSourceFile('test.ts', source, defaultCompilerOptions.target, true);
return new MutableSourceCode(ast);
}
describe("Mutable source actions performs", function () {
it("FastAppendAction at the end of source", ()=> {
const source = "const someCode = 'Some string';";
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([ new FastAppendAction('const b = 666;')]);
expect(mutableCode.code).to.equal("const someCode = 'Some string';const b = 666;");
});
describe('Mutable source actions performs', function() {
it('FastAppendAction at the end of source', () => {
const source = `const someCode = 'Some string';`;
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([new FastAppendAction('const b = 666;')]);
expect(mutableCode.code).to.equal(`const someCode = 'Some string';const b = 666;`);
});
it("FastRewriteAction", function () {
const source = "const someCode = 'Some string';";
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([ new FastRewriteAction(18, 'XXXXXXXXXXX')]);
expect(mutableCode.code).to.equal("const someCode = 'XXXXXXXXXXX';");
});
it('FastRewriteAction', function() {
const source = `const someCode = 'Some string';`;
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([new FastRewriteAction(18, 'XXXXXXXXXXX')]);
expect(mutableCode.code).to.equal(`const someCode = 'XXXXXXXXXXX';`);
});
it("ReplaceAction - replace style", function () {
const source = "const someCode = 'Some string';";
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([ new ReplaceAction(6, 30, 'b = 666')]);
expect(mutableCode.code).to.equal("const b = 666;");
});
it('ReplaceAction - replace style', function() {
const source = `const someCode = 'Some string';`;
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([new ReplaceAction(6, 30, 'b = 666')]);
expect(mutableCode.code).to.equal('const b = 666;');
});
it("InsertAction", function () {
const source = "const someCode = 'Some string';";
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([ new InsertAction(6, '__')]);
expect(mutableCode.code).to.equal("const __someCode = 'Some string';");
});
it('InsertAction', function() {
const source = `const someCode = 'Some string';`;
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([new InsertAction(6, '__')]);
expect(mutableCode.code).to.equal(`const __someCode = 'Some string';`);
});
it("InsertAction (beginning)", function () {
const source = "const someCode = 'Some string';";
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([ new InsertAction(0, '__')]);
expect(mutableCode.code).to.equal("__const someCode = 'Some string';");
});
it('InsertAction (beginning)', function() {
const source = `const someCode = 'Some string';`;
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([new InsertAction(0, '__')]);
expect(mutableCode.code).to.equal(`__const someCode = 'Some string';`);
});
it("several actions in sequence", function () {
const source = "const someCode = 'Some string';";
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([
new ReplaceAction(6, 6, '__'),
new FastAppendAction('const b = 666;'),
new FastRewriteAction(18, 'XXXXXXXXXXX')
]);
expect(mutableCode.code).to.equal("const __someCode = 'XXXXXXXXXXX';const b = 666;");
})
it('several actions in sequence', function() {
const source = `const someCode = 'Some string';`;
// 0123456789012345678901234567890
// 1 2 3
const mutableCode = aSourceMapperFor(source);
mutableCode.execute([
new ReplaceAction(6, 6, '__'),
new FastAppendAction('const b = 666;'),
new FastRewriteAction(18, 'XXXXXXXXXXX')
]);
expect(mutableCode.code).to.equal(`const __someCode = 'XXXXXXXXXXX';const b = 666;`);
})
});

@@ -1,56 +0,53 @@

/// <reference path="../typings/main.d.ts" />
import {expect} from 'chai';
import * as ts from 'typescript';
import {MutableSourceCode, ReplaceAction, Action} from '../src/mutable-source-code';
import {traverseAst} from '../src/traverse-ast';
import {findCodeRange, findCodePosition} from '../test-kit/index';
import {SingleFileHost} from '../src/hosts';
import {defaultCompilerOptions} from '../src/configuration';
import {RawSourceMap, SourceMapConsumer, SourceMapGenerator} from 'source-map';
import { expect } from 'chai';
import * as chai from "chai";
import * as ts from "typescript";
import { MutableSourceCode, ReplaceAction, Action} from "../src/mutable-source-code";
import { traverseAst } from '../src/traverse-ast';
import { findCodeRange, findCodePosition } from "../test-kit/index";
import { SingleFileHost } from '../src/hosts';
import { defaultCompilerOptions } from '../src/configuration';
import { RawSourceMap, SourceMapConsumer, SourceMapGenerator } from 'source-map';
function makeReplacement(source: string, atStr: string, insStr: string): Action {
const textRange = findCodeRange(source, atStr);
return new ReplaceAction(textRange.pos, textRange.end, insStr);
const textRange = findCodeRange(source, atStr);
return new ReplaceAction(textRange.pos, textRange.end, insStr);
}
function makeLineInsersion(source: string, atStr: string, insStr: string): Action {
const textRange = findCodeRange(source, atStr);
return new ReplaceAction(textRange.pos, textRange.pos, insStr + "\n");
const textRange = findCodeRange(source, atStr);
return new ReplaceAction(textRange.pos, textRange.pos, insStr + '\n');
}
function aSourceMapperFor(source: string): MutableSourceCode {
const ast = ts.createSourceFile("test.ts", source, defaultCompilerOptions.target, true);
return new MutableSourceCode(ast);
const ast = ts.createSourceFile('test.ts', source, defaultCompilerOptions.target, true);
return new MutableSourceCode(ast);
}
function expectSourceMapToMatchChangeForSuppliedText(source: string, target: string, sourceMap: RawSourceMap, text: string) {
const positionBeforeChange: SourceMap.Position = findCodePosition(source, text);
const positionAfterChange: SourceMap.Position = findCodePosition(target, text);
const mapConsumer = new SourceMapConsumer(sourceMap);
const mappedPosition: SourceMap.Position = mapConsumer.originalPositionFor(positionAfterChange);
expect({ line: mappedPosition.line, column: mappedPosition.column })
.to.eql({ line: positionBeforeChange.line, column: positionBeforeChange.column });
const positionBeforeChange: SourceMap.Position = findCodePosition(source, text);
const positionAfterChange: SourceMap.Position = findCodePosition(target, text);
const mapConsumer = new SourceMapConsumer(sourceMap);
const mappedPosition: SourceMap.Position = mapConsumer.originalPositionFor(positionAfterChange);
expect({ line: mappedPosition.line, column: mappedPosition.column })
.to.eql({ line: positionBeforeChange.line, column: positionBeforeChange.column });
}
function transpile(source: string): { code: string, map: RawSourceMap } {
const ast = ts.createSourceFile("test.ts", source, defaultCompilerOptions.target, true);
const compilerHost = new SingleFileHost(ast);
const program = ts.createProgram(["test.ts"], defaultCompilerOptions, compilerHost);
program.emit();
return {
code: compilerHost.output,
map: compilerHost.sourceMap
};
const ast = ts.createSourceFile('test.ts', source, defaultCompilerOptions.target, true);
const compilerHost = new SingleFileHost(ast);
const program = ts.createProgram(['test.ts'], defaultCompilerOptions, compilerHost);
program.emit();
return {
code: compilerHost.output,
map: compilerHost.sourceMap
};
}
describe("given a source code and given a replacement command, sourcemapper should", ()=> {
describe('given a source code and given a replacement command, sourcemapper should', () => {
const source = `class A {}
const source = `class A {}
PLACE_HOLDERclass B {}
fubar();`;
const target = `class A {}
const target = `class A {}
@bar

@@ -61,36 +58,34 @@ @foo

const action1 = makeLineInsersion(source, "PLACE_HOLDER", "@bar");
const action2 = makeReplacement(source, "PLACE_HOLDER", "@foo\n");
// adding action3 demonstrates problems with making changes based on a text after that text has been replaced (see action2).
// using the next versin of magic-string may solve this
// const action3 = makeLineInsersion(source, "PLACE_HOLDER", "\n@baz");
// mutableCode.execute([action1, action2 /*, action3*/]);
const action1 = makeLineInsersion(source, 'PLACE_HOLDER', '@bar');
const action2 = makeReplacement(source, 'PLACE_HOLDER', '@foo\n');
// adding action3 demonstrates problems with making changes based on a text after that text has been replaced (see action2).
// using the next versin of magic-string may solve this
// const action3 = makeLineInsersion(source, 'PLACE_HOLDER', '\n@baz');
// mutableCode.execute([action1, action2 /*, action3*/]);
var mutableCode;
beforeEach(() =>{
mutableCode = aSourceMapperFor(source);
var mutableCode;
beforeEach(() => {
mutableCode = aSourceMapperFor(source);
});
});
it("generate a new string that matches the expected target", ()=> {
mutableCode.execute([action1, action2 /*, action3*/]);
it('generate a new string that matches the expected target', () => {
mutableCode.execute([action1, action2 /*, action3*/]);
expect(mutableCode.code).to.equal(target);
});
expect(mutableCode.code).to.equal(target);
});
it("generate correct sourcemap that reflects the changes", ()=> {
mutableCode.execute([action1, action2 /*, action3*/]);
it('generate correct sourcemap that reflects the changes', () => {
mutableCode.execute([action1, action2 /*, action3*/]);
expectSourceMapToMatchChangeForSuppliedText(source, mutableCode.code, mutableCode.sourceMap, "class B");
});
expectSourceMapToMatchChangeForSuppliedText(source, mutableCode.code, mutableCode.sourceMap, 'class B');
});
it("map the changes onto a sourcemap generated by typescript", ()=> {
mutableCode.execute([action1, action2 /*, action3*/]);
it('map the changes onto a sourcemap generated by typescript', () => {
mutableCode.execute([action1, action2 /*, action3*/]);
var result = transpile(mutableCode.code);
const sourceMap = mutableCode.translateMap(result.map);
expectSourceMapToMatchChangeForSuppliedText(source, result.code, sourceMap, "fubar()");
});
var result = transpile(mutableCode.code);
const sourceMap = mutableCode.translateMap(result.map);
expectSourceMapToMatchChangeForSuppliedText(source, result.code, sourceMap, 'fubar()');
});
});

@@ -1,73 +0,70 @@

/// <reference path="../typings/main.d.ts" />
import {expect} from 'chai';
import {Node, Decorator, ClassDeclaration, SyntaxKind, CompilerOptions} from 'typescript';
import * as _ from 'lodash';
import {transpile, TranspilerConfig, VisitorContext} from '../src';
import { Node, Decorator, ClassDeclaration, SyntaxKind } from 'typescript';
import { CompilerOptions } from 'typescript';
import * as _ from 'lodash';
const config: TranspilerConfig = {
sourceFileName: 'sample.tsx',
visitors: []
sourceFileName: 'sample.tsx',
visitors: []
};
describe('transpiler', function () {
it('fails on parser errors', function () {
const source = 'let a = <div><div></div>;';
const transpiled = transpile(source, config);
expect(transpiled.code).not.to.be.ok;
expect(transpiled.diags).not.to.be.empty;
});
describe('transpiler', function() {
it('fails on parser errors', function() {
const source = 'let a = <div><div></div>;';
const transpiled = transpile(source, config);
expect(transpiled.code).not.to.be.ok;
expect(transpiled.diags).not.to.be.empty;
});
describe('e2e regression test', ()=> {
describe('e2e regression test', () => {
const config2: TranspilerConfig = {
compilerOptions : <CompilerOptions>{
inlineSourceMap : false,
sourceMap: true,
inlineSources : false,
noEmitHelpers: false
},
sourceFileName: 'sample.tsx',
visitors: [{
filter: function(node: Node): boolean {
return node.kind == SyntaxKind.ClassDeclaration && node.decorators && node.decorators.length > 0;
},
const config2: TranspilerConfig = {
compilerOptions: <CompilerOptions>{
inlineSourceMap: false,
sourceMap: true,
inlineSources: false,
noEmitHelpers: false
},
sourceFileName: 'sample.tsx',
visitors: [{
filter: function(node: Node): boolean {
return node.kind == SyntaxKind.ClassDeclaration && node.decorators && node.decorators.length > 0;
},
visit: function(node: Node, context: VisitorContext): void {
let targetPosition: number = node.pos;
const classNode: ClassDeclaration = <ClassDeclaration> node;
if(!_.isEmpty(classNode.decorators)) {
targetPosition = (<Decorator>_.last(classNode.decorators)).end + 1;
}
// console.log("targetPosition", targetPosition);
context.insertLine(targetPosition, `@fooo(\`------------------------
"tags": ["@type"],
"properties": [
visit: function(node: Node, context: VisitorContext): void {
let targetPosition: number = node.pos;
const classNode: ClassDeclaration = <ClassDeclaration>node;
if (!_.isEmpty(classNode.decorators)) {
targetPosition = (<Decorator>_.last(classNode.decorators)).end + 1;
}
// console.log('targetPosition', targetPosition);
context.insertLine(targetPosition, `@fooo(\`------------------------
'tags': ['@type'],
'properties': [
{
"name": "title",
"type": "core3.types.String"
'name': 'title',
'type': 'core3.types.String'
},
{
"name": "price",
"type": "core3.types.Number"
'name': 'price',
'type': 'core3.types.Number'
},
{
"name": "flag",
"type": "core3.types.Boolean"
'name': 'flag',
'type': 'core3.types.Boolean'
},
{
"name": "func",
"type": "core3.types.Function"
'name': 'func',
'type': 'core3.types.Function'
}
],
"methods": []
'methods': []
\`)`);
}
}]
};
}
}]
};
it('checks sample code doesn\'t get garbled up the same way it once did', () => {
const source = `
/// <reference path="../../../typings/tsd.d.ts"/>
it('checks sample code doesn\'t get garbled up the same way it once did', () => {
const source = `
/// <reference path='../../../typings/tsd.d.ts'/>

@@ -129,7 +126,7 @@ function bar(){

`;
const transpiled = transpile(source, config2);
expect(() => eval(transpiled.code)).not.to.throw();
});
});
const transpiled = transpile(source, config2);
expect(() => eval(transpiled.code)).not.to.throw();
});
});
});

@@ -1,15 +0,12 @@

/// <reference path="../typings/main.d.ts" />
import * as ts from 'typescript';
import {expect} from 'chai';
import {findCodeRange, findCodePosition} from '../test-kit/index';
import {defaultCompilerOptions} from '../src/configuration';
import {Visitor, VisitorContext, transpile, TranspilerOutput} from '../src/index';
import {traverseAst} from '../src/traverse-ast';
import {TranspilerContext} from '../src/transpiler-context';
import {MutableSourceCode} from '../src/mutable-source-code';
import { expect } from 'chai';
import * as chai from "chai";
import * as ts from "typescript";
import { findCodeRange, findCodePosition } from "../test-kit/index";
import { defaultCompilerOptions } from '../src/configuration';
import { Visitor, VisitorContext, transpile, TranspilerOutput } from "../src/index";
import { traverseAst } from "../src/traverse-ast";
import { TranspilerContext } from "../src/transpiler-context";
import { MutableSourceCode } from "../src/mutable-source-code";
function applyVisitor(source: string, visitor: Visitor): TranspilerOutput {
const ast = ts.createSourceFile("test.ts", source, defaultCompilerOptions.target, true);
const ast = ts.createSourceFile('test.ts', source, defaultCompilerOptions.target, true);
let context: TranspilerContext = new TranspilerContext(ast.fileName);

@@ -28,3 +25,3 @@ traverseAst(ast, visitor, context);

function matchDiagRanges(expected: ts.TextRange, actual: ts.Diagnostic): void {
chai.expect({
expect({
start: expected.pos,

@@ -38,79 +35,77 @@ end: expected.end

describe("given source code", function () {
describe('given source code', function() {
describe("and a simple visitor, transpiler should", function () {
const source = "\nclass A {}\nclass B {}\n";
describe('and a simple visitor, transpiler should', function() {
const source = '\nclass A {}\nclass B {}\n';
const fakeVisitor: Visitor = {
filter: (node: ts.Node): boolean => {
return node.kind == ts.SyntaxKind.ClassDeclaration;
},
visit: (node: ts.Node, context: VisitorContext): void => {
context.insertLine(node.getStart(), "@blah");
context.replace(node.getStart(), node.getStart() + 'class'.length, "interface");
context.reportDiag(node, ts.DiagnosticCategory.Error, "Test message");
}
};
const fakeVisitor: Visitor = {
filter: (node: ts.Node): boolean => {
return node.kind == ts.SyntaxKind.ClassDeclaration;
},
visit: (node: ts.Node, context: VisitorContext): void => {
context.insertLine(node.getStart(), '@blah');
context.replace(node.getStart(), node.getStart() + 'class'.length, 'interface');
context.reportDiag(node, ts.DiagnosticCategory.Error, 'Test message');
}
};
let postVisitorOutput;
let postVisitorOutput;
beforeEach(()=>{
postVisitorOutput = applyVisitor(source, fakeVisitor);
});
beforeEach(() => {
postVisitorOutput = applyVisitor(source, fakeVisitor);
});
const target = "\n@blah\ninterface A {}\n@blah\ninterface B {}\n";
const target = '\n@blah\ninterface A {}\n@blah\ninterface B {}\n';
it("generate the correct intermediate code", function () {
chai.expect(postVisitorOutput.code).to.equal(target);
});
it('generate the correct intermediate code', function() {
expect(postVisitorOutput.code).to.equal(target);
});
it("give correct diag positions", ()=> {
it('give correct diag positions', () => {
chai.expect(postVisitorOutput.diags).to.have.length(2);
expect(postVisitorOutput.diags).to.have.length(2);
matchDiagRanges(
findCodeRange(source, "class A {}"),
postVisitorOutput.diags[0]);
matchDiagRanges(
findCodeRange(source, 'class A {}'),
postVisitorOutput.diags[0]);
matchDiagRanges(
findCodeRange(source, "class B {}"),
postVisitorOutput.diags[1]);
});
});
matchDiagRanges(
findCodeRange(source, 'class B {}'),
postVisitorOutput.diags[1]);
});
});
describe("and a recursive visitor, transpiler should", function () {
const source = "class A { methodA() {} }\nclass B { methodB() {} }";
describe('and a recursive visitor, transpiler should', function() {
const source = 'class A { methodA() {} }\nclass B { methodB() {} }';
const subVisitor: Visitor = {
filter: (node:ts.Node):boolean => {
return node.kind == ts.SyntaxKind.MethodDeclaration;
},
visit: (node:ts.Node, context:VisitorContext):void => {
context.insertLine(node.getStart(), "@blah");
}
};
const subVisitor: Visitor = {
filter: (node: ts.Node): boolean => {
return node.kind == ts.SyntaxKind.MethodDeclaration;
},
visit: (node: ts.Node, context: VisitorContext): void => {
context.insertLine(node.getStart(), '@blah');
}
};
const fakeVisitor: Visitor = {
filter: (node: ts.Node): boolean => {
return node.kind == ts.SyntaxKind.ClassDeclaration;
},
visit: (node: ts.Node, context: VisitorContext, traverse: (...visitors: Visitor[])=> void): void => {
traverse(subVisitor);
}
};
const fakeVisitor: Visitor = {
filter: (node: ts.Node): boolean => {
return node.kind == ts.SyntaxKind.ClassDeclaration;
},
visit: (node: ts.Node, context: VisitorContext, traverse: (...visitors: Visitor[]) => void): void => {
traverse(subVisitor);
}
};
let postVisitorOutput;
let postVisitorOutput;
beforeEach(()=>{
postVisitorOutput = applyVisitor(source, fakeVisitor);
});
beforeEach(() => {
postVisitorOutput = applyVisitor(source, fakeVisitor);
});
it("generate the correct intermediate code", function () {
chai.expect(postVisitorOutput.code).to.equal(
"class A { @blah\nmethodA() {} }\nclass B { @blah\nmethodB() {} }"
);
});
});
it('generate the correct intermediate code', function() {
expect(postVisitorOutput.code).to.equal(
'class A { @blah\nmethodA() {} }\nclass B { @blah\nmethodB() {} }'
);
});
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc