|
| 1 | +var path = require('canonical-path'); |
| 2 | +var fs = require("fs"); |
| 3 | +var FRAGMENT_DIR = "./public/docs/_fragments"; |
| 4 | + |
| 5 | +/** |
| 6 | + * @dgService exampleInlineTagDef |
| 7 | + * @description |
| 8 | + * Process inline example tags (of the form {@example relativePath region -title='some title' -stylePattern='{some style pattern}' }), |
| 9 | + * replacing them with a jade makeExample mixin call. |
| 10 | + * @kind function |
| 11 | + * @param {Object} path The relative path to example |
| 12 | + * @param {Function} docs error message |
| 13 | + * @return {String} The jade makeExample mixin call |
| 14 | + * |
| 15 | + * @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc |
| 16 | + */ |
| 17 | +module.exports = function exampleInlineTagDef(getLinkInfo, createDocMessage, log) { |
| 18 | + return { |
| 19 | + name: 'example', |
| 20 | + description: 'Process inline example tags (of the form {@example some/uri Some Title}), replacing them with HTML anchors', |
| 21 | + handler: function(doc, tagName, tagDescription) { |
| 22 | + |
| 23 | + var tagArgs = parseArgs(tagDescription); |
| 24 | + var unnamedArgs = tagArgs._; |
| 25 | + var relativePath = unnamedArgs[0]; |
| 26 | + var region = unnamedArgs.length > 1 && unnamedArgs[1]; |
| 27 | + var title = tagArgs.title; |
| 28 | + // TODO: not yet implemented here |
| 29 | + var stylePattern = tagArgs.stylePattern; |
| 30 | + |
| 31 | + var dir = path.join("_api", path.dirname(relativePath)); |
| 32 | + var extn = path.extname(relativePath); |
| 33 | + var baseNameNoExtn = path.basename(relativePath, extn); |
| 34 | + var fileName = region ? baseNameNoExtn + "-" + region + extn : baseNameNoExtn + extn; |
| 35 | + var fullFileName = path.join(FRAGMENT_DIR, dir, fileName); |
| 36 | + if ( !fs.existsSync(fileName)) { |
| 37 | + log.warn(createDocMessage('Invalid example (unable to locate fragment file: ' + quote(fullFileName), doc)); |
| 38 | + } |
| 39 | + |
| 40 | + var comma = ', ' |
| 41 | + var res = [ "+makeExample(", quote(dir), comma, quote(fileName), comma, title ? quote(title) : 'null', ")" ].join(''); |
| 42 | + return res; |
| 43 | + } |
| 44 | + |
| 45 | + }; |
| 46 | +}; |
| 47 | + |
| 48 | +function quote(str) { |
| 49 | + if (str == null || str.length === 0) return str; |
| 50 | + str = str.replace("'","'\'"); |
| 51 | + return "'" + str + "'"; |
| 52 | +} |
| 53 | + |
| 54 | + |
| 55 | +// processes an arg string in 'almost' the same fashion that the command processor does |
| 56 | +// and returns an args object in yargs format. |
| 57 | +function parseArgs(str) { |
| 58 | + // regex from npm string-argv |
| 59 | + //[^\s'"] Match if not a space ' or " |
| 60 | + |
| 61 | + //+|['] or Match ' |
| 62 | + //([^']*) Match anything that is not ' |
| 63 | + //['] Close match if ' |
| 64 | + |
| 65 | + //+|["] or Match " |
| 66 | + //([^"]*) Match anything that is not " |
| 67 | + //["] Close match if " |
| 68 | + var rx = /[^\s'"]+|[']([^']*?)[']|["]([^"]*?)["]/gi; |
| 69 | + var value = str; |
| 70 | + var unnammedArgs = []; |
| 71 | + var args = { _: unnammedArgs }; |
| 72 | + var match, key; |
| 73 | + do { |
| 74 | + //Each call to exec returns the next regex match as an array |
| 75 | + match = rx.exec(value); |
| 76 | + if (match !== null) { |
| 77 | + //Index 1 in the array is the captured group if it exists |
| 78 | + //Index 0 is the matched text, which we use if no captured group exists |
| 79 | + var arg = match[2] ? match[2] : (match[1]?match[1]:match[0]); |
| 80 | + if (key) { |
| 81 | + args[key] = arg; |
| 82 | + key = null; |
| 83 | + } else { |
| 84 | + if (arg.substr(arg.length-1) === '=') { |
| 85 | + key = arg.substr(0, arg.length-1); |
| 86 | + // remove leading '-' if it exists. |
| 87 | + if (key.substr(0,1)=='-') { |
| 88 | + key = key.substr(1); |
| 89 | + } |
| 90 | + } else { |
| 91 | + unnammedArgs.push(arg) |
| 92 | + key = null; |
| 93 | + } |
| 94 | + } |
| 95 | + } |
| 96 | + } while (match !== null); |
| 97 | + return args; |
| 98 | +} |
0 commit comments