packages/docpack-jsdoc-extractor/lib/parseXMLExamples.js (85 lines of code) (raw):

var sax = require('sax'); var stripIndent = require('strip-indent'); var Example = require('docpack/lib/data/Example'); var ExampleFile = require('docpack/lib/data/ExampleFile'); var FILE_TAG = 'file'; var EXAMPLE_TAG = 'example'; var PARSER_STRICT_MODE = false; var PARSER_OPTIONS = { lowercase: true }; var TAG_START_REGEXP = /(?:<\s*\/\s*file\s*>)(?![\s\S]*<\s*\/\s*file\s*>)/; var EXAMPLE_START_REGEXP = /(?:<\s*\/\s*example\s*>)(?![\s\S]*<\s*\/\s*example\s*>)/; /** * @param {string} content * @returns {Array<Example>|null} */ module.exports = function (content) { var hasXMLExamples = content.match(EXAMPLE_START_REGEXP); var examples = []; var wrappedContent = '<root>' + content + '</root>'; var files = []; var fileNode = null; var exampleNode = null; var fileContentStartPosition = null; var exampleContentStartPosition = null; var parser = sax.parser(PARSER_STRICT_MODE, PARSER_OPTIONS); if (!hasXMLExamples) { return []; } function stopFileParsing() { fileNode = null; fileContentStartPosition = null; } function stopExampleParsing() { files = []; exampleNode = null; exampleContentStartPosition = null; } function getTagContent(startPosition, currentPosition, regexp) { var previousContent = wrappedContent.substring(0, currentPosition); var match = previousContent.match(regexp); var endPosition = match && match.index; return endPosition ? wrappedContent.substring(startPosition, endPosition) : ''; } parser.onopentag = function (node) { if (node.name === EXAMPLE_TAG && !exampleNode) { exampleNode = node; exampleContentStartPosition = parser.position; } // Don't go deeper than one level if (node.name === FILE_TAG && exampleNode && !fileNode) { fileNode = node; fileContentStartPosition = parser.position; } }; parser.onclosetag = function (nodeName) { var tagContent; if (nodeName === EXAMPLE_TAG && exampleNode) { tagContent = getTagContent( exampleContentStartPosition, parser.position, EXAMPLE_START_REGEXP ); examples.push(new Example({ content: stripIndent(tagContent), attrs: exampleNode.attributes, files: files })); stopFileParsing(); stopExampleParsing(); } if (nodeName === FILE_TAG && exampleNode && fileNode) { tagContent = getTagContent( fileContentStartPosition, parser.position, TAG_START_REGEXP ); if (tagContent == null) { stopFileParsing(); return; } files.push(new ExampleFile({ type: fileNode.attributes.type || 'js', content: stripIndent(tagContent), attrs: fileNode.attributes })); stopFileParsing(); } }; parser.write(wrappedContent).close(); return examples; };