chore(doc-gen): add TypeScript parsing
This commit is contained in:
parent
25a952755e
commit
9a72f19b97
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
p.location-badge.
|
p.location-badge.
|
||||||
exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a>
|
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||||
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.location.start.source.name $}.js#L{$ doc.location.start.line $}">{$ doc.location.start.source.name $}.js (line {$ doc.location.start.line $})</a>
|
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.fileInfo.relativePath $}#L{$ doc.location.start.line+1 $}-L{$ doc.location.end.line+1 $}">{$ doc.fileInfo.relativePath $} (line {$ doc.location.start.line+1 $})</a>
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
{$ doc.description | indent(2, true) $}
|
{$ doc.description | indent(2, true) $}
|
||||||
|
@ -17,10 +17,10 @@ p.location-badge.
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
h3 {$ doc.constructorDoc.name $}
|
h3 {$ doc.constructorDoc.name $}
|
||||||
|
|
||||||
{% if doc.constructorDoc.params %}
|
{% if doc.constructorDoc.parameters %}
|
||||||
pre.prettyprint
|
pre.prettyprint
|
||||||
code.
|
code.
|
||||||
{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) | indent(4, true) | trim $}
|
{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.parameters) | indent(4, true) | trim $}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
:markdown
|
:markdown
|
||||||
{$ doc.constructorDoc.description | indent(6, true) | replace('## Example', '') | replace('# Example', '') $}
|
{$ doc.constructorDoc.description | indent(6, true) | replace('## Example', '') | replace('# Example', '') $}
|
||||||
|
@ -32,10 +32,10 @@ p.location-badge.
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
h3 {$ member.name $}
|
h3 {$ member.name $}
|
||||||
|
|
||||||
{% if member.params %}
|
{% if member.parameters %}
|
||||||
pre.prettyprint
|
pre.prettyprint
|
||||||
code.
|
code.
|
||||||
{$ member.name $}{$ paramList(member.params) | indent(4, true) | trim $}
|
{$ member.name $}{$ paramList(member.parameters) | indent(4, true) | trim $}{$ returnType(doc.returnType) $}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
:markdown
|
:markdown
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,15 @@
|
||||||
.l-main-section
|
.l-main-section
|
||||||
h2(class="function export") {$ doc.name $}
|
h2(class="function export") {$ doc.name $}
|
||||||
|
|
||||||
p <code>{$ paramList(doc.parameters) $}</code>
|
{% if doc.parameters %}
|
||||||
|
pre.prettyprint
|
||||||
|
code.
|
||||||
|
{$ doc.name $}{$ paramList(doc.parameters) | indent(4, true) | trim $}{$ returnType(doc.returnType) $}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
p.location-badge.
|
p.location-badge.
|
||||||
exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a>
|
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||||
|
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.fileInfo.relativePath $}#L{$ doc.location.start.line+1 $}-L{$ doc.location.end.line+1 $}">{$ doc.fileInfo.relativePath $} (line {$ doc.location.start.line+1 $})</a>
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
{$ doc.description | indent(4, true) $}
|
{$ doc.description | indent(4, true) $}
|
||||||
|
|
|
@ -5,3 +5,8 @@
|
||||||
{%- endfor %})
|
{%- endfor %})
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro returnType(returnType) -%}
|
||||||
|
{%- if returnType %} : {$ returnType | escape $}{% endif -%}
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{% extends 'layout/base.template.html' -%}
|
{% extends 'layout/base.template.html' -%}
|
||||||
{% block body -%}
|
{% block body -%}
|
||||||
|
p.location-badge.
|
||||||
|
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.fileInfo.relativePath $}#L{$ doc.location.start.line+1 $}-L{$ doc.location.end.line+1 $}">{$ doc.fileInfo.relativePath $} (line {$ doc.location.start.line+1 $})</a>
|
||||||
|
|
||||||
ul
|
ul
|
||||||
for page, slug in public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]]._data
|
for page, slug in public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]]._data
|
||||||
if slug != 'index'
|
if slug != 'index'
|
||||||
|
|
|
@ -15,6 +15,11 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage, linksPac
|
||||||
|
|
||||||
// Register the services and file readers
|
// Register the services and file readers
|
||||||
.factory(require('./services/modules'))
|
.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('./readers/ngdoc'))
|
.factory(require('./readers/ngdoc'))
|
||||||
|
|
||||||
.factory('EXPORT_DOC_TYPES', function() {
|
.factory('EXPORT_DOC_TYPES', function() {
|
||||||
|
@ -28,6 +33,7 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage, linksPac
|
||||||
|
|
||||||
|
|
||||||
// Register the processors
|
// Register the processors
|
||||||
|
.processor(require('./processors/readTypeScriptModules'))
|
||||||
.processor(require('./processors/generateNavigationDoc'))
|
.processor(require('./processors/generateNavigationDoc'))
|
||||||
.processor(require('./processors/extractTitleFromGuides'))
|
.processor(require('./processors/extractTitleFromGuides'))
|
||||||
.processor(require('./processors/createOverviewDump'))
|
.processor(require('./processors/createOverviewDump'))
|
||||||
|
@ -40,13 +46,23 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage, linksPac
|
||||||
|
|
||||||
|
|
||||||
// Configure file reading
|
// Configure file reading
|
||||||
.config(function(readFilesProcessor, ngdocFileReader) {
|
.config(function(readFilesProcessor, ngdocFileReader, readTypeScriptModules) {
|
||||||
readFilesProcessor.fileReaders = [ngdocFileReader];
|
readFilesProcessor.fileReaders = [ngdocFileReader];
|
||||||
readFilesProcessor.basePath = path.resolve(__dirname, '../..');
|
readFilesProcessor.basePath = path.resolve(__dirname, '../..');
|
||||||
readFilesProcessor.sourceFiles = [
|
readFilesProcessor.sourceFiles = [
|
||||||
{ include: 'modules/*/docs/**/*.md', basePath: 'modules' },
|
{ include: 'modules/*/docs/**/*.md', basePath: 'modules' },
|
||||||
{ include: 'docs/content/**/*.md', basePath: 'docs/content' }
|
{ include: 'docs/content/**/*.md', basePath: 'docs/content' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
readTypeScriptModules.sourceFiles = [
|
||||||
|
'*/*.js',
|
||||||
|
'*/src/**/*.js',
|
||||||
|
'*/*.es6',
|
||||||
|
'*/src/**/*.es6',
|
||||||
|
'*/*.ts',
|
||||||
|
'*/src/**/*.ts'
|
||||||
|
];
|
||||||
|
readTypeScriptModules.basePath = 'modules';
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,6 +70,14 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage, linksPac
|
||||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/public'));
|
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/public'));
|
||||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/private'));
|
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/private'));
|
||||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/exportedAs'));
|
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/exportedAs'));
|
||||||
|
|
||||||
|
// We actually don't want to parse param docs in this package as we are getting the data out using TS
|
||||||
|
parseTagsProcessor.tagDefinitions.forEach(function(tagDef) {
|
||||||
|
if (tagDef.name === 'param') {
|
||||||
|
tagDef.ignore = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,12 +112,6 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage, linksPac
|
||||||
// Configure ids and paths
|
// Configure ids and paths
|
||||||
.config(function(computeIdsProcessor, computePathsProcessor, EXPORT_DOC_TYPES) {
|
.config(function(computeIdsProcessor, computePathsProcessor, EXPORT_DOC_TYPES) {
|
||||||
|
|
||||||
computeIdsProcessor.idTemplates.push({
|
|
||||||
docTypes: EXPORT_DOC_TYPES,
|
|
||||||
idTemplate: '${moduleDoc.id}.${name}',
|
|
||||||
getAliases: function(doc) { return [doc.id, doc.name]; }
|
|
||||||
});
|
|
||||||
|
|
||||||
computeIdsProcessor.idTemplates.push({
|
computeIdsProcessor.idTemplates.push({
|
||||||
docTypes: ['member'],
|
docTypes: ['member'],
|
||||||
idTemplate: '${classDoc.id}.${name}',
|
idTemplate: '${classDoc.id}.${name}',
|
||||||
|
@ -117,7 +135,7 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage, linksPac
|
||||||
|
|
||||||
computePathsProcessor.pathTemplates.push({
|
computePathsProcessor.pathTemplates.push({
|
||||||
docTypes: ['module'],
|
docTypes: ['module'],
|
||||||
pathTemplate: '${id}',
|
pathTemplate: '/${id}',
|
||||||
outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.html'
|
outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.html'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -136,7 +154,7 @@ module.exports = new Package('angular', [jsdocPackage, nunjucksPackage, linksPac
|
||||||
|
|
||||||
computePathsProcessor.pathTemplates.push({
|
computePathsProcessor.pathTemplates.push({
|
||||||
docTypes: ['guide'],
|
docTypes: ['guide'],
|
||||||
pathTemplate: '${id}',
|
pathTemplate: '/${id}',
|
||||||
outputPathTemplate: GUIDES_PATH + '/${id}.html'
|
outputPathTemplate: GUIDES_PATH + '/${id}.html'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export var x = 100;
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* @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; }
|
|
@ -0,0 +1,201 @@
|
||||||
|
var glob = require('glob');
|
||||||
|
var path = require('canonical-path');
|
||||||
|
var _ = require('lodash');
|
||||||
|
var ts = require('typescript');
|
||||||
|
|
||||||
|
module.exports = function readTypeScriptModules(tsParser, readFilesProcessor, modules, getFileInfo, getExportDocType, getContent, log) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
$runAfter: ['files-read'],
|
||||||
|
$runBefore: ['parsing-tags'],
|
||||||
|
|
||||||
|
$validate: {
|
||||||
|
sourceFiles: {presence: true},
|
||||||
|
basePath: {presence: true},
|
||||||
|
hidePrivateMembers: { inclusion: [true, false] },
|
||||||
|
hideSpecialExports: { inclusion: [true, false] }
|
||||||
|
},
|
||||||
|
|
||||||
|
sourceFiles: [],
|
||||||
|
basePath: '.',
|
||||||
|
hidePrivateMembers: false,
|
||||||
|
hideSpecialExports: true,
|
||||||
|
|
||||||
|
$process: function(docs) {
|
||||||
|
|
||||||
|
var hideSpecialExports = this.hideSpecialExports;
|
||||||
|
var hidePrivateMembers = this.hidePrivateMembers;
|
||||||
|
|
||||||
|
var basePath = path.resolve(readFilesProcessor.basePath, 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 (hideSpecialExports && exportSymbol.name.charAt(0) === '_') return;
|
||||||
|
|
||||||
|
// If the symbol is an Alias then for most things we want the original resolved symbol
|
||||||
|
var resolvedExport = exportSymbol.resolvedSymbol || exportSymbol;
|
||||||
|
var exportDoc = createExportDoc(exportSymbol.name, resolvedExport, moduleDoc, basePath, parseInfo.typeChecker);
|
||||||
|
log.debug('>>>> EXPORT: ' + exportDoc.name + ' (' + exportDoc.docType + ') from ' + moduleDoc.id);
|
||||||
|
|
||||||
|
// Generate docs for each of the export's members
|
||||||
|
if (resolvedExport.flags & ts.SymbolFlags.HasMembers) {
|
||||||
|
|
||||||
|
exportDoc.members = [];
|
||||||
|
for(var memberName in resolvedExport.members) {
|
||||||
|
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);
|
||||||
|
insertSorted(exportDoc.members, memberDoc, 'name');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this export doc to its module doc
|
||||||
|
moduleDoc.exports.push(exportDoc);
|
||||||
|
docs.push(exportDoc);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function createModuleDoc(moduleSymbol, basePath) {
|
||||||
|
var id = moduleSymbol.name.replace(/^"|"$/g, '');
|
||||||
|
var moduleDoc = {
|
||||||
|
docType: 'module',
|
||||||
|
id: id,
|
||||||
|
aliases: [id],
|
||||||
|
moduleTree: moduleSymbol,
|
||||||
|
content: getContent(moduleSymbol),
|
||||||
|
exports: [],
|
||||||
|
fileInfo: getFileInfo(moduleSymbol, basePath),
|
||||||
|
location: getLocation(moduleSymbol)
|
||||||
|
};
|
||||||
|
return moduleDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createExportDoc(name, exportSymbol, moduleDoc, basePath, typeChecker) {
|
||||||
|
var exportDoc = {
|
||||||
|
docType: getExportDocType(exportSymbol),
|
||||||
|
name: name,
|
||||||
|
id: name,
|
||||||
|
aliases: [name],
|
||||||
|
moduleDoc: moduleDoc,
|
||||||
|
content: getContent(exportSymbol),
|
||||||
|
fileInfo: getFileInfo(exportSymbol, basePath),
|
||||||
|
location: getLocation(exportSymbol)
|
||||||
|
};
|
||||||
|
if(exportSymbol.flags & ts.SymbolFlags.Function) {
|
||||||
|
exportDoc.parameters = getParameters(typeChecker, exportSymbol);
|
||||||
|
exportDoc.returnType = getReturnType(typeChecker, exportSymbol);
|
||||||
|
}
|
||||||
|
return exportDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMemberDoc(memberSymbol, classDoc, basePath, typeChecker) {
|
||||||
|
var memberDoc = {
|
||||||
|
docType: 'member',
|
||||||
|
classDoc: classDoc,
|
||||||
|
name: memberSymbol.name,
|
||||||
|
id: memberSymbol.name,
|
||||||
|
content: getContent(memberSymbol),
|
||||||
|
fileInfo: getFileInfo(memberSymbol, basePath),
|
||||||
|
location: getLocation(memberSymbol)
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
memberDoc.returnType = getReturnType(typeChecker, memberSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memberSymbol.flags & ts.SymbolFlags.Constructor) {
|
||||||
|
memberDoc.parameters = getParameters(typeChecker, memberSymbol);
|
||||||
|
memberDoc.name = 'constructor';
|
||||||
|
}
|
||||||
|
|
||||||
|
return memberDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getParameters(typeChecker, symbol) {
|
||||||
|
var declaration = symbol.valueDeclaration || symbol.declarations[0];
|
||||||
|
var sourceFile = ts.getSourceFileOfNode(declaration);
|
||||||
|
if(!declaration.parameters) {
|
||||||
|
console.log(declaration);
|
||||||
|
throw 'missing declaration parameters';
|
||||||
|
}
|
||||||
|
var signature = typeChecker.getSignatureFromDeclaration(declaration);
|
||||||
|
return declaration.parameters.map(function(parameter) {
|
||||||
|
return getText(sourceFile, parameter).trim();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReturnType(typeChecker, symbol) {
|
||||||
|
var declaration = symbol.valueDeclaration || symbol.declarations[0];
|
||||||
|
var sourceFile = ts.getSourceFileOfNode(declaration);
|
||||||
|
if(declaration.type) {
|
||||||
|
var signature = typeChecker.getSignatureFromDeclaration(declaration);
|
||||||
|
return getText(sourceFile, declaration.type).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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 insertSorted(collection, item, property) {
|
||||||
|
var index = collection.length;
|
||||||
|
while(index>0) {
|
||||||
|
if(collection[index-1][property] < item[property]) break;
|
||||||
|
index -= 1;
|
||||||
|
}
|
||||||
|
collection.splice(index, 0, item);
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
var ts = require('typescript');
|
||||||
|
|
||||||
|
module.exports = function tsParser(createCompilerHost, log) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
options: {
|
||||||
|
allowNonTsExtensions: true
|
||||||
|
},
|
||||||
|
|
||||||
|
parse: function(fileNames, baseDir) {
|
||||||
|
// This is the easiest way I could find to ensure that we loaded
|
||||||
|
// modules with paths relative to the baseDir
|
||||||
|
process.chdir(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);
|
||||||
|
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 & 8388608 /* 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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
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/'));
|
||||||
|
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']);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,32 @@
|
||||||
|
var ts = require('typescript');
|
||||||
|
|
||||||
|
// These are the extension that we should consider when trying to load a module
|
||||||
|
var extensions = ['.ts', '.js', '.es6']
|
||||||
|
|
||||||
|
// We need to provide our own version of CompilerHost because, at the moment, 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.
|
||||||
|
module.exports = function createCompilerHost(log) {
|
||||||
|
return function createCompilerHost(options) {
|
||||||
|
|
||||||
|
var host = ts.createCompilerHost(options);
|
||||||
|
|
||||||
|
// Override the `getSourceFile` implementation to also look for js and es6 files
|
||||||
|
var getSourceFile = host.getSourceFile;
|
||||||
|
host.getSourceFile = function(filename, languageVersion, onError) {
|
||||||
|
// Iterate through each possible extension and return the first source file that is actually found
|
||||||
|
for(var i=0; i<extensions.length; i++) {
|
||||||
|
var extension = extensions[i];
|
||||||
|
var altFileName = filename.replace(/\.ts$/, extension);
|
||||||
|
log.silly('getSourceFile:', altFileName);
|
||||||
|
var sourceFile = getSourceFile.call(host, altFileName, languageVersion, onError);
|
||||||
|
if(sourceFile) {
|
||||||
|
log.debug('found source file:', altFileName);
|
||||||
|
return sourceFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return host;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,49 @@
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,46 @@
|
||||||
|
var ts = require('typescript');
|
||||||
|
|
||||||
|
module.exports = function getExportDocType() {
|
||||||
|
|
||||||
|
return function(symbol) {
|
||||||
|
if(symbol.flags & ts.SymbolFlags.FunctionScopedVariable) {
|
||||||
|
return 'var';
|
||||||
|
}
|
||||||
|
if(symbol.flags & ts.SymbolFlags.BlockScopedVariable) {
|
||||||
|
return getBlockScopedVariableDocType(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';
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn('Unknown symbol type', symbol.name, symbol.flags, symbol.target);
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBlockScopedVariableDocType(symbol) {
|
||||||
|
|
||||||
|
var node = symbol.valueDeclaration;
|
||||||
|
while(node) {
|
||||||
|
if ( node.flags & 0x2000 /* const */) {
|
||||||
|
return 'const';
|
||||||
|
}
|
||||||
|
node = node.parent;
|
||||||
|
}
|
||||||
|
return 'let';
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,20 @@
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -4,7 +4,8 @@
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<h1 class="class export">{$ doc.name $} <span class="type">class</span></h1>
|
<h1 class="class export">{$ doc.name $} <span class="type">class</span></h1>
|
||||||
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a><br/>
|
<p class="module">exported from <a href="/{$ doc.moduleDoc.path $}">{$ doc.moduleDoc.id $}</a><br/>
|
||||||
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.location.start.source.name $}.js#L{$ doc.location.start.line $}">{$ doc.location.start.source.name $}.js (line {$ doc.location.start.line $})</a></p>
|
defined in <a href="https://github.com/angular/angular/tree/master/modules/{$ doc.fileInfo.relativePath $}#L{$ doc.location.start.line+1 $}-L{$ doc.location.end.line+1 $}">
|
||||||
|
{$ doc.fileInfo.relativePath $} (line {$ doc.location.start.line+1 $})</a></p>
|
||||||
<p>{$ doc.description | marked $}</p>
|
<p>{$ doc.description | marked $}</p>
|
||||||
|
|
||||||
{%- if doc.constructorDoc or doc.members.length -%}
|
{%- if doc.constructorDoc or doc.members.length -%}
|
||||||
|
|
|
@ -3,6 +3,25 @@ var basePackage = require('../dgeni-package');
|
||||||
|
|
||||||
module.exports = new Package('angular-public', [basePackage])
|
module.exports = new Package('angular-public', [basePackage])
|
||||||
|
|
||||||
|
.config(function(readTypeScriptModules) {
|
||||||
|
readTypeScriptModules.sourceFiles = [
|
||||||
|
'angular2/annotations.js',
|
||||||
|
'angular2/change_detection.ts',
|
||||||
|
'angular2/core.js',
|
||||||
|
'angular2/di.ts',
|
||||||
|
'angular2/directives.js',
|
||||||
|
'angular2/forms.js',
|
||||||
|
'angular2/router.js',
|
||||||
|
'angular2/test.js',
|
||||||
|
'angular2/pipes.js'
|
||||||
|
];
|
||||||
|
readTypeScriptModules.hidePrivateMembers = true;
|
||||||
|
})
|
||||||
|
|
||||||
|
.config(function(getLinkInfo) {
|
||||||
|
getLinkInfo.useFirstAmbiguousLink = false;
|
||||||
|
})
|
||||||
|
|
||||||
// Configure file writing
|
// Configure file writing
|
||||||
.config(function(writeFilesProcessor) {
|
.config(function(writeFilesProcessor) {
|
||||||
writeFilesProcessor.outputFolder = 'dist/public_docs';
|
writeFilesProcessor.outputFolder = 'dist/public_docs';
|
||||||
|
|
Loading…
Reference in New Issue