/** * All parsing/transformation code goes here. All code here should be sync to ease testing. */ var Showdown = require('../../lib/showdown').Showdown; var DOM = require('./dom.js').DOM; var htmlEscape = require('./dom.js').htmlEscape; var Example = require('./example.js').Example; var NEW_LINE = /\n\r?/; var globalID = 0; exports.trim = trim; exports.metadata = metadata; exports.scenarios = scenarios; exports.merge = merge; exports.Doc = Doc; var BOOLEAN_ATTR = {}; ['multiple', 'selected', 'checked', 'disabled', 'readOnly', 'required'].forEach(function(value) { BOOLEAN_ATTR[value] = true; }); ////////////////////////////////////////////////////////// function Doc(text, file, line) { if (typeof text == 'object') { for ( var key in text) { this[key] = text[key]; } } else { this.text = text; this.file = file; this.line = line; } this.scenarios = this.scenarios || []; this.requires = this.requires || []; this.param = this.param || []; this.properties = this.properties || []; this.methods = this.methods || []; this.events = this.events || []; this.links = this.links || []; } Doc.METADATA_IGNORE = (function() { var words = require('fs').readFileSync(__dirname + '/ignore.words', 'utf8'); return words.toString().split(/[,\s\n\r]+/gm); })(); Doc.prototype = { keywords: function keywords() { var keywords = {}; var words = []; Doc.METADATA_IGNORE.forEach(function(ignore){ keywords[ignore] = true; }); function extractWords(text) { var tokens = text.toLowerCase().split(/[\.\s,`'"#]+/mg); tokens.forEach(function(key){ var match = key.match(/^((ng:|[\$_a-z])[\w\-_]+)/); if (match){ key = match[1]; if (!keywords[key]) { keywords[key] = true; words.push(key); } } }); } extractWords(this.text); this.properties.forEach(function(prop) { extractWords(prop.text || prop.description || ''); }); this.methods.forEach(function(method) { extractWords(method.text || method.description || ''); }); words.sort(); return words.join(' '); }, /** * Converts relative urls (without section) into absolute * Absolute url means url with section * * @example * - if the link is inside any api doc: * angular.widget -> api/angular.widget * * - if the link is inside any guid doc: * intro -> guide/intro * * @param {string} url Absolute or relative url * @returns {string} Absolute url */ convertUrlToAbsolute: function(url) { if (url.substr(-1) == '/') return url + 'index'; if (url.match(/\//)) return url; return this.section + '/' + url; }, markdown: function(text) { if (!text) return text; var self = this, IS_URL = /^(https?:\/\/|ftps?:\/\/|mailto:|\.|\/)/, IS_ANGULAR = /^(api\/)?(angular|ng|AUTO)\./, IS_HASH = /^#/, parts = trim(text).split(/(
[\s\S]*?<\/pre>|[\s\S]*?<\/doc:example>|]*>[\s\S]*?<\/example>)/),
      seq = 0,
      placeholderMap = {};

    function placeholder(text) {
      var id = 'REPLACEME' + (seq++);
      placeholderMap[id] = text;
      return id;
    }

    parts.forEach(function(text, i) {
      parts[i] = (text || '').
        replace(/([\s\S]*?)<\/example>/gmi, function(_, module, deps, content) {
          var example = new Example(self.scenarios);

          example.setModule(module);
          example.addDeps(deps);
          content.replace(/([\s\S]*?)<\/file>/gmi, function(_, name, content) {
            example.addSource(name, content);
          });
          return placeholder(example.toHtml());
        }).
        replace(/^]*)?>([\s\S]*)<\/doc:example>/mi, function(_, attrs, content) {
          var html, script, scenario,
            example = new Example(self.scenarios);

          example.setModule((attrs||'module=""').match(/^\s*module=["'](.*)["']\s*$/)[1]);
          content.
            replace(/]*)?>([\s\S]*)<\/doc:source>/mi, function(_, attrs, content) {
              example.addSource('index.html', content.
                replace(/