Socket
Socket
Sign inDemoInstall

tsickle

Package Overview
Dependencies
Maintainers
2
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tsickle - npm Package Compare versions

Comparing version 0.1.7 to 0.2.0

.vscode/.browse.VC.db

6

.vscode/launch.json

@@ -8,3 +8,3 @@ {

"request": "launch",
"program": "${workspaceRoot}/node_modules/gulp-mocha/node_modules/mocha/bin/_mocha",
"program": "${workspaceRoot}/node_modules/.bin/_mocha",
"args": [

@@ -22,3 +22,3 @@ "--colors",

},
"externalConsole": false,
"console": "internalConsole",
"sourceMaps": true,

@@ -28,2 +28,2 @@ "outDir": "${workspaceRoot}/build"

]
}
}

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";

@@ -5,6 +12,11 @@ var path = require('path');

function pathToModuleName(context, fileName) {
fileName = fileName.replace(/\.js$/, '');
if (fileName[0] === '.') {
// './foo' or '../foo'.
// Resolve the path against the dirname of the current module.
fileName = path.join(path.dirname(context), fileName);
}
return fileName.replace(/\.js$/, '').replace(/\//g, '.');
// Replace characters not supported by goog.module.
var moduleName = fileName.replace(/\//g, '.').replace(/^[^a-zA-Z_$]/, '_').replace(/[^a-zA-Z0-9._$]/g, '_');
return moduleName;
}

@@ -11,0 +23,0 @@ exports.pathToModuleName = pathToModuleName;

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";

@@ -47,3 +54,6 @@ var __extends = (this && this.__extends) || function (d, b) {

var _this = this;
return (n.decorators || []).filter(function (d) { return _this.shouldLower(d); });
if (n.decorators) {
return n.decorators.filter(function (d) { return _this.shouldLower(d); });
}
return [];
};

@@ -50,0 +60,0 @@ /**

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";

@@ -17,6 +24,5 @@ var __extends = (this && this.__extends) || function (d, b) {

__extends(ES5Processor, _super);
function ES5Processor(file, pathToModuleName, isES5) {
function ES5Processor(file, pathToModuleName) {
_super.call(this, file);
this.pathToModuleName = pathToModuleName;
this.isES5 = isES5;
/**

@@ -44,3 +50,3 @@ * namespaceImports collects the variables for imported goog.modules.

}
ES5Processor.prototype.process = function () {
ES5Processor.prototype.process = function (moduleId, isES5) {
// TODO(evanm): only emit the goog.module *after* the first comment,

@@ -56,7 +62,7 @@ // so that @suppress statements work.

// optimizations mode.
if (this.isES5) {
this.emit("var module = module || {id: '" + this.file.fileName + "'};");
if (isES5) {
this.emit("var module = module || {id: '" + moduleId + "'};");
}
else {
this.emit("var module = {id: '" + this.file.fileName + "'};");
this.emit("var module = {id: '" + moduleId + "'};");
}

@@ -224,7 +230,4 @@ var pos = 0;

this.namespaceImports.add(varName);
if (this.moduleVariables.has(modName)) {
this.emit("var " + varName + " = " + this.moduleVariables.get(modName) + ";");
}
else {
this.emit("var " + varName + " = goog.require('" + modName + "');");
this.emit("var " + varName + " = goog.require('" + modName + "');");
if (!this.moduleVariables.has(modName)) {
this.moduleVariables.set(modName, varName);

@@ -301,3 +304,5 @@ }

/** Generates a new variable name inside the tsickle_ namespace. */
ES5Processor.prototype.generateFreshVariableName = function () { return "tsickle_module_" + this.unusedIndex++ + "_"; };
ES5Processor.prototype.generateFreshVariableName = function () {
return "tsickle_module_" + this.unusedIndex++ + "_";
};
return ES5Processor;

@@ -309,3 +314,5 @@ }(rewriter_1.Rewriter));

*
* @param fileName The source file name, without an extension.
* @param fileName The source file name.
* @param moduleId The "module id", a module-identifying string that is
* the value module.id in the scope of the module.
* @param pathToModuleName A function that maps a filesystem .ts path to a

@@ -316,6 +323,6 @@ * Closure module name, as found in a goog.require('...') statement.

*/
function processES5(fileName, content, pathToModuleName, isES5) {
function processES5(fileName, moduleId, content, pathToModuleName, isES5) {
if (isES5 === void 0) { isES5 = true; }
var file = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, true);
return new ES5Processor(file, pathToModuleName, isES5).process();
return new ES5Processor(file, pathToModuleName).process(moduleId, isES5);
}

@@ -322,0 +329,0 @@ exports.processES5 = processES5;

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";

