api-builder: update to dgeni-packages 0.12.0 - factoring out the typescript package
This commit is contained in:
		
							parent
							
								
									aaa927bc43
								
							
						
					
					
						commit
						ac583748d1
					
				| @ -34,7 +34,7 @@ | ||||
|     "codelyzer": "0.0.18", | ||||
|     "del": "^1.2.0", | ||||
|     "dgeni": "^0.4.0", | ||||
|     "dgeni-packages": "^0.11.1", | ||||
|     "dgeni-packages": "^0.12.0", | ||||
|     "diff": "^2.1.3", | ||||
|     "fs-extra": "^0.24.0", | ||||
|     "glob": "^5.0.14", | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| var Package = require('dgeni').Package; | ||||
| var jsdocPackage = require('dgeni-packages/jsdoc'); | ||||
| var nunjucksPackage = require('dgeni-packages/nunjucks'); | ||||
| var typescriptPackage = require('../typescript-package'); | ||||
| var typescriptPackage = require('dgeni-packages/typescript'); | ||||
| var linksPackage = require('../links-package'); | ||||
| var gitPackage = require('dgeni-packages/git'); | ||||
| var path = require('canonical-path'); | ||||
|  | ||||
| @ -1,73 +0,0 @@ | ||||
| var basePackage = require('dgeni-packages/base'); | ||||
| var Package = require('dgeni').Package; | ||||
| var path = require('canonical-path'); | ||||
| 
 | ||||
| // Define the dgeni package for generating the docs
 | ||||
| module.exports = new Package('typescript-parsing', [basePackage]) | ||||
| 
 | ||||
| // Register the services and file readers
 | ||||
| .factory(require('./services/modules')) | ||||
| .factory(require('./services/tsParser')) | ||||
| .factory(require('./services/tsParser/createCompilerHost')) | ||||
| .factory(require('./services/tsParser/getFileInfo')) | ||||
| .factory(require('./services/tsParser/getExportDocType')) | ||||
| .factory(require('./services/tsParser/getContent')) | ||||
| 
 | ||||
| .factory(require('./services/convertPrivateClassesToInterfaces')) | ||||
| 
 | ||||
| .factory('EXPORT_DOC_TYPES', function() { | ||||
|   return [ | ||||
|     'class', | ||||
|     'interface', | ||||
|     'function', | ||||
|     'var', | ||||
|     'const', | ||||
|     'let', | ||||
|     'enum', | ||||
|     'type-alias' | ||||
|   ]; | ||||
| }) | ||||
| 
 | ||||
| 
 | ||||
| // Register the processors
 | ||||
| .processor(require('./processors/readTypeScriptModules')) | ||||
| 
 | ||||
| 
 | ||||
| // Configure the log service
 | ||||
| .config(function(log) { | ||||
|   log.level = 'warn'; | ||||
| }) | ||||
| 
 | ||||
| 
 | ||||
| // Configure ids and paths
 | ||||
