224 lines
5.2 KiB
JavaScript
224 lines
5.2 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
|
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
* Code distributed by Google as part of the polymer project is also
|
|
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
*/
|
|
// jshint node: true
|
|
'use strict';
|
|
|
|
var doctrine = require('doctrine');
|
|
|
|
/**
|
|
* An annotated JSDoc block tag, all fields are optionally processed except for
|
|
* the tag:
|
|
*
|
|
* @TAG {TYPE} NAME DESC
|
|
*
|
|
* `line` and `col` indicate the position of the first character of text that
|
|
* the tag was extracted from - relative to the first character of the comment
|
|
* contents (e.g. the value of `desc` on a descriptor node). Lines are
|
|
* 1-indexed.
|
|
*
|
|
* @typedef {{
|
|
* tag: string,
|
|
* type: ?string,
|
|
* name: ?string,
|
|
* description: ?string,
|
|
* }}
|
|
*/
|
|
var JsdocTag;
|
|
|
|
/**
|
|
* The parsed representation of a JSDoc comment.
|
|
*
|
|
* @typedef {{
|
|
* description: ?string,
|
|
* tags: Array<JsdocTag>,
|
|
* }}
|
|
*/
|
|
var JsdocAnnotation;
|
|
|
|
/**
|
|
* doctrine configuration,
|
|
* CURRENTLY UNUSED BECAUSE PRIVATE
|
|
*/
|
|
// function configureDoctrine() {
|
|
|
|
// // @hero [path/to/image]
|
|
// doctrine.Rules['hero'] = ['parseNamePathOptional', 'ensureEnd'];
|
|
|
|
// // // @demo [path/to/demo] [Demo title]
|
|
// doctrine.Rules['demo'] = ['parseNamePathOptional', 'parseDescription', 'ensureEnd'];
|
|
|
|
// // // @polymerBehavior [Polymer.BehaviorName]
|
|
// doctrine.Rules['polymerBehavior'] = ['parseNamePathOptional', 'ensureEnd'];
|
|
// }
|
|
// configureDoctrine();
|
|
|
|
// @demo [path] [title]
|
|
function parseDemo(tag) {
|
|
var match = (tag.description || "").match(/^\s*(\S*)\s*(.*)$/);
|
|
return {
|
|
tag: 'demo',
|
|
type: null,
|
|
name: match ? match[1] : null,
|
|
description: match ? match[2] : null
|
|
};
|
|
}
|
|
|
|
// @hero [path]
|
|
function parseHero(tag) {
|
|
return {
|
|
tag: tag.title,
|
|
type: null,
|
|
name: tag.description,
|
|
description: null
|
|
};
|
|
}
|
|
|
|
// @polymerBehavior [name]
|
|
function parsePolymerBehavior(tag) {
|
|
return {
|
|
tag: tag.title,
|
|
type: null,
|
|
name: tag.description,
|
|
description: null
|
|
};
|
|
}
|
|
|
|
// @pseudoElement name
|
|
function parsePseudoElement(tag) {
|
|
return {
|
|
tag: tag.title,
|
|
type: null,
|
|
name: tag.description,
|
|
description: null
|
|
};
|
|
}
|
|
|
|
var CUSTOM_TAGS = {
|
|
demo: parseDemo,
|
|
hero: parseHero,
|
|
polymerBehavior: parsePolymerBehavior,
|
|
pseudoElement: parsePseudoElement
|
|
};
|
|
|
|
/**
|
|
* Convert doctrine tags to hydrolysis tag format
|
|
*/
|
|
function _tagsToHydroTags(tags) {
|
|
if (!tags)
|
|
return null;
|
|
return tags.map( function(tag) {
|
|
if (tag.title in CUSTOM_TAGS) {
|
|
return CUSTOM_TAGS[tag.title](tag);
|
|
}
|
|
else {
|
|
return {
|
|
tag: tag.title,
|
|
type: tag.type ? doctrine.type.stringify(tag.type) : null,
|
|
name: tag.name,
|
|
description: tag.description,
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* removes leading *, and any space before it
|
|
* @param {string} description -- js doc description
|
|
*/
|
|
function _removeLeadingAsterisks(description) {
|
|
if ((typeof description) !== 'string')
|
|
return description;
|
|
|
|
return description
|
|
.split('\n')
|
|
.map( function(line) {
|
|
// remove leading '\s*' from each line
|
|
var match = line.match(/^[\s]*\*\s?(.*)$/);
|
|
return match ? match[1] : line;
|
|
})
|
|
.join('\n');
|
|
}
|
|
|
|
/**
|
|
* Given a JSDoc string (minus opening/closing comment delimiters), extract its
|
|
* description and tags.
|
|
*
|
|
* @param {string} docs
|
|
* @return {?JsdocAnnotation}
|
|
*/
|
|
function parseJsdoc(docs) {
|
|
docs = _removeLeadingAsterisks(docs);
|
|
var d = doctrine.parse(docs, {
|
|
unwrap: false,
|
|
lineNumber: true,
|
|
preserveWhitespace: true
|
|
});
|
|
return {
|
|
description: d.description,
|
|
tags: _tagsToHydroTags(d.tags)
|
|
};
|
|
}
|
|
|
|
// Utility
|
|
|
|
/**
|
|
* @param {JsdocAnnotation} jsdoc
|
|
* @param {string} tagName
|
|
* @return {boolean}
|
|
*/
|
|
function hasTag(jsdoc, tagName) {
|
|
if (!jsdoc || !jsdoc.tags) return false;
|
|
return jsdoc.tags.some(function(tag) { return tag.tag === tagName; });
|
|
}
|
|
|
|
/**
|
|
* Finds the first JSDoc tag matching `name` and returns its value at `key`.
|
|
*
|
|
* @param {JsdocAnnotation} jsdoc
|
|
* @param {string} tagName
|
|
* @param {string=} key If omitted, the entire tag object is returned.
|
|
* @return {?string|Object}
|
|
*/
|
|
function getTag(jsdoc, tagName, key) {
|
|
if (!jsdoc || !jsdoc.tags) return false;
|
|
for (var i = 0; i < jsdoc.tags.length; i++) {
|
|
var tag = jsdoc.tags[i];
|
|
if (tag.tag === tagName) {
|
|
return key ? tag[key] : tag;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param {?string} text
|
|
* @return {?string}
|
|
*/
|
|
function unindent(text) {
|
|
if (!text) return text;
|
|
var lines = text.replace(/\t/g, ' ').split('\n');
|
|
var indent = lines.reduce(function(prev, line) {
|
|
if (/^\s*$/.test(line)) return prev; // Completely ignore blank lines.
|
|
|
|
var lineIndent = line.match(/^(\s*)/)[0].length;
|
|
if (prev === null) return lineIndent;
|
|
return lineIndent < prev ? lineIndent : prev;
|
|
}, null);
|
|
|
|
return lines.map(function(l) { return l.substr(indent); }).join('\n');
|
|
}
|
|
|
|
module.exports = {
|
|
getTag: getTag,
|
|
hasTag: hasTag,
|
|
parseJsdoc: parseJsdoc,
|
|
unindent: unindent
|
|
};
|