| // This file is a source for playground examples. |
| // Examples integrity is smoke-checked with examples.spec.js |
| |
| function parse_defaults(source, parse, stringify, transforms) { |
| // Invoking parser with default config covers the most genearic cases. |
| // Note how /*** and /* blocks are ignored |
| |
| /** One-liner */ |
| |
| /** @some-tag {someType} someName */ |
| |
| /** |
| * Description may go |
| * over multiple lines followed by @tags |
| * @param {string} name the name parameter |
| * @param {any} value the value parameter |
| */ |
| |
| /*** ignored */ |
| /* ignored */ |
| |
| const parsed = parse(source); |
| const stringified = parsed.map((block) => stringify(block)); |
| } |
| |
| function parse_line_numbering(source, parse, stringify, transforms) { |
| // Note, line numbers are off by 5 from what you see in editor |
| // |
| // Try changeing start line back to 0, or omit the option |
| // parse(source, {startLine: 0}) -- default |
| // parse(source, {startLine: 5}) -- enforce alternative start number |
| |
| /** |
| * Description may go |
| * over multiple lines followed by @tags |
| * @param {string} name the name parameter |
| * @param {any} value the value parameter |
| */ |
| |
| const parsed = parse(source, { startLine: 5 }); |
| const stringified = parsed[0].tags |
| .map((tag) => `line ${tag.source[0].number + 1} : @${tag.tag} ${tag.name}`) |
| .join('\n'); |
| } |
| |
| function parse_spacing(source, parse, stringify, transforms) { |
| // Note, when spacing option is set to 'compact' or omited, tag and block descriptions are collapsed to look like a single sentense. |
| // |
| // Try changeing it to 'preserve' or defining custom function |
| // parse(source, {spacing: 'compact'}) -- default |
| // parse(source, {spacing: 'preserve'}) -- preserve spaces and line breaks |
| // parse(source, {spacing: lines => lines |
| // .map(tokens => tokens.description.trim()) |
| // .filter(description => description !== '') |
| // .join(' '); |
| // }) -- mimic 'compact' implementation |
| |
| /** |
| * Description may go |
| * over multiple lines followed by |
| * @param {string} name the name parameter |
| * with multiline description |
| * @param {function( |
| * number, |
| * string |
| * )} options the options |
| */ |
| |
| const parsed = parse(source, { spacing: 'preserve' }); |
| const stringified = parsed[0].tags |
| .map((tag) => `@${tag.tag} - ${tag.description}\n\n${tag.type}`) |
| .join('\n----\n'); |
| } |
| |
| function parse_escaping(source, parse, stringify, transforms) { |
| // Note, @decorator is not parsed as another tag because block is wrapped into ###. |
| // |
| // Try setting alternative escape sequence |
| // parse(source, {fence: '```'}) -- default |
| // parse(source, {fence: '###'}) -- update source correspondingly |
| |
| /** |
| * @example "some code" |
| ### |
| @decorator |
| function hello() { |
| // do something |
| } |
| ### |
| */ |
| |
| const parsed = parse(source, { fence: '###' }); |
| const stringified = parsed[0].tags |
| .map((tag) => `@${tag.tag} - ${tag.description}`) |
| .join('\n'); |
| } |
| |
| function stringify_formatting(source, parse, stringify, transforms) { |
| // stringify preserves exact formatting by default, but you can transform parsing result first |
| // transform = align() -- align name, type, and description |
| // transform = flow(align(), indent(4)) -- align, then place the block's opening marker at pos 4 |
| |
| /** |
| * Description may go |
| * over multiple lines followed by @tags |
| * @param {string} name the name parameter |
| * @param {any} value the value parameter |
| */ |
| |
| const { flow, align, indent } = transforms; |
| const transform = flow(align(), indent(4)); |
| |
| const parsed = parse(source); |
| const stringified = stringify(transform(parsed[0])); |
| } |
| |
| function parse_source_exploration(source, parse, stringify, transforms) { |
| // parse() produces Block[].source keeping accurate track of origin source |
| |
| /** |
| * Description may go |
| * over multiple lines followed by @tags |
| * @param {string} name the name parameter |
| * @param {any} value the value parameter |
| */ |
| |
| const parsed = parse(source); |
| |
| const summary = ({ source }) => ({ |
| source: source |
| .map( |
| ({ tokens }) => |
| tokens.start + |
| tokens.delimiter + |
| tokens.postDelimiter + |
| tokens.tag + |
| tokens.postTag + |
| tokens.type + |
| tokens.postType + |
| tokens.name + |
| tokens.postName + |
| tokens.description + |
| tokens.end |
| ) |
| .join('\n'), |
| start: { |
| line: source[0].number + 1, |
| column: source[0].tokens.start.length, |
| }, |
| end: { |
| line: source[source.length - 1].number + 1, |
| column: source[source.length - 1].source.length, |
| }, |
| }); |
| |
| const pos = (p) => p.line + ':' + p.column; |
| |
| const stringified = parsed[0].tags |
| .map(summary) |
| .map((s) => `${pos(s.start)} - ${pos(s.end)}\n${s.source}`); |
| } |
| |
| function parse_advanced_parsing(source, parse, _, _, tokenizers) { |
| // Each '@tag ...' section results into a Spec. The Spec is computed by |
| // the chain of tokenizers each contributing a change to the the Spec.* and the Spec.tags[].tokens. |
| // Default parse() options come with stadart tokenizers: |
| // { |
| // ..., |
| // spacing = 'compact', |
| // tokenizers = [ |
| // tokenizers.tag(), |
| // tokenizers.type(spacing), |
| // tokenizers.name(), |
| // tokenizers.description(spacing), |
| // ] |
| // } |
| // You can reorder those, or even replace any with a custom function (spec: Spec) => Spec |
| // This example allows to parse "@tag description" comments |
| |
| /** |
| * @arg0 my parameter |
| * @arg1 |
| * another parameter |
| * with a strange formatting |
| */ |
| |
| const parsed = parse(source, { |
| tokenizers: [tokenizers.tag(), tokenizers.description('preserve')], |
| }); |
| const stringified = parsed[0].tags |
| .map((tag) => `@${tag.tag} - ${tag.description}`) |
| .join('\n'); |
| } |
| |
| function stringify_rename(source, parse, stringify, transforms) { |
| // You can do any manipulations with the parsed result |
| // See how each block is being mapped. If you are updating a Block.source |
| // then rewireSource(block) should be called on each changed block. |
| // If changes were made to Block.tags[].source then call rewireSpecs(block). |
| // This example shows how you can "rename" @param tags: value1 -> value11, value2 -> value22 |
| |
| /** |
| * Description may go |
| * over multiple lines followed by @tags |
| * @param {string} name the name parameter |
| * @param {any} value1 first value parameter |
| * with a multipline description |
| * @param {any} value2 second value parameter |
| */ |
| |
| function renameParam(from, to) { |
| return (block) => { |
| for (const tag of block.tags) { |
| if (tag.tag === 'param' && tag.name === from) { |
| tag.name = to; |
| for (const line of tag.source) { |
| if (line.tokens.name === from) line.tokens.name = to; |
| } |
| } |
| } |
| return block; |
| }; |
| } |
| |
| const transform = transforms.flow( |
| renameParam('value1', 'value11'), |
| renameParam('value2', 'value22'), |
| stringify |
| ); |
| |
| const parsed = parse(source); |
| const stringified = parsed.map(transform); |
| } |
| |
| (typeof window === 'undefined' ? module.exports : window).examples = [ |
| parse_defaults, |
| parse_line_numbering, |
| parse_escaping, |
| parse_spacing, |
| parse_source_exploration, |
| parse_advanced_parsing, |
| stringify_formatting, |
| stringify_rename, |
| ]; |