| .config(function(computeIdsProcessor, computePathsProcessor, EXPORT_DOC_TYPES) { | ||||
| 
 | ||||
|   computeIdsProcessor.idTemplates.push({ | ||||
|     docTypes: ['member'], | ||||
|     idTemplate: '${classDoc.id}.${name}', | ||||
|     getAliases: function(doc) { | ||||
|       return doc.classDoc.aliases.map(function(alias) { return alias + '.' + doc.name; }); | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   computePathsProcessor.pathTemplates.push({ | ||||
|     docTypes: ['member'], | ||||
|     pathTemplate: '${classDoc.path}#${name}', | ||||
|     getOutputPath: function() {} // These docs are not written to their own file, instead they are part of their class doc
 | ||||
|   }); | ||||
| 
 | ||||
|   var MODULES_DOCS_PATH = 'partials/modules'; | ||||
| 
 | ||||
|   computePathsProcessor.pathTemplates.push({ | ||||
|     docTypes: ['module'], | ||||
|     pathTemplate: '/${id}', | ||||
|     outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.html' | ||||
|   }); | ||||
| 
 | ||||
|   computePathsProcessor.pathTemplates.push({ | ||||
|     docTypes: EXPORT_DOC_TYPES, | ||||
|     pathTemplate: '${moduleDoc.path}/${name}', | ||||
|     outputPathTemplate: MODULES_DOCS_PATH + '/${path}/index.html' | ||||
|   }); | ||||
| 
 | ||||
| }); | ||||
| @ -1,11 +0,0 @@ | ||||
| var Package = require('dgeni').Package; | ||||
| 
 | ||||
| module.exports = function mockPackage() { | ||||
| 
 | ||||
|   return new Package('mockPackage', [require('../')]) | ||||
| 
 | ||||
|   // provide a mock log service
 | ||||
|   .factory('log', function() { return require('dgeni/lib/mocks/log')(false); }) | ||||
|   .factory('templateEngine', function() { return {}; }); | ||||
| 
 | ||||
| }; | ||||
| @ -1,4 +0,0 @@ | ||||
| export var __esModule = true; | ||||
| export class OKToExport {} | ||||
| export function _thisIsPrivate() {} | ||||
| export var thisIsOK = '!'; | ||||
| @ -1,5 +0,0 @@ | ||||
| export interface MyInterface { | ||||
|   optionalProperty? : string | ||||
|   <T, U extends Findable<T>>(param: T) : U | ||||
|   new (param: number) : MyInterface | ||||
| } | ||||
| @ -1,6 +0,0 @@ | ||||
| export class Test { | ||||
|   firstItem; | ||||
|   constructor() { this.doStuff(); } | ||||
|   otherMethod() {} | ||||
|   doStuff() {} | ||||
| } | ||||
| @ -1 +0,0 @@ | ||||
| export var x = 10; | ||||
| @ -1,3 +0,0 @@ | ||||
| export { x as y} from './privateModule'; | ||||
| 
 | ||||
| export abstract class AbstractClass {} | ||||
| @ -1 +0,0 @@ | ||||
| export var x = 100; | ||||
| @ -1,34 +0,0 @@ | ||||
| /** | ||||
|  * @module | ||||
|  * @description | ||||
|  * This is the module description | ||||
|  */ | ||||
| 
 | ||||
| export * from 'importedSrc'; | ||||
| 
 | ||||
| /** | ||||
|  * This is some random other comment | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * This is MyClass | ||||
|  */ | ||||
| export class MyClass { | ||||
|   message: String; | ||||
| 
 | ||||
|   /** | ||||
|    * Create a new MyClass | ||||
|    * @param {String} name The name to say hello to | ||||
|    */ | ||||
|   constructor(name) { this.message = 'hello ' + name; } | ||||
| 
 | ||||
|   /** | ||||
|    * Return a greeting message | ||||
|    */ | ||||
|   greet() { return this.message; } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * An exported function | ||||
|  */ | ||||
| export var myFn = (val: number) => return val * 2; | ||||
| @ -1,451 +0,0 @@ | ||||
| var glob = require('glob'); | ||||
| var path = require('canonical-path'); | ||||
| var _ = require('lodash'); | ||||
| var ts = require('typescript'); | ||||
| 
 | ||||
| module.exports = function readTypeScriptModules(tsParser, modules, getFileInfo, | ||||
|                                                 getExportDocType, getContent, createDocMessage, log) { | ||||
| 
 | ||||
|   return { | ||||
|     $runAfter: ['files-read'], | ||||
|     $runBefore: ['parsing-tags'], | ||||
| 
 | ||||
|     $validate: { | ||||
|       sourceFiles: {presence: true}, | ||||
|       basePath: {presence: true}, | ||||
|       hidePrivateMembers: {inclusion: [true, false]}, | ||||
|       sortClassMembers: {inclusion: [true, false]}, | ||||
|       ignoreExportsMatching: {} | ||||
|     }, | ||||
| 
 | ||||
|     // A collection of globs that identify those modules for which we should create docs
 | ||||
|     sourceFiles: [], | ||||
|     // The base path from which to load the source files
 | ||||
|     basePath: '.', | ||||
|     // We can ignore members of classes that are private
 | ||||
|     hidePrivateMembers: true, | ||||
|     // We leave class members sorted in order of declaration
 | ||||
|     sortClassMembers: false, | ||||
|     // We can provide a collection of strings or regexes to ignore exports whose export names match
 | ||||
|     ignoreExportsMatching: ['___esModule', '___core_private_types__', '___platform_browser_private__', '___compiler_private__', '__core_private__', '___core_private__'], | ||||
| 
 | ||||
|     $process: function(docs) { | ||||
| 
 | ||||
|       // Convert ignoreExportsMatching to an array of regexes
 | ||||
|       var ignoreExportsMatching = convertToRegexCollection(this.ignoreExportsMatching); | ||||
| 
 | ||||
|       var hidePrivateMembers = this.hidePrivateMembers; | ||||
|       var sortClassMembers = this.sortClassMembers; | ||||
| 
 | ||||
|       var basePath = path.resolve(this.basePath); | ||||
|       var filesPaths = expandSourceFiles(this.sourceFiles, basePath); | ||||
|       var parseInfo = tsParser.parse(filesPaths, this.basePath); | ||||
|       var moduleSymbols = parseInfo.moduleSymbols; | ||||
| 
 | ||||
|       // Iterate through each of the modules that were parsed and generate a module doc
 | ||||
|       // as well as docs for each module's exports.
 | ||||
|       moduleSymbols.forEach(function(moduleSymbol) { | ||||
| 
 | ||||
|         var moduleDoc = createModuleDoc(moduleSymbol, basePath); | ||||
| 
 | ||||
|         // Add this module doc to the module lookup collection and the docs collection
 | ||||
|         modules[moduleDoc.id] = moduleDoc; | ||||
|         docs.push(moduleDoc); | ||||
| 
 | ||||
|         // Iterate through this module's exports and generate a doc for each
 | ||||
|         moduleSymbol.exportArray.forEach(function(exportSymbol) { | ||||
| 
 | ||||
|           // Ignore exports starting with an underscore
 | ||||
|           if (anyMatches(ignoreExportsMatching, exportSymbol.name)) return; | ||||
| 
 | ||||
|           // If the symbol is an Alias then for most things we want the original resolved symbol
 | ||||
|           var resolvedExport = exportSymbol.resolvedSymbol || exportSymbol; | ||||
| 
 | ||||
|           // If the resolved symbol contains no declarations then it is invalid
 | ||||
|           // (probably an abstract class)
 | ||||
|           // For the moment we are just going to ignore such exports
 | ||||
|           // TODO: find a way of generating docs for them
 | ||||
|           if (!resolvedExport.declarations) return; | ||||
| 
 | ||||
|           var exportDoc = createExportDoc(exportSymbol.name, resolvedExport, moduleDoc, basePath, parseInfo.typeChecker); | ||||
|           log.debug('>>>> EXPORT: ' + exportDoc.name + ' (' + exportDoc.docType + ') from ' + moduleDoc.id); | ||||
| 
 | ||||
|           // Add this export doc to its module doc
 | ||||
|           moduleDoc.exports.push(exportDoc); | ||||
|           docs.push(exportDoc); | ||||
| 
 | ||||
|           exportDoc.members = []; | ||||
|           exportDoc.statics = []; | ||||
| 
 | ||||
|           // Generate docs for each of the export's members
 | ||||
|           if (resolvedExport.flags & ts.SymbolFlags.HasMembers) { | ||||
| 
 | ||||
|             for(var memberName in resolvedExport.members) { | ||||
|               // FIXME(alexeagle): why do generic type params appear in members?
 | ||||
|               if (memberName === 'T') { | ||||
|                 continue; | ||||
|               } | ||||
|               log.silly('>>>>>> member: ' + memberName + ' from ' + exportDoc.id + ' in ' + moduleDoc.id); | ||||
|               var memberSymbol = resolvedExport.members[memberName]; | ||||
|               var memberDoc = createMemberDoc(memberSymbol, exportDoc, basePath, parseInfo.typeChecker); | ||||
| 
 | ||||
|               // We special case the constructor and sort the other members alphabetically
 | ||||
|               if (memberSymbol.flags & ts.SymbolFlags.Constructor) { | ||||
|                 exportDoc.constructorDoc = memberDoc; | ||||
|                 docs.push(memberDoc); | ||||
|               } else if (!hidePrivateMembers || memberSymbol.name.charAt(0) !== '_') { | ||||
|                 docs.push(memberDoc); | ||||
|                 exportDoc.members.push(memberDoc); | ||||
|               } else if (memberSymbol.name === '__call' && memberSymbol.flags & ts.SymbolFlags.Signature) { | ||||
|                 docs.push(memberDoc); | ||||
|                 exportDoc.callMember = memberDoc; | ||||
|               } else if (memberSymbol.name === '__new' && memberSymbol.flags & ts.SymbolFlags.Signature) { | ||||
|                 docs.push(memberDoc); | ||||
|                 exportDoc.newMember = memberDoc; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           if (exportDoc.docType === 'enum') { | ||||
|             for(var memberName in resolvedExport.exports) { | ||||
|               log.silly('>>>>>> member: ' + memberName + ' from ' + exportDoc.id + ' in ' + moduleDoc.id); | ||||
|               var memberSymbol = resolvedExport.exports[memberName]; | ||||
|               var memberDoc = createMemberDoc(memberSymbol, exportDoc, basePath, parseInfo.typeChecker); | ||||
|               docs.push(memberDoc); | ||||
|               exportDoc.members.push(memberDoc); | ||||
|             } | ||||
|           } else if (resolvedExport.flags & ts.SymbolFlags.HasExports) { | ||||
|             for (var exported in resolvedExport.exports) { | ||||
|               if (exported === 'prototype') continue; | ||||
|               if (hidePrivateMembers && exported.charAt(0) === '_') continue; | ||||
|               var memberSymbol = resolvedExport.exports[exported]; | ||||
|               var memberDoc = createMemberDoc(memberSymbol, exportDoc, basePath, parseInfo.typeChecker); | ||||
|               memberDoc.isStatic = true; | ||||
|               docs.push(memberDoc); | ||||
|               exportDoc.statics.push(memberDoc); | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           if (sortClassMembers) { | ||||
|             exportDoc.members.sort(function(a, b) { | ||||
|               if (a.name > b.name) return 1; | ||||
|               if (a.name < b.name) return -1; | ||||
|               return 0; | ||||
|             }); | ||||
|             exportDoc.statics.sort(function(a, b) { | ||||
|               if (a.name > b.name) return 1; | ||||
|               if (a.name < b.name) return -1; | ||||
|               return 0; | ||||
|             }); | ||||
|           } | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
|   function createModuleDoc(moduleSymbol, basePath) { | ||||
|     var id = moduleSymbol.name.replace(/^"|"$/g, ''); | ||||
|     var name = id.split('/').pop(); | ||||
|     var moduleDoc = { | ||||
|       docType: 'module', | ||||
|       name: name, | ||||
|       id: id, | ||||
|       aliases: [id, name], | ||||
|       moduleTree: moduleSymbol, | ||||
|       content: getContent(moduleSymbol), | ||||
|       exports: [], | ||||
|       fileInfo: getFileInfo(moduleSymbol, basePath), | ||||
|       location: getLocation(moduleSymbol) | ||||
|     }; | ||||
|     return moduleDoc; | ||||
|   } | ||||
| 
 | ||||
|   function createExportDoc(name, exportSymbol, moduleDoc, basePath, typeChecker) { | ||||
|     var typeParamString = ''; | ||||
|     var heritageString = ''; | ||||
|     var typeDefinition = ''; | ||||
| 
 | ||||
|     exportSymbol.declarations.forEach(function(decl) { | ||||
|       var sourceFile = ts.getSourceFileOfNode(decl); | ||||
| 
 | ||||
|       if (decl.typeParameters) { | ||||
|         typeParamString = '<' + getText(sourceFile, decl.typeParameters) + '>'; | ||||
|       } | ||||
| 
 | ||||
|       if (decl.symbol.flags & ts.SymbolFlags.TypeAlias) { | ||||
|         typeDefinition = getText(sourceFile, decl.type); | ||||
|       } | ||||
| 
 | ||||
|       if (decl.heritageClauses) { | ||||
|         decl.heritageClauses.forEach(function(heritage) { | ||||
| 
 | ||||
|           if (heritage.token == ts.SyntaxKind.ExtendsKeyword) { | ||||
|             heritageString += " extends"; | ||||
|             heritage.types.forEach(function(typ, idx) { | ||||
|               heritageString += (idx > 0 ? ',' : '') + typ.getFullText(); | ||||
|             }); | ||||
|           } | ||||
| 
 | ||||
|           if (heritage.token == ts.SyntaxKind.ImplementsKeyword) { | ||||
|             heritageString += " implements"; | ||||
|             heritage.types.forEach(function(typ, idx) { | ||||
|               heritageString += (idx > 0 ? ', ' : '') + typ.getFullText(); | ||||
|             }); | ||||
|           } | ||||
|         }); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     //Make sure duplicate aliases aren't created, so "Ambiguous link" warnings are prevented
 | ||||
|     var aliasNames = [name, moduleDoc.id + '/' + name]; | ||||
|     if (typeParamString) { | ||||
|       aliasNames.push(name + typeParamString); | ||||
|       aliasNames.push(moduleDoc.id + '/' + name + typeParamString); | ||||
|     } | ||||
| 
 | ||||
|     var exportDoc = { | ||||
|       docType: getExportDocType(exportSymbol), | ||||
|       exportSymbol: exportSymbol, | ||||
|       name: name, | ||||
|       id: moduleDoc.id + '/' + name, | ||||
|       typeParams: typeParamString, | ||||
|       heritage: heritageString, | ||||
|       decorators: getDecorators(exportSymbol), | ||||
|       aliases: aliasNames, | ||||
|       moduleDoc: moduleDoc, | ||||
|       content: getContent(exportSymbol), | ||||
|       fileInfo: getFileInfo(exportSymbol, basePath), | ||||
|       location: getLocation(exportSymbol) | ||||
|     }; | ||||
| 
 | ||||
|     if (exportDoc.docType === 'var' || exportDoc.docType === 'const' || exportDoc.docType === 'let') { | ||||
|       exportDoc.symbolTypeName = exportSymbol.valueDeclaration.type && | ||||
|                                  exportSymbol.valueDeclaration.type.typeName && | ||||
|                                  exportSymbol.valueDeclaration.type.typeName.text; | ||||
|     } | ||||
| 
 | ||||
|     if (exportDoc.docType === 'type-alias') { | ||||
|       exportDoc.returnType = getReturnType(typeChecker, exportSymbol); | ||||
|     } | ||||
| 
 | ||||
|     if(exportSymbol.flags & ts.SymbolFlags.Function) { | ||||
|       exportDoc.parameters = getParameters(typeChecker, exportSymbol); | ||||
|     } | ||||
|     if(exportSymbol.flags & ts.SymbolFlags.Value) { | ||||
|       exportDoc.returnType = getReturnType(typeChecker, exportSymbol); | ||||
|     } | ||||
|     if (exportSymbol.flags & ts.SymbolFlags.TypeAlias) { | ||||
|       exportDoc.typeDefinition = typeDefinition; | ||||
|     } | ||||
| 
 | ||||
|     // Compute the original module name from the relative file path
 | ||||
|     exportDoc.originalModule = exportDoc.fileInfo.relativePath | ||||
|         .replace(new RegExp('\.' + exportDoc.fileInfo.extension + '$'), ''); | ||||
| 
 | ||||
|     return exportDoc; | ||||
|   } | ||||
| 
 | ||||
|   function createMemberDoc(memberSymbol, classDoc, basePath, typeChecker) { | ||||
|     var memberDoc = { | ||||
|       docType: 'member', | ||||
|       classDoc: classDoc, | ||||
|       name: memberSymbol.name, | ||||
|       decorators: getDecorators(memberSymbol), | ||||
|       content: getContent(memberSymbol), | ||||
|       fileInfo: getFileInfo(memberSymbol, basePath), | ||||
|       location: getLocation(memberSymbol) | ||||
|     }; | ||||
| 
 | ||||
|     memberDoc.typeParameters = getTypeParameters(typeChecker, memberSymbol); | ||||
| 
 | ||||
|     if(memberSymbol.flags & (ts.SymbolFlags.Signature) ) { | ||||
|       memberDoc.parameters = getParameters(typeChecker, memberSymbol); | ||||
|       memberDoc.returnType = getReturnType(typeChecker, memberSymbol); | ||||
|       switch(memberDoc.name) { | ||||
|         case '__call': | ||||
|           memberDoc.name = ''; | ||||
|           break; | ||||
|         case '__new': | ||||
|           memberDoc.name = 'new'; | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (memberSymbol.flags & ts.SymbolFlags.Method) { | ||||
|       // NOTE: we use the property name `parameters` here so we don't conflict
 | ||||
|       // with the `params` property that will be updated by dgeni reading the
 | ||||
|       // `@param` tags from the docs
 | ||||
|       memberDoc.parameters = getParameters(typeChecker, memberSymbol); | ||||
|     } | ||||
| 
 | ||||
|     if (memberSymbol.flags & ts.SymbolFlags.Constructor) { | ||||
|       memberDoc.parameters = getParameters(typeChecker, memberSymbol); | ||||
|       memberDoc.name = 'constructor'; | ||||
|     } | ||||
| 
 | ||||
|     if(memberSymbol.flags & ts.SymbolFlags.Value) { | ||||
|       memberDoc.returnType = getReturnType(typeChecker, memberSymbol); | ||||
|     } | ||||
| 
 | ||||
|     if(memberSymbol.flags & ts.SymbolFlags.Optional) { | ||||
|       memberDoc.optional = true; | ||||
|     } | ||||
| 
 | ||||
|     return memberDoc; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   function getDecorators(symbol) { | ||||
| 
 | ||||
|     var declaration = symbol.valueDeclaration || symbol.declarations[0]; | ||||
|     var sourceFile = ts.getSourceFileOfNode(declaration); | ||||
| 
 | ||||
|     var decorators = declaration.decorators && declaration.decorators.map(function(decorator) { | ||||
|       decorator = decorator.expression; | ||||
|       return { | ||||
|         name: decorator.expression ? decorator.expression.text : decorator.text, | ||||
|         arguments: decorator.arguments && decorator.arguments.map(function(argument) { | ||||
|           return getText(sourceFile, argument).trim(); | ||||
|         }), | ||||
|         argumentInfo: decorator.arguments && decorator.arguments.map(function(argument) { | ||||
|           return parseArgument(argument); | ||||
|         }), | ||||
|         expression: decorator | ||||
|       }; | ||||
|     }); | ||||
|     return decorators; | ||||
|   } | ||||
| 
 | ||||
|   function parseProperties(properties) { | ||||
|     var result = {}; | ||||
|     _.forEach(properties, function(property) { | ||||
|       result[property.name.text] = parseArgument(property.initializer); | ||||
|     }); | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   function parseArgument(argument) { | ||||
|     if (argument.text) return argument.text; | ||||
|     if (argument.properties) return parseProperties(argument.properties); | ||||
|     if (argument.elements) return argument.elements.map(function(element) { return element.text; }); | ||||
|     var sourceFile = ts.getSourceFileOfNode(argument); | ||||
|     var text = getText(sourceFile, argument).trim(); | ||||
|     return text; | ||||
|   } | ||||
| 
 | ||||
|   function getParameters(typeChecker, symbol) { | ||||
|     var declaration = symbol.valueDeclaration || symbol.declarations[0]; | ||||
|     var sourceFile = ts.getSourceFileOfNode(declaration); | ||||
|     if (!declaration.parameters) { | ||||
|       var location = getLocation(symbol); | ||||
|       throw new Error('missing declaration parameters for "' + symbol.name + | ||||
|         '" in ' + sourceFile.fileName + | ||||
|         ' at line ' + location.start.line); | ||||
|     } | ||||
|     return declaration.parameters.map(function(parameter) { | ||||
|       var paramText = ''; | ||||
|       if (parameter.dotDotDotToken) { | ||||
|         paramText += '...'; | ||||
|       } | ||||
|       paramText += getText(sourceFile, parameter.name); | ||||
|       if (parameter.questionToken || parameter.initializer) { | ||||
|         paramText += '?'; | ||||
|       } | ||||
|       if (parameter.type) { | ||||
|         paramText += ':' + getType(sourceFile, parameter.type); | ||||
|       } else { | ||||
|         paramText += ': any'; | ||||
|         if (parameter.dotDotDotToken) { | ||||
|           paramText += '[]'; | ||||
|         } | ||||
|       } | ||||
|       return paramText.trim(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function getTypeParameters(typeChecker, symbol) { | ||||
|     var declaration = symbol.valueDeclaration || symbol.declarations[0]; | ||||
|     var sourceFile = ts.getSourceFileOfNode(declaration); | ||||
|     if (!declaration.typeParameters) return; | ||||
|     var typeParams = declaration.typeParameters.map(function(type) { | ||||
|       return getText(sourceFile, type).trim(); | ||||
|     }); | ||||
|     return typeParams; | ||||
|   } | ||||
| 
 | ||||
|   function getReturnType(typeChecker, symbol) { | ||||
|     var declaration = symbol.valueDeclaration || symbol.declarations[0]; | ||||
|     var sourceFile = ts.getSourceFileOfNode(declaration); | ||||
|     if (declaration.type) { | ||||
|       return getType(sourceFile, declaration.type).trim(); | ||||
|     } else if (declaration.initializer) { | ||||
|       // The symbol does not have a "type" but it is being initialized
 | ||||
|       // so we can deduce the type of from the initializer (mostly).
 | ||||
|       if (declaration.initializer.expression) { | ||||
|         return declaration.initializer.expression.text.trim(); | ||||
|       } else { | ||||
|         return getType(sourceFile, declaration.initializer).trim(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   function expandSourceFiles(sourceFiles, basePath) { | ||||
|     var filePaths = []; | ||||
|     sourceFiles.forEach(function(sourcePattern) { | ||||
|       filePaths = filePaths.concat(glob.sync(sourcePattern, { cwd: basePath })); | ||||
|     }); | ||||
|     return filePaths; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   function getText(sourceFile, node) { | ||||
|     return sourceFile.text.substring(node.pos, node.end); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   // Strip any local renamed imports from the front of types
 | ||||
|   function getType(sourceFile, type) { | ||||
|     var text = getText(sourceFile, type); | ||||
|     while (text.indexOf(".") >= 0) { | ||||
|       // Keep namespaced symbols in RxNext
 | ||||
|       if (text.match(/^\s*RxNext\./)) break; | ||||
|       // handle the case List<thing.stuff> -> List<stuff>
 | ||||
|       text = text.replace(/([^.<]*)\.([^>]*)/, "$2"); | ||||
|     } | ||||
|     return text; | ||||
|   } | ||||
| 
 | ||||
|   function getLocation(symbol) { | ||||
|     var node = symbol.valueDeclaration || symbol.declarations[0]; | ||||
|     var sourceFile = ts.getSourceFileOfNode(node); | ||||
|     var location = { | ||||
|       start: ts.getLineAndCharacterOfPosition(sourceFile, node.pos), | ||||
|       end: ts.getLineAndCharacterOfPosition(sourceFile, node.end) | ||||
|     }; | ||||
|     return location; | ||||
|   } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| function convertToRegexCollection(items) { | ||||
|   if (!items) return []; | ||||
| 
 | ||||
|   // Must be an array
 | ||||
|   if (!_.isArray(items)) { | ||||
|     items = [items]; | ||||
|   } | ||||
| 
 | ||||
|   // Convert string to exact matching regexes
 | ||||
|   return items.map(function(item) { | ||||
|     return _.isString(item) ? new RegExp('^' + item + '$') : item; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function anyMatches(regexes, item) { | ||||
|   for(var i=0; i<regexes.length; ++i) { | ||||
|     if ( item.match(regexes[i]) ) return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| @ -1,136 +0,0 @@ | ||||
| var mockPackage = require('../mocks/mockPackage'); | ||||
| var Dgeni = require('dgeni'); | ||||
| var path = require('canonical-path'); | ||||
| var _ = require('lodash'); | ||||
| 
 | ||||
| describe('readTypeScriptModules', function() { | ||||
|   var dgeni, injector, processor; | ||||
| 
 | ||||
|   beforeEach(function() { | ||||
|     dgeni = new Dgeni([mockPackage()]); | ||||
|     injector = dgeni.configureInjector(); | ||||
|     processor = injector.get('readTypeScriptModules'); | ||||
|     processor.basePath = path.resolve(__dirname, '../mocks/readTypeScriptModules'); | ||||
|   }); | ||||
| 
 | ||||
|   describe('exportDocs', function() { | ||||
|     it('should provide the original module if the export is re-exported', function() { | ||||
|       processor.sourceFiles = [ 'publicModule.ts' ]; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
| 
 | ||||
|       var exportedDoc = docs[1]; | ||||
|       expect(exportedDoc.originalModule).toEqual('privateModule'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should include exported abstract classes', function() { | ||||
|       processor.sourceFiles = [ 'publicModule.ts' ]; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
| 
 | ||||
|       var exportedDoc = docs[2]; | ||||
|       expect(exportedDoc.name).toEqual('AbstractClass'); | ||||
|     }); | ||||
| 
 | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('ignoreExportsMatching', function() { | ||||
|     it('should ignore exports that match items in the `ignoreExportsMatching` property', function() { | ||||
|       processor.sourceFiles = [ 'ignoreExportsMatching.ts']; | ||||
|       processor.ignoreExportsMatching = [/^_/]; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
| 
 | ||||
|       var moduleDoc = docs[0]; | ||||
|       expect(moduleDoc.docType).toEqual('module'); | ||||
|       expect(moduleDoc.exports).toEqual([ | ||||
|         jasmine.objectContaining({ name: 'OKToExport' }), | ||||
|         jasmine.objectContaining({ name: 'thisIsOK' }) | ||||
|       ]); | ||||
|     }); | ||||
| 
 | ||||
|     it('should only ignore `___esModule` exports by default', function() { | ||||
|       processor.sourceFiles = [ 'ignoreExportsMatching.ts']; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
| 
 | ||||
|       var moduleDoc = docs[0]; | ||||
|       expect(moduleDoc.docType).toEqual('module'); | ||||
|       expect(getNames(moduleDoc.exports)).toEqual([ | ||||
|         'OKToExport', | ||||
|         '_thisIsPrivate', | ||||
|         'thisIsOK' | ||||
|       ]); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('interfaces', function() { | ||||
| 
 | ||||
|     it('should mark optional properties', function() { | ||||
|       processor.sourceFiles = [ 'interfaces.ts']; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
| 
 | ||||
|       var moduleDoc = docs[0]; | ||||
|       var exportedInterface = moduleDoc.exports[0]; | ||||
|       var member = exportedInterface.members[0]; | ||||
|       expect(member.name).toEqual('optionalProperty'); | ||||
|       expect(member.optional).toEqual(true); | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
|     it('should handle "call" type interfaces', function() { | ||||
|       processor.sourceFiles = [ 'interfaces.ts']; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
| 
 | ||||
|       var moduleDoc = docs[0]; | ||||
|       var exportedInterface = moduleDoc.exports[0]; | ||||
| 
 | ||||
|       expect(exportedInterface.callMember).toBeDefined(); | ||||
|       expect(exportedInterface.callMember.parameters).toEqual(['param: T']); | ||||
|       expect(exportedInterface.callMember.returnType).toEqual('U'); | ||||
|       expect(exportedInterface.callMember.typeParameters).toEqual(['T', 'U extends Findable<T>']); | ||||
|       expect(exportedInterface.newMember).toBeDefined(); | ||||
|       expect(exportedInterface.newMember.parameters).toEqual(['param: number']); | ||||
|       expect(exportedInterface.newMember.returnType).toEqual('MyInterface'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('ordering of members', function() { | ||||
|     it('should order class members in order of appearance (by default)', function() { | ||||
|       processor.sourceFiles = ['orderingOfMembers.ts']; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
|       var classDoc = _.find(docs, { docType: 'class' }); | ||||
|       expect(classDoc.docType).toEqual('class'); | ||||
|       expect(getNames(classDoc.members)).toEqual([ | ||||
|         'firstItem', | ||||
|         'otherMethod', | ||||
|         'doStuff', | ||||
|       ]); | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
|     it('should not order class members if not sortClassMembers is false', function() { | ||||
|       processor.sourceFiles = ['orderingOfMembers.ts']; | ||||
|       processor.sortClassMembers = false; | ||||
|       var docs = []; | ||||
|       processor.$process(docs); | ||||
|       var classDoc = _.find(docs, { docType: 'class' }); | ||||
|       expect(classDoc.docType).toEqual('class'); | ||||
|       expect(getNames(classDoc.members)).toEqual([ | ||||
|         'firstItem', | ||||
|         'otherMethod', | ||||
|         'doStuff' | ||||
|       ]); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| function getNames(collection) { | ||||
|   return collection.map(function(item) { return item.name; }); | ||||
| } | ||||
| @ -1,31 +0,0 @@ | ||||
| var _ = require('lodash'); | ||||
| 
 | ||||
| module.exports = function convertPrivateClassesToInterfaces() { | ||||
|   return function(exportDocs, addInjectableReference) { | ||||
|     _.forEach(exportDocs, function(exportDoc) { | ||||
| 
 | ||||
|       // Search for classes with a constructor marked as `@internal`
 | ||||
|       if (exportDoc.docType === 'class' && exportDoc.constructorDoc && exportDoc.constructorDoc.internal) { | ||||
| 
 | ||||
|         // Convert this class to an interface with no constructor
 | ||||
|         exportDoc.docType = 'interface'; | ||||
|         exportDoc.constructorDoc = null; | ||||
| 
 | ||||
|         if (exportDoc.heritage) { | ||||
|           // convert the heritage since interfaces use `extends` not `implements`
 | ||||
|           exportDoc.heritage = exportDoc.heritage.replace('implements', 'extends'); | ||||
|         } | ||||
| 
 | ||||
|         if (addInjectableReference) { | ||||
|           // Add the `declare var SomeClass extends InjectableReference` construct
 | ||||
|           exportDocs.push({ | ||||
|             docType: 'var', | ||||
|             name: exportDoc.name, | ||||
|             id: exportDoc.id, | ||||
|             returnType: 'InjectableReference' | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
| }; | ||||
| @ -1,76 +0,0 @@ | ||||
| var mockPackage = require('../mocks/mockPackage'); | ||||
| var Dgeni = require('dgeni'); | ||||
| var _ = require('lodash'); | ||||
| 
 | ||||
| describe('readTypeScriptModules', function() { | ||||
|   var dgeni, injector, convertPrivateClassesToInterfaces; | ||||
| 
 | ||||
|   beforeEach(function() { | ||||
|     dgeni = new Dgeni([mockPackage()]); | ||||
|     injector = dgeni.configureInjector(); | ||||
|     convertPrivateClassesToInterfaces = injector.get('convertPrivateClassesToInterfaces'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should convert private class docs to interface docs', function() { | ||||
|     var docs = [ | ||||
|       { | ||||
|         docType: 'class', | ||||
|         name: 'privateClass', | ||||
|         id: 'privateClass', | ||||
|         constructorDoc: { internal: true } | ||||
|       } | ||||
|     ]; | ||||
|     convertPrivateClassesToInterfaces(docs, false); | ||||
|     expect(docs[0].docType).toEqual('interface'); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   it('should not touch non-private class docs', function() { | ||||
|     var docs = [ | ||||
|       { | ||||
|         docType: 'class', | ||||
|         name: 'privateClass', | ||||
|         id: 'privateClass', | ||||
|         constructorDoc: { } | ||||
|       } | ||||
|     ]; | ||||
|     convertPrivateClassesToInterfaces(docs, false); | ||||
|     expect(docs[0].docType).toEqual('class'); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   it('should convert the heritage since interfaces use `extends` not `implements`', function() { | ||||
|     var docs = [ | ||||
|       { | ||||
|         docType: 'class', | ||||
|         name: 'privateClass', | ||||
|         id: 'privateClass', | ||||
|         constructorDoc: { internal: true }, | ||||
|         heritage: 'implements parentInterface' | ||||
|       } | ||||
|     ]; | ||||
|     convertPrivateClassesToInterfaces(docs, false); | ||||
|     expect(docs[0].heritage).toEqual('extends parentInterface'); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   it('should add new injectable reference types, if specified, to the passed in collection', function() { | ||||
|     var docs = [ | ||||
|       { | ||||
|         docType: 'class', | ||||
|         name: 'privateClass', | ||||
|         id: 'privateClass', | ||||
|         constructorDoc: { internal: true }, | ||||
|         heritage: 'implements parentInterface' | ||||
|       } | ||||
|     ]; | ||||
|     convertPrivateClassesToInterfaces(docs, true); | ||||
|     expect(docs[1]).toEqual({ | ||||
|       docType : 'var', | ||||
|       name : 'privateClass', | ||||
|       id : 'privateClass', | ||||
|       returnType : 'InjectableReference' | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| }); | ||||
| @ -1,3 +0,0 @@ | ||||
| module.exports = function modules() { | ||||
|   return {}; | ||||
| }; | ||||
| @ -1,80 +0,0 @@ | ||||
| var ts = require('typescript'); | ||||
| var fs = require('fs'); | ||||
| var path = require('canonical-path'); | ||||
| 
 | ||||
| // We need to provide our own version of CompilerHost because we want to set the
 | ||||
| // base directory and specify what extensions to consider when trying to load a source
 | ||||
| // file
 | ||||
| module.exports = function createCompilerHost(log) { | ||||
| 
 | ||||
|   return function createCompilerHost(options, baseDir, extensions) { | ||||
| 
 | ||||
|     return { | ||||
|       getSourceFile: function(fileName, languageVersion, onError) { | ||||
|         var text, resolvedPath, resolvedPathWithExt; | ||||
| 
 | ||||
|         // Strip off the extension and resolve relative to the baseDir
 | ||||
|         baseFilePath = fileName.replace(/\.[^.]+$/, ''); | ||||
|         resolvedPath = path.resolve(baseDir, baseFilePath); | ||||
| 
 | ||||
|         // Iterate through each possible extension and return the first source file that is actually found
 | ||||
|         for(var i=0; i<extensions.length; i++) { | ||||
| 
 | ||||
|           // Try reading the content from files using each of the given extensions
 | ||||
|           try { | ||||
|             resolvedPathWithExt = resolvedPath + extensions[i]; | ||||
|             log.silly('getSourceFile:', resolvedPathWithExt); | ||||
|             text = fs.readFileSync(resolvedPathWithExt, { encoding: options.charset }); | ||||
|             log.debug('found source file:', fileName, resolvedPathWithExt); | ||||
|             return ts.createSourceFile(baseFilePath + extensions[i], text, languageVersion); | ||||
|           } | ||||
|           catch(e) { | ||||
|             // Try again if the file simply did not exist, otherwise report the error as a warning
 | ||||
|             if(e.code !== 'ENOENT') { | ||||
|               if (onError) onError(e.message); | ||||
|               log.warn('Error reading ' + resolvedPathWithExt + ' : ' + e.message); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       getDefaultLibFileName: function(options) { | ||||
|         return path.resolve(path.dirname(ts.sys.getExecutingFilePath()), ts.getDefaultLibFileName(options)); | ||||
|       }, | ||||
|       writeFile: function(fileName, data, writeByteOrderMark, onError) { | ||||
|         // no-op
 | ||||
|       }, | ||||
|       getCurrentDirectory: function() { | ||||
|         return baseDir; | ||||
|       }, | ||||
|       useCaseSensitiveFileNames: function() { | ||||
|         return ts.sys.useCaseSensitiveFileNames; | ||||
|       }, | ||||
|       getCanonicalFileName: function(fileName) { | ||||
|         // if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
 | ||||
|         // otherwise use toLowerCase as a canonical form.
 | ||||
|         return ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); | ||||
|       }, | ||||
|       getNewLine: function() { | ||||
|         return ts.sys.newLine; | ||||
|       }, | ||||
|       fileExists(fileName) { | ||||
|         var text, resolvedPath, resolvedPathWithExt; | ||||
| 
 | ||||
|         // Strip off the extension and resolve relative to the baseDir
 | ||||
|         baseFilePath = fileName.replace(/\.[^.]+$/, ''); | ||||
|         resolvedPath = path.resolve(baseDir, baseFilePath); | ||||
| 
 | ||||
|         // Iterate through each possible extension and return the first source file that is actually found
 | ||||
|         for(var i=0; i<extensions.length; i++) { | ||||
|           // Try reading the content from files using each of the given extensions
 | ||||
|           resolvedPathWithExt = resolvedPath + extensions[i]; | ||||
|           if (fs.existsSync(resolvedPathWithExt)) return true; | ||||
|         } | ||||
|         return false; | ||||
|       }, | ||||
|       readFile(fileName) { | ||||
|         console.log('readFile - NOT IMPLEMENTED', fileName); | ||||
|       } | ||||
|     }; | ||||
|   }; | ||||
| }; | ||||
| @ -1,80 +0,0 @@ | ||||
| var mockPackage = require('../../mocks/mockPackage'); | ||||
| var Dgeni = require('dgeni'); | ||||
| var path = require('canonical-path'); | ||||
| var ts = require('typescript'); | ||||
| 
 | ||||
| describe('createCompilerHost', function() { | ||||
|   var dgeni, injector, options, host, baseDir, extensions; | ||||
| 
 | ||||
|   beforeEach(function() { | ||||
|     dgeni = new Dgeni([mockPackage()]); | ||||
|     injector = dgeni.configureInjector(); | ||||
|     var createCompilerHost = injector.get('createCompilerHost'); | ||||
| 
 | ||||
|     options = { charset: 'utf8' }; | ||||
|     baseDir = path.resolve(__dirname, '../../mocks/tsParser'); | ||||
|     extensions = ['.ts', '.js']; | ||||
| 
 | ||||
|     host = createCompilerHost(options, baseDir, extensions); | ||||
|   }); | ||||
| 
 | ||||
|   describe('getSourceFile', function() { | ||||
|     it('should return a SourceFile object for a given path, with fileName relative to baseDir', function() { | ||||
|       var sourceFile = host.getSourceFile('testSrc.ts'); | ||||
|       expect(sourceFile.fileName).toEqual('testSrc.ts'); | ||||
|       expect(sourceFile.pos).toEqual(0); | ||||
|       expect(sourceFile.text).toEqual(jasmine.any(String)); | ||||
|     }); | ||||
| 
 | ||||
|     it('should try each of the configured extensions and update the filename to the correct extension', function() { | ||||
|       var sourceFile = host.getSourceFile('testSrc.js'); | ||||
|       expect(sourceFile.fileName).toEqual('testSrc.ts'); | ||||
| 
 | ||||
|       sourceFile = host.getSourceFile('../mockPackage.ts'); | ||||
|       expect(sourceFile.fileName).toEqual('../mockPackage.js'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('getDefaultLibFileName', function() { | ||||
|     it('should return a path to the default library', function() { | ||||
|       expect(host.getDefaultLibFileName(options)).toContain('typescript/lib/lib.d.ts'); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('writeFile', function() { | ||||
|     it('should do nothing', function() { | ||||
|       host.writeFile(); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('getCurrentDirectory', function() { | ||||
|     it('should return the baseDir', function() { | ||||
|       expect(host.getCurrentDirectory()).toEqual(baseDir); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('useCaseSensitiveFileNames', function() { | ||||
|     it('should return true if the OS is case sensitive', function() { | ||||
|       expect(host.useCaseSensitiveFileNames()).toBe(ts.sys.useCaseSensitiveFileNames); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('getCanonicalFileName', function() { | ||||
|     it('should lower case the filename', function() { | ||||
|       var expectedFilePath = host.useCaseSensitiveFileNames() ? 'SomeFile.ts' : 'somefile.ts'; | ||||
|       expect(host.getCanonicalFileName('SomeFile.ts')).toEqual(expectedFilePath); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   describe('getNewLine', function() { | ||||
|     it('should return the newline character for the OS', function() { | ||||
|       expect(host.getNewLine()).toEqual(require('os').EOL); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @ -1,49 +0,0 @@ | ||||
| var ts = require('typescript'); | ||||
| var LEADING_STAR = /^[^\S\r\n]*\*[^\S\n\r]?/gm; | ||||
| 
 | ||||
| module.exports = function getContent() { | ||||
|   return function(symbol) { | ||||
| 
 | ||||
|     var content = ""; | ||||
| 
 | ||||
|     if (!symbol.declarations) return content; | ||||
| 
 | ||||
|     symbol.declarations.forEach(function(declaration) { | ||||
| 
 | ||||
|       // If this is left side of dotted module declaration, there is no doc comment associated with this declaration
 | ||||
|       if (declaration.kind === ts.SyntaxKind.ModuleDeclaration && declaration.body.kind === ts.SyntaxKind.ModuleDeclaration) { | ||||
|           return content; | ||||
|       } | ||||
| 
 | ||||
|       // If this is dotted module name, get the doc comments from the parent
 | ||||
|       while (declaration.kind === ts.SyntaxKind.ModuleDeclaration && declaration.parent.kind === ts.SyntaxKind.ModuleDeclaration) { | ||||
|           declaration = declaration.parent; | ||||
|       } | ||||
| 
 | ||||
|       // If this is a variable declaration then we get the doc comments from the grand parent
 | ||||
|       if (declaration.kind === ts.SyntaxKind.VariableDeclaration) { | ||||
|         declaration = declaration.parent.parent; | ||||
|       } | ||||
| 
 | ||||
|       // Get the source file of this declaration
 | ||||
|       var sourceFile = ts.getSourceFileOfNode(declaration); | ||||
|       var commentRanges = ts.getJsDocComments(declaration, sourceFile); | ||||
| 
 | ||||
|       if (commentRanges) { | ||||
|         commentRanges.forEach(function(commentRange) { | ||||
|           content += sourceFile.text | ||||
|               .substring(commentRange.pos+ '/**'.length, commentRange.end - '*/'.length) | ||||
|               .replace(LEADING_STAR, '') | ||||
|               .trim(); | ||||
|           if (commentRange.hasTrailingNewLine) { | ||||
|             content += '\n'; | ||||
|           } | ||||
|         }); | ||||
|       } | ||||
| 
 | ||||
|       content += '\n'; | ||||
|     }); | ||||
| 
 | ||||
|     return content; | ||||
|   }; | ||||
| }; | ||||
| @ -1,54 +0,0 @@ | ||||
| var ts = require('typescript'); | ||||
| 
 | ||||
| module.exports = function getExportDocType(log) { | ||||
| 
 | ||||
|   return function(symbol) { | ||||
|     if(symbol.flags & ts.SymbolFlags.Function) { | ||||
|       return 'function'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.Class) { | ||||
|       return 'class'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.Interface) { | ||||
|       return 'interface'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.ConstEnum) { | ||||
|       return 'enum'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.RegularEnum) { | ||||
|       return 'enum'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.Property) { | ||||
|       return 'module-property'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.TypeAlias) { | ||||
|       return 'type-alias'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.FunctionScopedVariable) { | ||||
|       return 'var'; | ||||
|     } | ||||
|     if(symbol.flags & ts.SymbolFlags.BlockScopedVariable) { | ||||
|       return getBlockScopedVariableDocType(symbol); | ||||
|     } | ||||
| 
 | ||||
|     log.warn('getExportDocType(): Unknown symbol type', { | ||||
|       symbolName: symbol.name, | ||||
|       symbolType: symbol.flags, | ||||
|       symbolTarget: symbol.target, | ||||
|       file: ts.getSourceFileOfNode(symbol.declarations[0]).fileName | ||||
|     }); | ||||
|     return 'unknown'; | ||||
|   }; | ||||
| 
 | ||||
|   function getBlockScopedVariableDocType(symbol) { | ||||
| 
 | ||||
|     var node = symbol.valueDeclaration; | ||||
|     while(node) { | ||||
|       if ( node.flags & 0x2000 /* const */) { | ||||
|         return 'const'; | ||||
|       } | ||||
|       node = node.parent; | ||||
|     } | ||||
|     return 'let'; | ||||
|   } | ||||
| }; | ||||
| @ -1,20 +0,0 @@ | ||||
| var path = require('canonical-path'); | ||||
| var ts = require('typescript'); | ||||
| 
 | ||||
| module.exports = function getFileInfo(log) { | ||||
| 
 | ||||
|   return function (symbol, basePath) { | ||||
|     var fileName = ts.getSourceFileOfNode(symbol.declarations[0]).fileName; | ||||
| 
 | ||||
|     var file = path.resolve(basePath, fileName); | ||||
|     var fileInfo = { | ||||
|       filePath: file, | ||||
|       baseName: path.basename(file, path.extname(file)), | ||||
|       extension: path.extname(file).replace(/^\./, ''), | ||||
|       basePath: basePath, | ||||
|       relativePath: fileName, | ||||
|       projectRelativePath: fileName | ||||
|     }; | ||||
|     return fileInfo; | ||||
|   }; | ||||
| }; | ||||
| @ -1,74 +0,0 @@ | ||||
| var ts = require('typescript'); | ||||
| var path = require('canonical-path'); | ||||
| 
 | ||||
| module.exports = function tsParser(createCompilerHost, log) { | ||||
| 
 | ||||
|   return { | ||||
| 
 | ||||
|     // These are the extension that we should consider when trying to load a module
 | ||||
|     // During migration from Traceur, there is a mix of `.ts`, `.es6` and `.js` (atScript)
 | ||||
|     // files in the project and the TypeScript compiler only looks for `.ts` files when trying
 | ||||
|     // to load imports.
 | ||||
|     extensions: ['.ts', '.js'], | ||||
| 
 | ||||
|     // The options for the TS compiler
 | ||||
|     options: { | ||||
|       allowNonTsExtensions: true, | ||||
|       charset: 'utf8' | ||||
|     }, | ||||
| 
 | ||||
|     parse: function(fileNames, baseDir) { | ||||
| 
 | ||||
|       // "Compile" a program from the given module filenames, to get hold of a
 | ||||
|       // typeChecker that can be used to interrogate the modules, exports and so on.
 | ||||
|       var host = createCompilerHost(this.options, baseDir, this.extensions); | ||||
|       var program = ts.createProgram(fileNames, this.options, host); | ||||
|       var typeChecker = program.getTypeChecker(); | ||||
| 
 | ||||
|       // Create an array of module symbols for each file we were given
 | ||||
|       var moduleSymbols = []; | ||||
|       fileNames.forEach(function(fileName) { | ||||
|         var sourceFile = program.getSourceFile(fileName); | ||||
| 
 | ||||
|         if (!sourceFile) { | ||||
|           throw new Error('Invalid source file: ' + fileName); | ||||
|         } else if (!sourceFile.symbol) { | ||||
|           // Some files contain only a comment and no actual module code
 | ||||
|           log.warn('No module code found in ' + fileName); | ||||
|         } else { | ||||
|           moduleSymbols.push(sourceFile.symbol); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
| 
 | ||||
|       moduleSymbols.forEach(function(tsModule) { | ||||
| 
 | ||||
|         // The type checker has a nice helper function that returns an array of Symbols
 | ||||
|         // representing the exports for a given module
 | ||||
|         tsModule.exportArray = typeChecker.getExportsOfModule(tsModule); | ||||
| 
 | ||||
|         // Although 'star' imports (e.g. `export * from 'some/module';) get resolved automatically
 | ||||
|         // by the compiler/binder, it seems that explicit imports (e.g. `export {SomeClass} from 'some/module'`)
 | ||||
|         // do not so we have to do a little work.
 | ||||
|         tsModule.exportArray.forEach(function(moduleExport) { | ||||
|           if (moduleExport.flags & ts.SymbolFlags.Alias) { | ||||
|             // To maintain the alias information (particularly the alias name)
 | ||||
|             // we just attach the original "resolved" symbol to the alias symbol
 | ||||
|             moduleExport.resolvedSymbol = typeChecker.getAliasedSymbol(moduleExport); | ||||
|           } | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       moduleSymbols.typeChecker = typeChecker; | ||||
| 
 | ||||
|       return { | ||||
|         moduleSymbols: moduleSymbols, | ||||
|         typeChecker: typeChecker, | ||||
|         program: program, | ||||
|         host: host | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
| }; | ||||
| @ -1,21 +0,0 @@ | ||||
| var mockPackage = require('../../mocks/mockPackage'); | ||||
| var Dgeni = require('dgeni'); | ||||
| var path = require('canonical-path'); | ||||
| 
 | ||||
| describe('tsParser', function() { | ||||
|   var dgeni, injector, parser; | ||||
| 
 | ||||
|   beforeEach(function() { | ||||
|     dgeni = new Dgeni([mockPackage()]); | ||||
|     injector = dgeni.configureInjector(); | ||||
|     parser = injector.get('tsParser'); | ||||
|   }); | ||||
| 
 | ||||
|   it("should parse a TS file", function() { | ||||
|     var parseInfo = parser.parse(['testSrc.ts'], path.resolve(__dirname, '../../mocks/tsParser')); | ||||
|     var tsModules = parseInfo.moduleSymbols; | ||||
|     expect(tsModules.length).toEqual(1); | ||||
|     expect(tsModules[0].exportArray.length).toEqual(3); | ||||
|     expect(tsModules[0].exportArray.map(function(i) { return i.name; })).toEqual(['MyClass', 'myFn', 'x']); | ||||
|   }); | ||||
| }); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user