@@ -171,2 +178,4 @@ function arrayIncludes(array, key) {

function toString(tags) {
if (tags.length === 0)
return '';
var out = '';

@@ -173,0 +182,0 @@ out += '/**\n';

@@ -139,3 +139,5 @@ #!/usr/bin/env node

logWarning: settings.verbose ?
function (warning) { console.error(tsickle.formatDiagnostics([warning])); } :
function (warning) {
console.error(tsickle.formatDiagnostics([warning]));
} :
undefined,

@@ -162,11 +164,8 @@ };

program = ts.createProgram(fileNames, options, host);
var diagnostics = ts.getPreEmitDiagnostics(program);
if (diagnostics.length > 0) {
allDiagnostics.push.apply(allDiagnostics, diagnostics);
return null;
}
// Emit, creating a map of fileName => generated JS source.
var jsFiles = new Map();
function writeFile(fileName, data) { jsFiles.set(fileName, data); }
(_b = program.emit(undefined, writeFile), diagnostics = _b.diagnostics, _b);
function writeFile(fileName, data) {
jsFiles.set(fileName, data);
}
var diagnostics = program.emit(undefined, writeFile).diagnostics;
if (diagnostics.length > 0) {

@@ -176,6 +175,7 @@ allDiagnostics.push.apply(allDiagnostics, diagnostics);

}
for (var _c = 0, _d = util_1.toArray(jsFiles.keys()); _c < _d.length; _c++) {
var fileName = _d[_c];
for (var _b = 0, _c = util_1.toArray(jsFiles.keys()); _b < _c.length; _b++) {
var fileName = _c[_b];
if (path.extname(fileName) !== '.map') {
var output = tsickle.convertCommonJsToGoogModule(fileName, jsFiles.get(fileName), cliSupport.pathToModuleName).output;
var moduleId = fileName; // TODO: does anyone use this?
var output = tsickle.processES5(fileName, moduleId, jsFiles.get(fileName), cliSupport.pathToModuleName).output;
jsFiles.set(fileName, output);

@@ -185,3 +185,2 @@ }

return { jsFiles: jsFiles, externs: tsickleExterns };
var _b;
}

@@ -188,0 +187,0 @@ function main(args) {

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";
var source_map_1 = require('source-map');
var ts = require('typescript');

@@ -14,2 +22,6 @@ /**

this.diagnostics = [];
/** The source map that's generated while rewriting this file. */
this.sourceMap = new source_map_1.SourceMapGenerator();
/** Current position in the output. */
this.position = { line: 1, column: 1 };
/**

@@ -20,2 +32,7 @@ * The current level of recursion through TypeScript Nodes. Used in formatting internal debug

this.indent = 0;
this.sourceMap.addMapping({
original: this.position,
generated: this.position,
source: file.fileName,
});
}

@@ -26,3 +43,7 @@ Rewriter.prototype.getOutput = function () {

}
return { output: this.output.join(''), diagnostics: this.diagnostics };
return {
output: this.output.join(''),
diagnostics: this.diagnostics,
sourceMap: this.sourceMap,
};
};

@@ -46,3 +67,5 @@ /**

*/
Rewriter.prototype.maybeProcess = function (node) { return false; };
Rewriter.prototype.maybeProcess = function (node) {
return false;
};
/** writeNode writes a ts.Node, calling this.visit() on its children. */

@@ -80,6 +103,29 @@ Rewriter.prototype.writeNode = function (node, skipComments) {

var text = this.file.text.slice(from, to);
if (text)
if (text) {
// Add a source mapping. writeRange(from, to) always corresponds to
// original source code, so add a mapping at the current location that
// points back to the location at `from`. The additional code generated
// by tsickle will then be considered part of the last mapped code
// section preceding it. That's arguably incorrect (e.g. for the fake
// methods defining properties), but is good enough for stack traces.
var pos = this.file.getLineAndCharacterOfPosition(from);
this.sourceMap.addMapping({
original: { line: pos.line + 1, column: pos.character + 1 },
generated: this.position,
source: this.file.fileName,
});
this.emit(text);
}
};
Rewriter.prototype.emit = function (str) { this.output.push(str); };
Rewriter.prototype.emit = function (str) {
this.output.push(str);
for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
var c = str_1[_i];
this.position.column++;
if (c === '\n') {
this.position.line++;
this.position.column = 1;
}
}
};
/** Removes comment metacharacters from a string, to make it safe to embed in a comment. */

@@ -86,0 +132,0 @@ Rewriter.prototype.escapeForComment = function (str) {

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";

@@ -15,3 +22,3 @@ var __extends = (this && this.__extends) || function (d, b) {

var es5processor_1 = require('./es5processor');
exports.convertCommonJsToGoogModule = es5processor_1.processES5;
exports.processES5 = es5processor_1.processES5;
/**

@@ -43,2 +50,35 @@ * Symbols that are already declared as externs in Closure, that should

exports.formatDiagnostics = formatDiagnostics;
/**
* TypeScript allows you to write identifiers quoted, like:
* interface Foo {
* 'bar': string;
* 'complex name': string;
* }
* Foo.bar; // ok
* Foo['bar'] // ok
* Foo['complex name'] // ok
*
* In Closure-land, we want identify that the legal name 'bar' can become an
* ordinary field, but we need to skip strings like 'complex name'.
*/
function isValidClosurePropertyName(name) {
// In local experimentation, it appears that reserved words like 'var' and
// 'if' are legal JS and still accepted by Closure.
return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name);
}
/**
* TypeScript allows parameters named "arguments", but Closure
* disallows this, even in externs.
*/
function makeLegalExternsParam(name) {
switch (name) {
case 'arguments':
return 'tsickle_arguments';
default:
return name;
}
}
function isDtsFileName(fileName) {
return /\.d\.ts$/.test(fileName);
}
var VISIBILITY_FLAGS = ts.NodeFlags.Private | ts.NodeFlags.Protected | ts.NodeFlags.Public;

@@ -58,25 +98,54 @@ /**

}
ClosureRewriter.prototype.emitFunctionType = function (fnDecl, extraTags) {
/**
* Handles emittng the jsdoc for methods, including overloads.
* If overloaded, merges the signatures in the list of SignatureDeclarations into a single jsdoc.
* - Total number of parameters will be the maximum count found across all variants.
* - Any parameters beyond the minimum count found across all variants; prefix: "opt_"
* - Different names at the same parameter index will be joined with "_or_"
* - Variable args (...type[] in TypeScript) will be output as "...type",
* except if found at the same index as another argument.
* @param fnDecls Pass > 1 declaration for overloads of same name
* @return The list of parameter names that should be used to emit the actual
* function statement; for overloads, name will have been merged.
*/
ClosureRewriter.prototype.emitFunctionType = function (fnDecls, extraTags) {
if (extraTags === void 0) { extraTags = []; }
var typeChecker = this.program.getTypeChecker();
var sig = typeChecker.getSignatureFromDeclaration(fnDecl);
// Construct the JSDoc comment by reading the existing JSDoc, if
// any, and merging it with the known types of the function
// parameters and return type.
var jsDoc = this.getJSDoc(fnDecl) || [];
var newDoc = extraTags;
// Copy all the tags other than @param/@return into the new
// comment without any change; @param/@return are handled later.
for (var _i = 0, jsDoc_1 = jsDoc; _i < jsDoc_1.length; _i++) {
var tag = jsDoc_1[_i];
if (tag.tagName === 'param' || tag.tagName === 'return')
continue;
newDoc.push(tag);
}
// Abstract
if ((fnDecl.flags & ts.NodeFlags.Abstract)) {
newDoc.push({ tagName: 'abstract' });
}
// Parameters.
if (sig.parameters.length) {
var paramNamesToReturn = [];
var abstract = { tagName: 'abstract' };
var lens = fnDecls.map(function (fnDecl) { return fnDecl.parameters.length; });
var minCount = Math.min.apply(Math, lens);
var maxCount = Math.max.apply(Math, lens);
var isOverloaded = fnDecls.length > 1;
var isConstructor = fnDecls[0].kind === ts.SyntaxKind.Constructor;
var paramData = {
names: new Array(maxCount),
types: new Array(maxCount),
returns: new Set()
};
for (var _i = 0, fnDecls_1 = fnDecls; _i < fnDecls_1.length; _i++) {
var fnDecl = fnDecls_1[_i];
// Construct the JSDoc comment by reading the existing JSDoc, if
// any, and merging it with the known types of the function
// parameters and return type.
var jsDoc = this.getJSDoc(fnDecl) || [];
// Copy all the tags other than @param/@return into the new
// comment without any change; @param/@return are handled later.
// TODO: handle for overloads. indexOf on the array doesn't match instances of the Tag type,
// so another matching strategy is needed to avoid dupes. Also, there may be problems if
// an annotation doesn't apply to all overloads.
for (var _a = 0, jsDoc_1 = jsDoc; _a < jsDoc_1.length; _a++) {
var tag = jsDoc_1[_a];
if (tag.tagName === 'param' || tag.tagName === 'return' || isOverloaded)
continue;
newDoc.push(tag);
}
// Abstract
if ((fnDecl.flags & ts.NodeFlags.Abstract) && (newDoc.indexOf(abstract) === -1)) {
newDoc.push(abstract);
}
// Merge the parameters into a single list of merged names and list of types
var sig = typeChecker.getSignatureFromDeclaration(fnDecl);
// Parameters.
// Iterate through both the AST parameter list and the type's parameter

@@ -91,3 +160,3 @@ // list, as some information is only available in the former.

optional: paramNode.initializer !== undefined || paramNode.questionToken !== undefined,
parameterName: rewriter_1.unescapeName(paramSym.getName()),
parameterName: makeLegalExternsParam(rewriter_1.unescapeName(paramSym.getName())),
};

@@ -104,34 +173,86 @@ var destructuring = (paramNode.name.kind === ts.SyntaxKind.ArrayBindingPattern ||

newTag.type = this.typeToClosure(fnDecl, type, destructuring);
// Search for this parameter in the JSDoc @params.
for (var _a = 0, jsDoc_2 = jsDoc; _a < jsDoc_2.length; _a++) {
var _b = jsDoc_2[_a], tagName = _b.tagName, parameterName = _b.parameterName, text = _b.text;
if (tagName === 'param' && parameterName === newTag.parameterName) {
newTag.text = text;
break;
if (!isOverloaded) {
// Search for this parameter in the JSDoc @params.
// TODO: Consider adding text from existing JSDoc into overloads
for (var _b = 0, jsDoc_2 = jsDoc; _b < jsDoc_2.length; _b++) {
var _c = jsDoc_2[_b], tagName = _c.tagName, parameterName = _c.parameterName, text = _c.text;
if (tagName === 'param' && parameterName === newTag.parameterName) {
newTag.text = text;
break;
}
}
// push to the newDoc for rendering the single function
newDoc.push(newTag);
}
newDoc.push(newTag);
else {
// build set of param names at this index
if (newTag.parameterName) {
if (!paramData.names[i]) {
paramData.names[i] = new Set();
}
paramData.names[i].add(newTag.parameterName);
}
// build set of type names at this index
if (newTag.type) {
if (!paramData.types[i]) {
paramData.types[i] = new Set();
}
paramData.types[i].add(newTag.type);
}
}
}
// If this method is not overloaded, we set the list of names to those in the only declaration
if (!isOverloaded) {
paramNamesToReturn = fnDecl.parameters.map(function (p) { return p.name.getText(); });
}
// Return type.
if (!isConstructor) {
var retType = typeChecker.getReturnTypeOfSignature(sig);
var retTypeString = this.typeToClosure(fnDecl, retType);
if (!isOverloaded) {
// TODO: Consider adding text from existing JSDoc into overloads
var returnDoc = void 0;
for (var _d = 0, jsDoc_3 = jsDoc; _d < jsDoc_3.length; _d++) {
var _e = jsDoc_3[_d], tagName = _e.tagName, text = _e.text;
if (tagName === 'return') {
returnDoc = text;
break;
}
}
newDoc.push({
tagName: 'return',
type: retTypeString,
text: returnDoc,
});
}
else {
if (retTypeString) {
paramData.returns.add(retTypeString);
}
}
}
}
// Return type.
if (fnDecl.kind !== ts.SyntaxKind.Constructor) {
var retType = typeChecker.getReturnTypeOfSignature(sig);
var returnDoc = void 0;
for (var _c = 0, jsDoc_3 = jsDoc; _c < jsDoc_3.length; _c++) {
var _d = jsDoc_3[_c], tagName = _d.tagName, text = _d.text;
if (tagName === 'return') {
returnDoc = text;
break;
if (isOverloaded) {
// Build actual JSDoc tags for the merged param names/types and return types
for (var i = 0; i < maxCount; i++) {
paramNamesToReturn.push(Array.from(paramData.names[i].values()).join('_or_'));
if (i >= minCount) {
paramNamesToReturn[i] = 'opt_' + paramNamesToReturn[i];
}
var concatenatedTypes = Array.from(paramData.types[i].values()).join('|');
newDoc.push({
tagName: 'param',
parameterName: paramNamesToReturn[i],
type: concatenatedTypes,
});
}
newDoc.push({
tagName: 'return',
type: this.typeToClosure(fnDecl, retType),
text: returnDoc,
});
if (!isConstructor) {
newDoc.push({
tagName: 'return',
type: Array.from(paramData.returns.values()).join('|'),
});
}
}
// The first \n makes the output sometimes uglier than necessary,
// but it's needed to work around
// https://github.com/Microsoft/TypeScript/issues/6982
this.emit('\n' + jsdoc.toString(newDoc));
return paramNamesToReturn;
};

@@ -233,3 +354,3 @@ /**

if (externs.output) {
externsSource = "/** @externs */\n// NOTE: generated by tsickle, do not edit.\n" + externs.output;
externsSource = "/**\n * @externs\n * @suppress {duplicate}\n */\n// NOTE: generated by tsickle, do not edit.\n" + externs.output;
}

@@ -240,2 +361,3 @@ return {

diagnostics: externs.diagnostics.concat(annotated.diagnostics),
sourceMap: annotated.sourceMap,
};

@@ -250,3 +372,3 @@ };

Annotator.prototype.maybeProcess = function (node) {
if (node.flags & ts.NodeFlags.Ambient) {
if ((node.flags & ts.NodeFlags.Ambient) || isDtsFileName(this.file.fileName)) {
this.externsWriter.visit(node);

@@ -289,17 +411,3 @@ // An ambient declaration declares types for TypeScript's benefit, so we want to skip Tsickle

var classNode = node;
if (classNode.members.length > 0) {
// We must visit all members individually, to strip out any
// /** @export */ annotations that show up in the constructor
// and to annotate methods.
this.writeRange(classNode.getFullStart(), classNode.members[0].getFullStart());
for (var _i = 0, _a = classNode.members; _i < _a.length; _i++) {
var member = _a[_i];
this.visit(member);
}
}
else {
this.writeRange(classNode.getFullStart(), classNode.getLastToken().getFullStart());
}
this.emitTypeAnnotationsHelper(classNode);
this.writeNode(classNode.getLastToken());
this.visitClassDeclaration(classNode);
return true;

@@ -320,3 +428,3 @@ case ts.SyntaxKind.PublicKeyword:

var ctor = node;
this.emitFunctionType(ctor);
this.emitFunctionType([ctor]);
// Write the "constructor(...) {" bit, but iterate through any

@@ -326,4 +434,4 @@ // parameters if given so that we can examine them more closely.

if (ctor.parameters.length) {
for (var _b = 0, _c = ctor.parameters; _b < _c.length; _b++) {
var param = _c[_b];
for (var _i = 0, _a = ctor.parameters; _i < _a.length; _i++) {
var param = _a[_i];
this.writeRange(offset, param.getFullStart());

@@ -343,6 +451,8 @@ this.visit(param);

case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
var fnDecl = node;
if (!fnDecl.body) {
if ((fnDecl.flags & ts.NodeFlags.Abstract) !== 0) {
this.emitFunctionType(fnDecl);
this.emitFunctionType([fnDecl]);
// Abstract functions look like

@@ -370,3 +480,3 @@ // abstract foo();

}
this.emitFunctionType(fnDecl);
this.emitFunctionType([fnDecl]);
this.writeRange(fnDecl.getStart(), fnDecl.body.getFullStart());

@@ -503,2 +613,26 @@ this.visit(fnDecl.body);

};
Annotator.prototype.visitClassDeclaration = function (classDecl) {
var jsDoc = this.getJSDoc(classDecl) || [];
if ((classDecl.flags & ts.NodeFlags.Abstract) !== 0) {
jsDoc.push({ tagName: 'abstract' });
}
this.writeRange(classDecl.getFullStart(), classDecl.getStart());
this.emit(jsdoc.toString(jsDoc));
if (classDecl.members.length > 0) {
// We must visit all members individually, to strip out any
// /** @export */ annotations that show up in the constructor
// and to annotate methods.
this.writeRange(classDecl.getStart(), classDecl.members[0].getFullStart());
for (var _i = 0, _a = classDecl.members; _i < _a.length; _i++) {
var member = _a[_i];
this.visit(member);
}
}
else {
this.writeRange(classDecl.getStart(), classDecl.getLastToken().getFullStart());
}
this.emitTypeAnnotationsHelper(classDecl);
this.writeNode(classDecl.getLastToken());
return true;
};
Annotator.prototype.emitInterface = function (iface) {

@@ -724,2 +858,9 @@ if (this.options.untyped)

switch (node.kind) {
case ts.SyntaxKind.SourceFile:
var sourceFile = node;
for (var _i = 0, _a = sourceFile.statements; _i < _a.length; _i++) {
var stmt = _a[_i];
this.visit(stmt, namespace);
}
break;
case ts.SyntaxKind.ModuleDeclaration:

@@ -756,4 +897,4 @@ var decl = node;

var block = node;
for (var _i = 0, _a = block.statements; _i < _a.length; _i++) {
var stmt = _a[_i];
for (var _b = 0, _c = block.statements; _b < _c.length; _b++) {
var stmt = _c[_b];
this.visit(stmt, namespace);

@@ -773,10 +914,10 @@ }

}
this.emitFunctionType(f);
this.emitFunctionType([f]);
var params = f.parameters.map(function (p) { return p.name.getText(); });
this.writeExternsFunction(name_4.getText(), params.join(', '), namespace);
this.writeExternsFunction(name_4.getText(), params, namespace);
break;
case ts.SyntaxKind.VariableStatement:
for (var _b = 0, _c = node.declarationList.declarations; _b < _c.length; _b++) {
var decl_1 = _c[_b];
this.writeExternsVariable(decl_1, namespace);
for (var _d = 0, _e = node.declarationList.declarations; _d < _e.length; _d++) {
var decl_1 = _e[_d];
this.writeExternsVariableDecl(decl_1, namespace);
}

@@ -787,2 +928,5 @@ break;

break;
case ts.SyntaxKind.TypeAliasDeclaration:
this.writeExternsTypeAlias(node, namespace);
break;
default:

@@ -819,25 +963,26 @@ this.emit("\n/* TODO: " + ts.SyntaxKind[node.kind] + " in " + namespace.join('.') + " */\n");

if (this.isFirstDeclaration(decl)) {
var paramNames = '';
var paramNames = [];
if (decl.kind === ts.SyntaxKind.ClassDeclaration) {
var ctors = decl.members.filter(function (m) { return m.kind === ts.SyntaxKind.Constructor; });
if (ctors.length) {
var firstCtor = ctors[0];
var ctorTags = [{ tagName: 'constructor' }, { tagName: 'struct' }];
if (ctors.length > 1) {
// TODO: unify the multiple constructors as overloads.
// For now, we just drop all but the first.
// See https://github.com/angular/tsickle/issues/180 .
this.debugWarn(ctors[1], 'multiple constructor signatures in declarations');
paramNames = this.emitFunctionType(ctors, ctorTags);
}
var ctor = ctors[0];
this.emitFunctionType(ctor, [{ tagName: 'constructor' }, { tagName: 'struct' }]);
paramNames = ctor.parameters.map(function (p) { return p.name.getText(); }).join(', ');
else {
paramNames = this.emitFunctionType([firstCtor], ctorTags);
}
}
else {
this.emit('/** @constructor @struct */\n');
this.emit('\n/** @constructor @struct */\n');
}
}
else {
this.emit('/** @record @struct */\n');
this.emit('\n/** @record @struct */\n');
}
this.writeExternsFunction(name.getText(), paramNames, namespace);
}
// Process everything except (MethodSignature|MethodDeclaration|Constructor)
var methods = new Map();
for (var _i = 0, _a = decl.members; _i < _a.length; _i++) {

@@ -859,6 +1004,10 @@ var member = _a[_i];

case ts.SyntaxKind.MethodDeclaration:
var m = member;
this.emitFunctionType(m);
this.emit((typeName + ".prototype." + m.name.getText() + " = ") +
("function(" + m.parameters.map(function (p) { return p.name.getText(); }).join(', ') + ") {};\n"));
var method = member;
var methodName = method.name.getText();
if (methods.has(methodName)) {
methods.get(methodName).push(method);
}
else {
methods.set(methodName, [method]);
}
continue;

@@ -880,16 +1029,25 @@ case ts.SyntaxKind.Constructor:

}
// Handle method declarations/signatures separately, since we need to deal with overloads.
namespace = namespace.concat([name.getText(), 'prototype']);
for (var _b = 0, _c = Array.from(methods.values()); _b < _c.length; _b++) {
var methodVariants = _c[_b];
var firstMethodVariant = methodVariants[0];
var parameterNames = void 0;
if (methodVariants.length > 1) {
parameterNames = this.emitFunctionType(methodVariants);
}
else {
parameterNames = this.emitFunctionType([firstMethodVariant]);
}
this.writeExternsFunction(firstMethodVariant.name.getText(), parameterNames, namespace);
}
};
ExternsWriter.prototype.writeExternsVariable = function (decl, namespace) {
ExternsWriter.prototype.writeExternsVariableDecl = function (decl, namespace) {
if (decl.name.kind === ts.SyntaxKind.Identifier) {
var identifier = decl.name;
var qualifiedName = namespace.concat([rewriter_1.getIdentifierText(identifier)]).join('.');
if (exports.closureExternsBlacklist.indexOf(qualifiedName) >= 0)
var name_5 = rewriter_1.getIdentifierText(decl.name);
if (exports.closureExternsBlacklist.indexOf(name_5) >= 0)
return;
this.emitJSDocType(decl);
if (namespace.length > 0) {
this.emit("\n" + qualifiedName + ";\n");
}
else {
this.emit("\nvar " + qualifiedName + ";\n");
}
this.emit('\n');
this.writeExternsVariable(name_5, namespace);
}

@@ -900,9 +1058,16 @@ else {

};
ExternsWriter.prototype.writeExternsVariable = function (name, namespace) {
var qualifiedName = namespace.concat([name]).join('.');
if (namespace.length === 0)
this.emit("var ");
this.emit(qualifiedName + ";\n");
};
ExternsWriter.prototype.writeExternsFunction = function (name, params, namespace) {
var paramsStr = params.map(makeLegalExternsParam).join(', ');
if (namespace.length > 0) {
name = namespace.concat([name]).join('.');
this.emit(name + " = function(" + params + ") {};\n");
this.emit(name + " = function(" + paramsStr + ") {};\n");
}
else {
this.emit("function " + name + "(" + params + ") {}\n");
this.emit("function " + name + "(" + paramsStr + ") {}\n");
}

@@ -916,8 +1081,28 @@ };

var member = _a[_i];
var memberName = member.name.getText();
var name_5 = namespace.concat([memberName]).join('.');
var memberName = void 0;
switch (member.name.kind) {
case ts.SyntaxKind.Identifier:
memberName = rewriter_1.getIdentifierText(member.name);
break;
case ts.SyntaxKind.StringLiteral:
var text = member.name.text;
if (isValidClosurePropertyName(text))
memberName = text;
break;
default:
break;
}
if (!memberName) {
this.emit("\n/* TODO: " + ts.SyntaxKind[member.name.kind] + ": " + member.name.getText() + " */\n");
continue;
}
var name_6 = namespace.concat([memberName]).join('.');
this.emit('/** @const {number} */\n');
this.emit(name_5 + ";\n");
this.emit(name_6 + ";\n");
}
};
ExternsWriter.prototype.writeExternsTypeAlias = function (decl, namespace) {
this.emit("\n/** @typedef {" + this.typeToClosure(decl) + "} */\n");
this.writeExternsVariable(rewriter_1.getIdentifierText(decl.name), namespace);
};
return ExternsWriter;

@@ -924,0 +1109,0 @@ }(ClosureRewriter));

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";

@@ -114,3 +121,5 @@ var ts = require('typescript');

var writeText = function (text) { return str += text; };
var doNothing = function () { return; };
var doNothing = function () {
return;
};
var builder = this.typeChecker.getSymbolDisplayBuilder();

@@ -117,0 +126,0 @@ var writer = {

@@ -0,5 +1,12 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
"use strict";
// toArray is a temporary function to help in the use of
// ES6 maps and sets when running on node 4, which doesn't
// support Iterators completely.
"use strict";
function toArray(iterator) {

@@ -6,0 +13,0 @@ var array = [];

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
require('source-map-support').install();

@@ -15,22 +23,6 @@

var TSC_OPTIONS = {
module: 'commonjs',
// allow pulling in files from node_modules until TS 1.5 is in tsd / DefinitelyTyped (the
// alternative is to include node_modules paths in the src arrays below for compilation)
noExternalResolve: false,
noImplicitAny: true,
declarationFiles: true,
noEmitOnError: true,
target: 'es5',
lib: [
'es5',
'es2015.collection',
'es2015.iterable',
'dom',
],
var tsProject = ts.createProject('tsconfig.json', {
// Specify the TypeScript version we're using.
typescript: typescript,
strictNullChecks: true,
};
var tsProject = ts.createProject(TSC_OPTIONS);
});

@@ -55,3 +47,2 @@ gulp.task('test.check-format', function() {

hasError = true;
gutil.log(err.message);
if (failOnError) {

@@ -64,6 +55,4 @@ process.exit(1);

hasError = false;
var tsResult = gulp.src(['src/**/*.ts', 'typings/**/*.d.ts'])
.pipe(sourcemaps.init())
.pipe(ts(tsProject))
.on('error', onError);
var tsResult =
gulp.src(['src/**/*.ts']).pipe(sourcemaps.init()).pipe(tsProject()).on('error', onError);
return merge([

@@ -83,5 +72,5 @@ tsResult.dts.pipe(gulp.dest('build/definitions')),

}
return gulp.src(['test/*.ts', 'typings/**/*.d.ts'], {base: '.'})
return gulp.src(['test/*.ts'], {base: '.'})
.pipe(sourcemaps.init())
.pipe(ts(tsProject))
.pipe(tsProject())
.on('error', onError)

@@ -105,3 +94,3 @@ .js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: '../..'}))

}
return gulp.src(['build/test/**/e2e*.js']).pipe(mocha({timeout: 20000}));
return gulp.src(['build/test/**/e2e*.js']).pipe(mocha({timeout: 25000}));
});

@@ -108,0 +97,0 @@

{
"name": "tsickle",
"version": "0.1.7",
"version": "0.2.0",
"description": "Transpile TypeScript code to JavaScript with Closure annotations.",

@@ -13,12 +13,22 @@ "main": "build/src/tsickle.js",

"minimist": "^1.2.0",
"source-map": "^0.4.2",
"source-map-support": "^0.3.1",
"mkdirp": "^0.5.1"
"mkdirp": "^0.5.1",
"source-map": "^0.5.6",
"source-map-support": "^0.4.2"
},
"peerDependencies": {
"typescript": "^2.0.0 || ^2.1.0-dev"
"typescript": "^2.0.0"
},
"devDependencies": {
"chai": "^2.1.1",
"clang-format": "^1.0.43",
"@types/chai": "^3.4.32",
"@types/glob": "^5.0.29",
"@types/google-closure-compiler": "0.0.18",
"@types/minimatch": "^2.0.28",
"@types/minimist": "^1.1.28",
"@types/mkdirp": "^0.3.28",
"@types/mocha": "^2.2.31",
"@types/node": "^6.0.38",
"@types/source-map": "^0.1.27",
"@types/source-map-support": "^0.2.27",
"chai": "^3.5.0",
"clang-format": "^1.0.45",
"glob": "^7.0.0",

@@ -28,15 +38,14 @@ "google-closure-compiler": "^20160315.2.0",

"gulp-clang-format": "^1.0.22",
"gulp-mocha": "^2.0.0",
"gulp-mocha": "^3.0.1",
"gulp-sourcemaps": "^1.5.0",
"gulp-tslint": "^6.1.1",
"gulp-typescript": "^2.7.6",
"gulp-typescript": "^3.0.0",
"gulp-util": "^3.0.4",
"merge2": "^0.3.1",
"merge2": "^1.0.2",
"temp": "^0.8.1",
"tsd": "^0.6.0",
"tslint": "3.15.0-dev.0",
"typescript": "^2.1.0-dev.20160827"
"tslint": "^3.15.1",
"typescript": "^2.0.0"
},
"scripts": {
"prepublish": "npm install tsd@^0.6.0 && tsd reinstall --overwrite && gulp compile",
"prepublish": "gulp compile",
"test": "gulp test"

@@ -43,0 +52,0 @@ },

@@ -32,2 +32,31 @@ # Tsickle - TypeScript to Closure Annotator [![Build Status](https://travis-ci.org/angular/tsickle.svg?branch=master)](https://travis-ci.org/angular/tsickle)

### Differences from TypeScript
Closure and TypeScript are not identical. Tsickle hides most of the
differences, but users must still be aware of some differences.
#### `declare`
Any declaration in a `.d.ts` file, as well as any declaration tagged with
`declare ...`, is intepreted by Tsickle as a name that should be preserved
through Closure compilation (i.e. not renamed into something shorter). Use it
any time the specific string names of your fields are significant. That would
most often happen when the object either coming from outside your program, or
being passed out of the program.
Example:
declare interface JSONResult {
username: string;
}
let r = JSON.parse(input) as JSONResult;
console.log(r.username);
By adding `declare` to the interface (or if it were in a `.d.ts` file), Tsickle
will inform Closure that it must use exactly the field name `.username` (and not
e.g. `.a`) in the output JS. This matters for this example because the input
JSON probably uses the string `'username'` and not whatever name Closure would
invent for it. (Note: `declare` on an interface has no additional meaning in
pure TypeScript.)
## Development

@@ -34,0 +63,0 @@

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as path from 'path';

@@ -5,6 +13,14 @@

export function pathToModuleName(context: string, fileName: string): string {
fileName = fileName.replace(/\.js$/, '');
if (fileName[0] === '.') {
// './foo' or '../foo'.
// Resolve the path against the dirname of the current module.
fileName = path.join(path.dirname(context), fileName);
}
return fileName.replace(/\.js$/, '').replace(/\//g, '.');
// Replace characters not supported by goog.module.
let moduleName =
fileName.replace(/\//g, '.').replace(/^[^a-zA-Z_$]/, '_').replace(/[^a-zA-Z0-9._$]/g, '_');
return moduleName;
}

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';

@@ -25,3 +33,5 @@

constructor(private typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile) { super(sourceFile); }
constructor(private typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile) {
super(sourceFile);
}

@@ -55,3 +65,6 @@ /**

private decoratorsToLower(n: ts.Node): ts.Decorator[] {
return (n.decorators as ts.NodeArray<ts.Decorator>|| []).filter(d => this.shouldLower(d));
if (n.decorators) {
return n.decorators.filter((d) => this.shouldLower(d));
}
return [];
}

@@ -265,3 +278,5 @@

class DecoratorRewriter extends Rewriter {
constructor(private typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile) { super(sourceFile); }
constructor(private typeChecker: ts.TypeChecker, sourceFile: ts.SourceFile) {
super(sourceFile);
}

@@ -268,0 +283,0 @@ process(): {output: string, diagnostics: ts.Diagnostic[]} {

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';

@@ -39,8 +47,8 @@

constructor(
file: ts.SourceFile, private pathToModuleName: (context: string, fileName: string) => string,
private isES5: boolean) {
file: ts.SourceFile,
private pathToModuleName: (context: string, fileName: string) => string) {
super(file);
}
process(): {output: string, referencedModules: string[]} {
process(moduleId: string, isES5: boolean): {output: string, referencedModules: string[]} {
// TODO(evanm): only emit the goog.module *after* the first comment,

@@ -56,9 +64,8 @@ // so that @suppress statements work.

// optimizations mode.
if (this.isES5) {
this.emit(`var module = module || {id: '${this.file.fileName}'};`);
if (isES5) {
this.emit(`var module = module || {id: '${moduleId}'};`);
} else {
this.emit(`var module = {id: '${this.file.fileName}'};`);
this.emit(`var module = {id: '${moduleId}'};`);
}
let pos = 0;

@@ -224,6 +231,4 @@ for (let stmt of this.file.statements) {

if (isNamespaceImport) this.namespaceImports.add(varName);
if (this.moduleVariables.has(modName)) {
this.emit(`var ${varName} = ${this.moduleVariables.get(modName)};`);
} else {
this.emit(`var ${varName} = goog.require('${modName}');`);
this.emit(`var ${varName} = goog.require('${modName}');`);
if (!this.moduleVariables.has(modName)) {
this.moduleVariables.set(modName, varName);

@@ -295,3 +300,5 @@ }

/** Generates a new variable name inside the tsickle_ namespace. */
generateFreshVariableName(): string { return `tsickle_module_${this.unusedIndex++}_`; }
generateFreshVariableName(): string {
return `tsickle_module_${this.unusedIndex++}_`;
}
}

@@ -303,3 +310,5 @@

*
* @param fileName The source file name, without an extension.
* @param fileName The source file name.
* @param moduleId The "module id", a module-identifying string that is
* the value module.id in the scope of the module.
* @param pathToModuleName A function that maps a filesystem .ts path to a

@@ -311,7 +320,7 @@ * Closure module name, as found in a goog.require('...') statement.

export function processES5(
fileName: string, content: string,
fileName: string, moduleId: string, content: string,
pathToModuleName: (context: string, fileName: string) => string,
isES5 = true): {output: string, referencedModules: string[]} {
let file = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, true);
return new ES5Processor(file, pathToModuleName, isES5).process();
return new ES5Processor(file, pathToModuleName).process(moduleId, isES5);
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* TypeScript has an API for JSDoc already, but it's not exposed.

@@ -191,2 +199,3 @@ * https://github.com/Microsoft/TypeScript/issues/7393

export function toString(tags: Tag[]): string {
if (tags.length === 0) return '';
let out = '';

@@ -193,0 +202,0 @@ out += '/**\n';

#!/usr/bin/env node
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as fs from 'fs';

@@ -177,3 +185,5 @@ import * as minimist from 'minimist';

logWarning: settings.verbose ?
(warning: ts.Diagnostic) => { console.error(tsickle.formatDiagnostics([warning])); } :
(warning: ts.Diagnostic) => {
console.error(tsickle.formatDiagnostics([warning]));
} :
undefined,

@@ -202,12 +212,10 @@ };

program = ts.createProgram(fileNames, options, host);
let diagnostics = ts.getPreEmitDiagnostics(program);
if (diagnostics.length > 0) {
allDiagnostics.push(...diagnostics);
return null;
}
// Emit, creating a map of fileName => generated JS source.
const jsFiles = new Map<string, string>();
function writeFile(fileName: string, data: string): void { jsFiles.set(fileName, data); }
({diagnostics} = program.emit(undefined, writeFile));
function writeFile(fileName: string, data: string): void {
jsFiles.set(fileName, data);
}
let {diagnostics} = program.emit(undefined, writeFile);
if (diagnostics.length > 0) {

@@ -220,4 +228,5 @@ allDiagnostics.push(...diagnostics);

if (path.extname(fileName) !== '.map') {
let {output} = tsickle.convertCommonJsToGoogModule(
fileName, jsFiles.get(fileName)!, cliSupport.pathToModuleName);
const moduleId = fileName; // TODO: does anyone use this?
let {output} = tsickle.processES5(
fileName, moduleId, jsFiles.get(fileName)!, cliSupport.pathToModuleName);
jsFiles.set(fileName, output);

@@ -224,0 +233,0 @@ }

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {SourceMapGenerator} from 'source-map';
import * as ts from 'typescript';

@@ -9,5 +18,9 @@

export abstract class Rewriter {
protected output: string[] = [];
private output: string[] = [];
/** Errors found while examining the code. */
protected diagnostics: ts.Diagnostic[] = [];
/** The source map that's generated while rewriting this file. */
private sourceMap = new SourceMapGenerator();
/** Current position in the output. */
private position = {line: 1, column: 1};
/**

@@ -19,9 +32,19 @@ * The current level of recursion through TypeScript Nodes. Used in formatting internal debug

constructor(protected file: ts.SourceFile) {}
constructor(protected file: ts.SourceFile) {
this.sourceMap.addMapping({
original: this.position,
generated: this.position,
source: file.fileName,
});
}
getOutput(): {output: string, diagnostics: ts.Diagnostic[]} {
getOutput(): {output: string, diagnostics: ts.Diagnostic[], sourceMap: SourceMapGenerator} {
if (this.indent !== 0) {
throw new Error('visit() failed to track nesting');
}
return {output: this.output.join(''), diagnostics: this.diagnostics};
return {
output: this.output.join(''),
diagnostics: this.diagnostics,
sourceMap: this.sourceMap,
};
}

@@ -47,3 +70,5 @@

*/
protected maybeProcess(node: ts.Node): boolean { return false; }
protected maybeProcess(node: ts.Node): boolean {
return false;
}

@@ -81,6 +106,29 @@ /** writeNode writes a ts.Node, calling this.visit() on its children. */

let text = this.file.text.slice(from, to);
if (text) this.emit(text);
if (text) {
// Add a source mapping. writeRange(from, to) always corresponds to
// original source code, so add a mapping at the current location that
// points back to the location at `from`. The additional code generated
// by tsickle will then be considered part of the last mapped code
// section preceding it. That's arguably incorrect (e.g. for the fake
// methods defining properties), but is good enough for stack traces.
const pos = this.file.getLineAndCharacterOfPosition(from);
this.sourceMap.addMapping({
original: {line: pos.line + 1, column: pos.character + 1},
generated: this.position,
source: this.file.fileName,
});
this.emit(text);
}
}
emit(str: string) { this.output.push(str); }
emit(str: string) {
this.output.push(str);
for (const c of str) {
this.position.column++;
if (c === '\n') {
this.position.line++;
this.position.column = 1;
}
}
}

@@ -87,0 +135,0 @@ /** Removes comment metacharacters from a string, to make it safe to embed in a comment. */

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

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {SourceMapGenerator} from 'source-map';
import * as ts from 'typescript';

@@ -9,13 +18,17 @@

export {convertDecorators} from './decorator-annotator';
export {processES5 as convertCommonJsToGoogModule} from './es5processor';
export {processES5} from './es5processor';
export interface Options {
// If true, convert every type to the Closure {?} type, which means
// "don't check types".
/**
* If true, convert every type to the Closure {?} type, which means
* "don't check types".
*/
untyped?: boolean;
// If provided a function that logs an internal warning.
// These warnings are not actionable by an end user and should be hidden
// by default.
/**
* If provided a function that logs an internal warning.
* These warnings are not actionable by an end user and should be hidden
* by default.
*/
logWarning?: (warning: ts.Diagnostic) => void;
// If provided, a set of paths whose types should always generate as {?}.
/** If provided, a set of paths whose types should always generate as {?}. */
typeBlackListPaths?: Set<string>;

@@ -25,8 +38,10 @@ }

export interface Output {
// The TypeScript source with Closure annotations inserted.
/** The TypeScript source with Closure annotations inserted. */
output: string;
// Generated externs declarations, if any.
/** Generated externs declarations, if any. */
externs: string|null;
// Error messages, if any.
/** Error messages, if any. */
diagnostics: ts.Diagnostic[];
/** A source map mapping back into the original sources. */
sourceMap: SourceMapGenerator;
}

@@ -61,2 +76,38 @@

/**
* TypeScript allows you to write identifiers quoted, like:
* interface Foo {
* 'bar': string;
* 'complex name': string;
* }
* Foo.bar; // ok
* Foo['bar'] // ok
* Foo['complex name'] // ok
*
* In Closure-land, we want identify that the legal name 'bar' can become an
* ordinary field, but we need to skip strings like 'complex name'.
*/
function isValidClosurePropertyName(name: string): boolean {
// In local experimentation, it appears that reserved words like 'var' and
// 'if' are legal JS and still accepted by Closure.
return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name);
}
/**
* TypeScript allows parameters named "arguments", but Closure
* disallows this, even in externs.
*/
function makeLegalExternsParam(name: string): string {
switch (name) {
case 'arguments':
return 'tsickle_arguments';
default:
return name;
}
}
function isDtsFileName(fileName: string): boolean {
return /\.d\.ts$/.test(fileName);
}
const VISIBILITY_FLAGS = ts.NodeFlags.Private | ts.NodeFlags.Protected | ts.NodeFlags.Public;

@@ -75,26 +126,53 @@

emitFunctionType(fnDecl: ts.SignatureDeclaration, extraTags: jsdoc.Tag[] = []) {
/**
* Handles emittng the jsdoc for methods, including overloads.
* If overloaded, merges the signatures in the list of SignatureDeclarations into a single jsdoc.
* - Total number of parameters will be the maximum count found across all variants.
* - Any parameters beyond the minimum count found across all variants; prefix: "opt_"
* - Different names at the same parameter index will be joined with "_or_"
* - Variable args (...type[] in TypeScript) will be output as "...type",
* except if found at the same index as another argument.
* @param fnDecls Pass > 1 declaration for overloads of same name
* @return The list of parameter names that should be used to emit the actual
* function statement; for overloads, name will have been merged.
*/
emitFunctionType(fnDecls: ts.SignatureDeclaration[], extraTags: jsdoc.Tag[] = []): string[] {
let typeChecker = this.program.getTypeChecker();
let sig = typeChecker.getSignatureFromDeclaration(fnDecl);
// Construct the JSDoc comment by reading the existing JSDoc, if
// any, and merging it with the known types of the function
// parameters and return type.
let jsDoc = this.getJSDoc(fnDecl) || [];
let newDoc = extraTags;
let paramNamesToReturn: string[] = [];
const abstract = {tagName: 'abstract'};
const lens = fnDecls.map(fnDecl => fnDecl.parameters.length);
const minCount = Math.min(...lens);
const maxCount = Math.max(...lens);
const isOverloaded = fnDecls.length > 1;
const isConstructor = fnDecls[0].kind === ts.SyntaxKind.Constructor;
let paramData = {
names: new Array<Set<string>>(maxCount),
types: new Array<Set<string>>(maxCount),
returns: new Set<string>()
};
// Copy all the tags other than @param/@return into the new
// comment without any change; @param/@return are handled later.
for (let tag of jsDoc) {
if (tag.tagName === 'param' || tag.tagName === 'return') continue;
newDoc.push(tag);
}
for (let fnDecl of fnDecls) {
// Construct the JSDoc comment by reading the existing JSDoc, if
// any, and merging it with the known types of the function
// parameters and return type.
let jsDoc = this.getJSDoc(fnDecl) || [];
// Abstract
if ((fnDecl.flags & ts.NodeFlags.Abstract)) {
newDoc.push({tagName: 'abstract'});
}
// Copy all the tags other than @param/@return into the new
// comment without any change; @param/@return are handled later.
// TODO: handle for overloads. indexOf on the array doesn't match instances of the Tag type,
// so another matching strategy is needed to avoid dupes. Also, there may be problems if
// an annotation doesn't apply to all overloads.
for (let tag of jsDoc) {
if (tag.tagName === 'param' || tag.tagName === 'return' || isOverloaded) continue;
newDoc.push(tag);
}
// Parameters.
if (sig.parameters.length) {
// Abstract
if ((fnDecl.flags & ts.NodeFlags.Abstract) && (newDoc.indexOf(abstract) === -1)) {
newDoc.push(abstract);
}
// Merge the parameters into a single list of merged names and list of types
let sig = typeChecker.getSignatureFromDeclaration(fnDecl);
// Parameters.
// Iterate through both the AST parameter list and the type's parameter

@@ -110,3 +188,3 @@ // list, as some information is only available in the former.

optional: paramNode.initializer !== undefined || paramNode.questionToken !== undefined,
parameterName: unescapeName(paramSym.getName()),
parameterName: makeLegalExternsParam(unescapeName(paramSym.getName())),
};

@@ -128,34 +206,83 @@

// Search for this parameter in the JSDoc @params.
for (let {tagName, parameterName, text} of jsDoc) {
if (tagName === 'param' && parameterName === newTag.parameterName) {
newTag.text = text;
break;
if (!isOverloaded) {
// Search for this parameter in the JSDoc @params.
// TODO: Consider adding text from existing JSDoc into overloads
for (let {tagName, parameterName, text} of jsDoc) {
if (tagName === 'param' && parameterName === newTag.parameterName) {
newTag.text = text;
break;
}
}
// push to the newDoc for rendering the single function
newDoc.push(newTag);
} else {
// build set of param names at this index
if (newTag.parameterName) {
if (!paramData.names[i]) {
paramData.names[i] = new Set<string>();
}
paramData.names[i].add(newTag.parameterName);
}
// build set of type names at this index
if (newTag.type) {
if (!paramData.types[i]) {
paramData.types[i] = new Set<string>();
}
paramData.types[i].add(newTag.type);
}
}
newDoc.push(newTag);
}
}
// If this method is not overloaded, we set the list of names to those in the only declaration
if (!isOverloaded) {
paramNamesToReturn = fnDecl.parameters.map(p => p.name.getText());
}
// Return type.
if (fnDecl.kind !== ts.SyntaxKind.Constructor) {
let retType = typeChecker.getReturnTypeOfSignature(sig);
let returnDoc: string|undefined;
for (let {tagName, text} of jsDoc) {
if (tagName === 'return') {
returnDoc = text;
break;
// Return type.
if (!isConstructor) {
let retType = typeChecker.getReturnTypeOfSignature(sig);
let retTypeString: string = this.typeToClosure(fnDecl, retType);
if (!isOverloaded) {
// TODO: Consider adding text from existing JSDoc into overloads
let returnDoc: string|undefined;
for (let {tagName, text} of jsDoc) {
if (tagName === 'return') {
returnDoc = text;
break;
}
}
newDoc.push({
tagName: 'return',
type: retTypeString,
text: returnDoc,
});
} else {
if (retTypeString) {
paramData.returns.add(retTypeString);
}
}
}
newDoc.push({
tagName: 'return',
type: this.typeToClosure(fnDecl, retType),
text: returnDoc,
});
}
// The first \n makes the output sometimes uglier than necessary,
// but it's needed to work around
// https://github.com/Microsoft/TypeScript/issues/6982
if (isOverloaded) {
// Build actual JSDoc tags for the merged param names/types and return types
for (let i = 0; i < maxCount; i++) {
paramNamesToReturn.push(Array.from(paramData.names[i].values()).join('_or_'));
if (i >= minCount) {
paramNamesToReturn[i] = 'opt_' + paramNamesToReturn[i];
}
let concatenatedTypes = Array.from(paramData.types[i].values()).join('|');
newDoc.push({
tagName: 'param',
parameterName: paramNamesToReturn[i],
type: concatenatedTypes,
});
}
if (!isConstructor) {
newDoc.push({
tagName: 'return',
type: Array.from(paramData.returns.values()).join('|'),
});
}
}
this.emit('\n' + jsdoc.toString(newDoc));
return paramNamesToReturn;
}

@@ -269,3 +396,6 @@

if (externs.output) {
externsSource = `/** @externs */
externsSource = `/**
* @externs
* @suppress {duplicate}
*/
// NOTE: generated by tsickle, do not edit.

@@ -279,2 +409,3 @@ ` + externs.output;

diagnostics: externs.diagnostics.concat(annotated.diagnostics),
sourceMap: annotated.sourceMap,
};

@@ -289,3 +420,3 @@ }

maybeProcess(node: ts.Node): boolean {
if (node.flags & ts.NodeFlags.Ambient) {
if ((node.flags & ts.NodeFlags.Ambient) || isDtsFileName(this.file.fileName)) {
this.externsWriter.visit(node);

@@ -329,15 +460,3 @@ // An ambient declaration declares types for TypeScript's benefit, so we want to skip Tsickle

let classNode = <ts.ClassDeclaration>node;
if (classNode.members.length > 0) {
// We must visit all members individually, to strip out any
// /** @export */ annotations that show up in the constructor
// and to annotate methods.
this.writeRange(classNode.getFullStart(), classNode.members[0].getFullStart());
for (let member of classNode.members) {
this.visit(member);
}
} else {
this.writeRange(classNode.getFullStart(), classNode.getLastToken().getFullStart());
}
this.emitTypeAnnotationsHelper(classNode);
this.writeNode(classNode.getLastToken());
this.visitClassDeclaration(classNode);
return true;

@@ -358,3 +477,3 @@ case ts.SyntaxKind.PublicKeyword:

let ctor = <ts.ConstructorDeclaration>node;
this.emitFunctionType(ctor);
this.emitFunctionType([ctor]);
// Write the "constructor(...) {" bit, but iterate through any

@@ -379,2 +498,4 @@ // parameters if given so that we can examine them more closely.

case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
let fnDecl = <ts.FunctionLikeDeclaration>node;

@@ -384,3 +505,3 @@

if ((fnDecl.flags & ts.NodeFlags.Abstract) !== 0) {
this.emitFunctionType(fnDecl);
this.emitFunctionType([fnDecl]);
// Abstract functions look like

@@ -409,3 +530,3 @@ // abstract foo();

this.emitFunctionType(fnDecl);
this.emitFunctionType([fnDecl]);
this.writeRange(fnDecl.getStart(), fnDecl.body.getFullStart());

@@ -548,2 +669,25 @@ this.visit(fnDecl.body);

private visitClassDeclaration(classDecl: ts.ClassDeclaration) {
let jsDoc = this.getJSDoc(classDecl) || [];
if ((classDecl.flags & ts.NodeFlags.Abstract) !== 0) {
jsDoc.push({tagName: 'abstract'});
}
this.writeRange(classDecl.getFullStart(), classDecl.getStart());
this.emit(jsdoc.toString(jsDoc));
if (classDecl.members.length > 0) {
// We must visit all members individually, to strip out any
// /** @export */ annotations that show up in the constructor
// and to annotate methods.
this.writeRange(classDecl.getStart(), classDecl.members[0].getFullStart());
for (let member of classDecl.members) {
this.visit(member);
}
} else {
this.writeRange(classDecl.getStart(), classDecl.getLastToken().getFullStart());
}
this.emitTypeAnnotationsHelper(classDecl);
this.writeNode(classDecl.getLastToken());
return true;
}
private emitInterface(iface: ts.InterfaceDeclaration) {

@@ -762,2 +906,8 @@ if (this.options.untyped) return;

switch (node.kind) {
case ts.SyntaxKind.SourceFile:
let sourceFile = node as ts.SourceFile;
for (let stmt of sourceFile.statements) {
this.visit(stmt, namespace);
}
break;
case ts.SyntaxKind.ModuleDeclaration:

@@ -806,9 +956,9 @@ let decl = <ts.ModuleDeclaration>node;

}
this.emitFunctionType(f);
this.emitFunctionType([f]);
const params = f.parameters.map((p) => p.name.getText());
this.writeExternsFunction(name.getText(), params.join(', '), namespace);
this.writeExternsFunction(name.getText(), params, namespace);
break;
case ts.SyntaxKind.VariableStatement:
for (let decl of (<ts.VariableStatement>node).declarationList.declarations) {
this.writeExternsVariable(decl, namespace);
this.writeExternsVariableDecl(decl, namespace);
}

@@ -819,2 +969,5 @@ break;

break;
case ts.SyntaxKind.TypeAliasDeclaration:
this.writeExternsTypeAlias(node as ts.TypeAliasDeclaration, namespace);
break;
default:

@@ -851,3 +1004,3 @@ this.emit(`\n/* TODO: ${ts.SyntaxKind[node.kind]} in ${namespace.join('.')} */\n`);

if (this.isFirstDeclaration(decl)) {
let paramNames = '';
let paramNames: string[] = [];
if (decl.kind === ts.SyntaxKind.ClassDeclaration) {

@@ -857,16 +1010,14 @@ let ctors =

if (ctors.length) {
let firstCtor: ts.ConstructorDeclaration = <ts.ConstructorDeclaration>ctors[0];
const ctorTags = [{tagName: 'constructor'}, {tagName: 'struct'}];
if (ctors.length > 1) {
// TODO: unify the multiple constructors as overloads.
// For now, we just drop all but the first.
// See https://github.com/angular/tsickle/issues/180 .
this.debugWarn(ctors[1], 'multiple constructor signatures in declarations');
paramNames = this.emitFunctionType(ctors as ts.ConstructorDeclaration[], ctorTags);
} else {
paramNames = this.emitFunctionType([firstCtor], ctorTags);
}
let ctor = <ts.ConstructorDeclaration>ctors[0];
this.emitFunctionType(ctor, [{tagName: 'constructor'}, {tagName: 'struct'}]);
paramNames = ctor.parameters.map((p) => p.name.getText()).join(', ');
} else {
this.emit('/** @constructor @struct */\n');
this.emit('\n/** @constructor @struct */\n');
}
} else {
this.emit('/** @record @struct */\n');
this.emit('\n/** @record @struct */\n');
}

@@ -876,2 +1027,4 @@ this.writeExternsFunction(name.getText(), paramNames, namespace);

// Process everything except (MethodSignature|MethodDeclaration|Constructor)
let methods: Map<string, ts.MethodDeclaration[]> = new Map();
for (let member of decl.members) {

@@ -892,7 +1045,9 @@ switch (member.kind) {

case ts.SyntaxKind.MethodDeclaration:
let m = <ts.MethodDeclaration>member;
this.emitFunctionType(m);
this.emit(
`${typeName}.prototype.${m.name.getText()} = ` +
`function(${m.parameters.map((p) => p.name.getText()).join(', ')}) {};\n`);
const method = member as ts.MethodDeclaration;
const methodName = method.name.getText();
if (methods.has(methodName)) {
methods.get(methodName)!.push(method);
} else {
methods.set(methodName, [method]);
}
continue;

@@ -914,15 +1069,24 @@ case ts.SyntaxKind.Constructor:

}
// Handle method declarations/signatures separately, since we need to deal with overloads.
namespace = namespace.concat([name.getText(), 'prototype']);
for (const methodVariants of Array.from(methods.values())) {
let firstMethodVariant = methodVariants[0];
let parameterNames: string[];
if (methodVariants.length > 1) {
parameterNames = this.emitFunctionType(methodVariants);
} else {
parameterNames = this.emitFunctionType([firstMethodVariant]);
}
this.writeExternsFunction(firstMethodVariant.name.getText(), parameterNames, namespace);
}
}
private writeExternsVariable(decl: ts.VariableDeclaration, namespace: string[]) {
private writeExternsVariableDecl(decl: ts.VariableDeclaration, namespace: string[]) {
if (decl.name.kind === ts.SyntaxKind.Identifier) {
let identifier = <ts.Identifier>decl.name;
let qualifiedName = namespace.concat([getIdentifierText(identifier)]).join('.');
if (closureExternsBlacklist.indexOf(qualifiedName) >= 0) return;
let name = getIdentifierText(decl.name as ts.Identifier);
if (closureExternsBlacklist.indexOf(name) >= 0) return;
this.emitJSDocType(decl);
if (namespace.length > 0) {
this.emit(`\n${qualifiedName};\n`);
} else {
this.emit(`\nvar ${qualifiedName};\n`);
}
this.emit('\n');
this.writeExternsVariable(name, namespace);
} else {

@@ -933,8 +1097,15 @@ this.errorUnimplementedKind(decl.name, 'externs for variable');

private writeExternsFunction(name: string, params: string, namespace: string[]) {
private writeExternsVariable(name: string, namespace: string[]) {
let qualifiedName = namespace.concat([name]).join('.');
if (namespace.length === 0) this.emit(`var `);
this.emit(`${qualifiedName};\n`);
}
private writeExternsFunction(name: string, params: string[], namespace: string[]) {
let paramsStr = params.map(makeLegalExternsParam).join(', ');
if (namespace.length > 0) {
name = namespace.concat([name]).join('.');
this.emit(`${name} = function(${params}) {};\n`);
this.emit(`${name} = function(${paramsStr}) {};\n`);
} else {
this.emit(`function ${name}(${params}) {}\n`);
this.emit(`function ${name}(${paramsStr}) {}\n`);
}

@@ -948,3 +1119,18 @@ }

for (let member of decl.members) {
let memberName = member.name.getText();
let memberName: string|undefined;
switch (member.name.kind) {
case ts.SyntaxKind.Identifier:
memberName = getIdentifierText(member.name as ts.Identifier);
break;
case ts.SyntaxKind.StringLiteral:
let text = (member.name as ts.StringLiteral).text;
if (isValidClosurePropertyName(text)) memberName = text;
break;
default:
break;
}
if (!memberName) {
this.emit(`\n/* TODO: ${ts.SyntaxKind[member.name.kind]}: ${member.name.getText()} */\n`);
continue;
}
let name = namespace.concat([memberName]).join('.');

@@ -955,2 +1141,7 @@ this.emit('/** @const {number} */\n');

}
private writeExternsTypeAlias(decl: ts.TypeAliasDeclaration, namespace: string[]) {
this.emit(`\n/** @typedef {${this.typeToClosure(decl)}} */\n`);
this.writeExternsVariable(getIdentifierText(decl.name), namespace);
}
}

@@ -957,0 +1148,0 @@

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript';

@@ -118,3 +126,5 @@

let writeText = (text: string) => str += text;
let doNothing = () => { return; };
let doNothing = () => {
return;
};

@@ -121,0 +131,0 @@ let builder = this.typeChecker.getSymbolDisplayBuilder();

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// toArray is a temporary function to help in the use of

@@ -2,0 +10,0 @@ // ES6 maps and sets when running on node 4, which doesn't

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

goog.module('test_files.abstract.abstract');var module = module || {id: 'test_files/abstract/abstract.js'};class Base {
goog.module('test_files.abstract.abstract');var module = module || {id: 'test_files/abstract/abstract.js'};/**
* @abstract
*/
class Base {
/**

@@ -40,4 +43,2 @@ * @abstract

class Derived extends Base {
/**
*/
constructor() {

@@ -44,0 +45,0 @@ super();

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

/**
* @abstract
*/
abstract class Base {

@@ -41,4 +44,2 @@ /**

class Derived extends Base {
/**
*/
constructor() {

@@ -45,0 +46,0 @@ super();

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

/** @externs */
/**
* @externs
* @suppress {duplicate}
*/
// NOTE: generated by tsickle, do not edit.
/** @constructor @struct */

@@ -4,0 +8,0 @@ function ClassAndNamespace() {}

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

/** @externs */
/**
* @externs
* @suppress {duplicate}
*/
// NOTE: generated by tsickle, do not edit.

@@ -9,2 +12,3 @@ /** @const */

DeclareTestModule.inner.someBool;
/** @record @struct */

@@ -34,2 +38,3 @@ DeclareTestModule.Foo = function() {};

DeclareTestModule.Clazz.prototype.method = function(a) {};
/** @record @struct */

@@ -46,2 +51,12 @@ DeclareTestModule.NotYetHandled = function() {};

DeclareTestModule.Enumeration.Value3;
/** @const */
DeclareTestModule.StringEnum = {};
/** @const {number} */
DeclareTestModule.StringEnum.foo;
/* TODO: StringLiteral: '.tricky.invalid name' */
/** @typedef {(string|number)} */
DeclareTestModule.TypeAlias;
/** @type {number} */

@@ -55,2 +70,3 @@ var declareGlobalVar;

function declareGlobalFunction(x) {}
/** @record @struct */

@@ -64,4 +80,5 @@ function DeclareTestInterface() {}

* @struct
* @param {number} opt_a
*/
function MultipleConstructors() {}
function MultipleConstructors(opt_a) {}

@@ -72,1 +89,30 @@ /**

Object.prototype.myMethod = function() {};
/**
* @param {string} x
* @return {CodeMirror.Editor}
*/
function CodeMirror(x) {}
/**
* @param {number} y
* @param {string} x
* @return {CodeMirror.Editor}
*/
function CodeMirror(y, x) {}
/** @record @struct */
CodeMirror.Editor = function() {};
/** @type {string} */
CodeMirror.Editor.prototype.name;
/** @record @struct */
function BareInterface() {}
/** @type {string} */
BareInterface.prototype.name;
/**
* @param {string} tsickle_arguments
* @return {?}
*/
function usesArguments(tsickle_arguments) {}

@@ -10,3 +10,3 @@ goog.module('test_files.export.export');var module = module || {id: 'test_files/export/export.js'};

exports.export1 = 'wins';
var export_helper_2 = export_helper_1;
var export_helper_2 = goog.require('test_files.export.export_helper');
exports.export3 = export_helper_2.export4;

@@ -20,3 +20,3 @@ // This local should be fine to export.

// This is just an import, so export5 should still be included.
var export_helper_3 = export_helper_1;
var export_helper_3 = goog.require('test_files.export.export_helper');
const export5 = export_helper_3.export5; /* local alias for Closure JSDoc */

@@ -8,4 +8,4 @@ goog.module('test_files.jsdoc_types.untyped.jsdoc_types');var module = module || {id: 'test_files/jsdoc_types.untyped/jsdoc_types.js'};/**

var module2_1 = goog.require('test_files.jsdoc_types.untyped.module2');
var module2_2 = module2_1;
var module2_3 = module2_1;
var module2_2 = goog.require('test_files.jsdoc_types.untyped.module2');
var module2_3 = goog.require('test_files.jsdoc_types.untyped.module2');
var default_1 = goog.require('test_files.jsdoc_types.untyped.default');

@@ -12,0 +12,0 @@ // Check that imported types get the proper names in JSDoc.

@@ -10,9 +10,9 @@ goog.module('test_files.jsdoc_types.jsdoc_types');var module = module || {id: 'test_files/jsdoc_types/jsdoc_types.js'};/**

const value = module2_1.value; /* local alias for Closure JSDoc */
var module2_2 = module2_1;
var module2_2 = goog.require('test_files.jsdoc_types.module2');
const RenamedClassOne = module2_2.ClassOne; /* local alias for Closure JSDoc */
var module2_3 = module2_1;
var module2_3 = goog.require('test_files.jsdoc_types.module2');
const RenamedClassTwo = module2_3.ClassTwo; /* local alias for Closure JSDoc */
var module2_4 = module2_1;
var module2_4 = goog.require('test_files.jsdoc_types.module2');
const Interface = module2_4.Interface; /* local alias for Closure JSDoc */
var module2_5 = module2_1;
var module2_5 = goog.require('test_files.jsdoc_types.module2');
const ClassWithParams = module2_5.ClassWithParams; /* local alias for Closure JSDoc */

@@ -19,0 +19,0 @@ var default_1 = goog.require('test_files.jsdoc_types.default');

@@ -1,7 +0,12 @@

/** @externs */
/**
* @externs
* @suppress {duplicate}
*/
// NOTE: generated by tsickle, do not edit.
/** @const */
var JSX = {};
/** @record @struct */
JSX.Element = function() {};
/** @record @struct */

@@ -8,0 +13,0 @@ JSX.IntrinsicElements = function() {};

goog.module('test_files.super.super');var module = module || {id: 'test_files/super/super.js'};class SuperTestBaseNoArg {
/**
*/
constructor() {

@@ -35,4 +33,2 @@ }

class SuperTestDerivedInitializedProps extends SuperTestBaseOneArg {
/**
*/
constructor() {

@@ -49,4 +45,2 @@ super(3);

class SuperTestDerivedOrdinary extends SuperTestBaseOneArg {
/**
*/
constructor() {

@@ -53,0 +47,0 @@ super(3);

class SuperTestBaseNoArg {
/**
*/
constructor() {}

@@ -39,4 +37,2 @@ }

y: string = 'foo';
/**
*/
constructor() {

@@ -55,4 +51,2 @@ super(3);

class SuperTestDerivedOrdinary extends SuperTestBaseOneArg {
/**
*/
constructor() {

@@ -59,0 +53,0 @@ super(3);

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

/** @externs */
/**
* @externs
* @suppress {duplicate}
*/
// NOTE: generated by tsickle, do not edit.

@@ -3,0 +6,0 @@ /** @const */

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {expect} from 'chai';

@@ -50,3 +58,5 @@ import * as ts from 'typescript';

describe('class decorator rewriter', () => {
it('leaves plain classes alone', () => { expectUnchanged(`class Foo {}`); });
it('leaves plain classes alone', () => {
expectUnchanged(`class Foo {}`);
});

@@ -53,0 +63,0 @@ it('leaves un-marked decorators alone', () => {

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as fs from 'fs';

@@ -18,2 +26,3 @@ import * as closure from 'google-closure-compiler';

'language_in': 'ECMASCRIPT6_STRICT',
'language_out': 'ECMASCRIPT5',
};

@@ -20,0 +29,0 @@

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {expect} from 'chai';

@@ -9,3 +17,4 @@

return expect(
es5processor.processES5(fileName, content, cliSupport.pathToModuleName, isES5).output);
es5processor.processES5(fileName, fileName, content, cliSupport.pathToModuleName, isES5)
.output);
}

@@ -92,3 +101,3 @@

`goog.module('a');var module = module || {id: 'a.js'};var tsickle_module_0_ = goog.require('req.mod');__export(tsickle_module_0_);
var mod2 = tsickle_module_0_;`);
var mod2 = goog.require('req.mod');`);
});

@@ -158,3 +167,3 @@ it('reuses an existing imported variable name', () => {

`).to.equal(`goog.module('a.b');var module = module || {id: 'a/b.js'};var foo_1 = goog.require('foo');
var foo_2 = foo_1;
var foo_2 = goog.require('foo');
foo_1.A, foo_2.B, foo_2 , foo_3.default;

@@ -166,8 +175,8 @@ `);

let {referencedModules} = es5processor.processES5(
'a/b', `
require('../foo/bare-require');
'a/b', 'a/b', `
require('../foo/bare_require');
var googRequire = require('goog:foo.bar');
var es6RelativeRequire = require('./relative');
var es6NonRelativeRequire = require('non/relative');
__export(require('./export-star');
__export(require('./export_star');
`,

@@ -177,9 +186,9 @@ cliSupport.pathToModuleName);

return expect(referencedModules).to.deep.equal([
'foo.bare-require',
'foo.bare_require',
'foo.bar',
'a.relative',
'non.relative',
'a.export-star',
'a.export_star',
]);
});
});

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {expect} from 'chai';

@@ -2,0 +10,0 @@

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as fs from 'fs';

@@ -64,4 +72,5 @@ import * as glob from 'glob';

let {diagnostics} = program.emit(undefined, (fileName: string, data: string) => {
const moduleId = fileName.replace(/^\.\//, '');
transformed[fileName] =
tsickle.convertCommonJsToGoogModule(fileName, data, cliSupport.pathToModuleName).output;
tsickle.processES5(fileName, moduleId, data, cliSupport.pathToModuleName).output;
});

@@ -77,3 +86,3 @@ if (diagnostics.length > 0) {

path: string;
// Input .ts/.tsx file names.
// Input .ts/.tsx/.d.ts file names.
tsFiles: string[];

@@ -86,13 +95,22 @@

get name(): string { return path.basename(this.path); }
get name(): string {
return path.basename(this.path);
}
get externsPath(): string { return path.join(this.path, 'externs.js'); }
get externsPath(): string {
return path.join(this.path, 'externs.js');
}
get tsPaths(): string[] { return this.tsFiles.map(f => path.join(this.path, f)); }
get tsPaths(): string[] {
return this.tsFiles.map(f => path.join(this.path, f));
}
get jsPaths(): string[] {
return this.tsFiles.map(f => path.join(this.path, GoldenFileTest.tsPathToJs(f)));
return this.tsFiles.filter(f => !/\.d\.ts/.test(f))
.map(f => path.join(this.path, GoldenFileTest.tsPathToJs(f)));
}
public static tsPathToJs(tsPath: string): string { return tsPath.replace(/\.tsx?$/, '.js'); }
public static tsPathToJs(tsPath: string): string {
return tsPath.replace(/\.tsx?$/, '.js');
}
}

@@ -99,0 +117,0 @@

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {expect} from 'chai';

@@ -119,3 +127,5 @@ import * as fs from 'fs';

let warnings: ts.Diagnostic[] = [];
options.logWarning = (diag: ts.Diagnostic) => { warnings.push(diag); };
options.logWarning = (diag: ts.Diagnostic) => {
warnings.push(diag);
};
// Run TypeScript through tsickle and compare against goldens.

@@ -139,3 +149,3 @@ let {output, externs, diagnostics} =

}
let tsicklePath = tsPath.replace(/.ts(x)?$/, '.tsickle.ts$1');
let tsicklePath = tsPath.replace(/((\.d)?\.tsx?)$/, '.tsickle$1');
expect(tsicklePath).to.not.equal(tsPath);

@@ -142,0 +152,0 @@ compareAgainstGolden(fileOutput, tsicklePath);

@@ -0,1 +1,9 @@

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {expect} from 'chai';

@@ -2,0 +10,0 @@

@@ -6,13 +6,15 @@ {

"noImplicitAny": true,
"noEmit": true,
"noEmitOnError": true,
"target": "es5",
"lib": ["es5", "es2015.collection", "es2015.iterable", "dom"],
"jsx": "react",
"types": ["node", "mocha"],
"strictNullChecks": true
},
"files": [
"src/cli_support.ts",
"src/decorator-annotator.ts",
"src/es5processor.ts",
"src/jsdoc.ts",
"src/main.ts",
"src/jsdoc.ts",
"src/rewriter.ts",

@@ -26,7 +28,7 @@ "src/tsickle.ts",

"test/jsdoc_test.ts",
"test/source_map_test.ts",
"test/test_support.ts",
"test/tsickle_test.ts",
"test/type-translator_test.ts",
"typings/tsd.d.ts"
"test/type-translator_test.ts"
]
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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