diff --git a/.clang-tidy b/.clang-tidy index 9274a133..1307bee6 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -5,6 +5,7 @@ Checks: >- -*osx*, -abseil*, -android*, + -boost*, -bugprone-branch-clone, -bugprone-exception-escape, -bugprone-easily-swappable-parameters, @@ -29,11 +30,16 @@ Checks: >- -google-default-arguments, -google-explicit-constructor, -google-build-using-namespace, + -google-upgrade-*, + -google-runtime-int, -hicpp-signed-bitwise, -hicpp-explicit-conversions, -llvmlibc-*, -llvm-header-guard, -llvm-namespace-comment, + -llvm-prefer-register-over-unsigned, + -llvm-twine-local, + -misc-confusable-identifiers, -misc-no-recursion, -misc-non-private-member-variables-in-classes, -misc-const-correctness, @@ -44,6 +50,7 @@ Checks: >- -mpi*, -objc*, -openmp*, + -performance-unnecessary-value-param, -readability-inconsistent-declaration-parameter-name, -readability-identifier-length, -readability-identifier-naming, diff --git a/.clang-uml b/.clang-uml index ec0124c5..ceef3fe2 100644 --- a/.clang-uml +++ b/.clang-uml @@ -2,6 +2,7 @@ compilation_database_dir: debug output_directory: docs/diagrams comment_parser: clang add_compile_flags: + - -fparse-all-comments - -Wno-deprecated-declarations remove_compile_flags: - -Wno-class-memaccess @@ -37,7 +38,7 @@ diagrams: include!: uml/class/stylable_element_hierarchy_class.yml source_location_hierarchy_class: include!: uml/class/source_location_hierarchy_class.yml - "filter_visitor_hierarchy_class": + filter_visitor_hierarchy_class: include!: uml/class/filter_visitor_hierarchy_class.yml diagram_filter_context_class: include!: uml/class/diagram_filter_context_class.yml @@ -76,6 +77,8 @@ diagrams: include!: uml/sequence/diagram_generate_generic_sequence.yml class_diagram_generator_sequence: include!: uml/sequence/class_diagram_generator_sequence.yml + plantuml_sequence_diagram_generator_sequence: + include!: uml/sequence/plantuml_sequence_diagram_generator_sequence.yml template_builder_sequence: include!: uml/sequence/template_builder_sequence.yml # Package diagrams diff --git a/CHANGELOG.md b/CHANGELOG.md index a7e0de0b..785324e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG +### 0.5.1 + + * Fixed elements filter in sequence diagrams (#248) + * Fixed progress indicators ranges with multiple commands per TU (#240) + * Added default diagram generation error for empty diagrams (#246) + * Added style option to plantuml config section (#238) + * Added generate_concept_requirements config option (#237) + * Refactored util pipe handling (#244) + * Fixed handling of variadic template parameters in sequence diagrams (#241) + * Fixed handling of query_driver option in config file (#243) + ### 0.5.0 * Fixed static linking against LLVM (#225) * Fixed handling of absolute paths in glob patterns (#233) diff --git a/Doxyfile b/Doxyfile index 73fda184..91fbeddf 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "clang-uml" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.5.0 +PROJECT_NUMBER = 0.5.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index 710a0ccd..9254ddce 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build status](https://github.com/bkryza/clang-uml/actions/workflows/build.yml/badge.svg)](https://github.com/bkryza/clang-uml/actions) [![Coverage](https://codecov.io/gh/bkryza/clang-uml/branch/master/graph/badge.svg)](https://codecov.io/gh/bkryza/clang-uml) -[![Version](https://img.shields.io/badge/version-0.5.0-blue)](https://github.com/bkryza/clang-uml/releases) +[![Version](https://img.shields.io/badge/version-0.5.1-blue)](https://github.com/bkryza/clang-uml/releases) [![Version](https://img.shields.io/badge/LLVM-12,13,14,15,16,17-orange)](https://github.com/bkryza/clang-uml/releases) [![Doxygen](https://img.shields.io/badge/Docs-Doxygen-gainsboro)](https://clang-uml.github.io) diff --git a/docs/class_diagrams.md b/docs/class_diagrams.md index ac6a670b..dda12be7 100644 --- a/docs/class_diagrams.md +++ b/docs/class_diagrams.md @@ -90,8 +90,10 @@ type of relationship generated in the class diagrams. By default, a member from which a relationship has been added to the diagram -between 2 classes will also be rendered inside the class. This behaviour can be -however disabled by adding the following option to the diagram definition: +between 2 classes will also be rendered inside as a property inside the class +box. This behaviour can be however disabled by adding the following option to +the diagram definition: + ```yaml include_relations_also_as_members: false ``` @@ -158,7 +160,7 @@ which results in the following diagram: ![t00036_class](test_cases/t00036_class.svg) ### Directory packages -In case the code base is structured based on subdirectory instead of namespaces +In case the code base is structured based on subdirectories instead of namespaces (or this is a C project, where namespaces are not available), packages can be generated based on the location of a given declaration in the filesystem tree, by adding also the following option: @@ -175,8 +177,10 @@ which results in the following diagram: > properly configured for your project, if necessary add `relative_to` option to > denote the root path against which all relative paths in the config file are > calculated. + ### Module packages + Finally, to generate UML packages in the diagram based on C++20 modules, use the following option: @@ -213,7 +217,7 @@ this can be easily achieved using `context` inclusion filter: ``` By default, the diagram will include only elements in direct relationship to -`ns1::MyClass`, but an addition option called `radius` can be added to this +`ns1::MyClass`, but an additional option called `radius` can be added to this filter, which will extend the context to elements related to `ns1::MyClass` through at most N relationships, e.g: diff --git a/docs/common_options.md b/docs/common_options.md index 38513e05..c8fea3ba 100644 --- a/docs/common_options.md +++ b/docs/common_options.md @@ -15,30 +15,34 @@ ## Overall configuration file structure -By default, `clang-uml` will look for file `.clang-uml` in the project's directory and read all diagrams definitions -configuration from it. The file must be specified in YAML and it's overall structure is as follows: +By default, `clang-uml` will look for file `.clang-uml` in the project's +directory and read all diagram definitions configuration from it. The file must +be specified in YAML and it's overall structure is as follows: ```yaml -# common options for all diagrams -... +# Common options for all diagrams +# ... +# Diagram definitions diagrams: first_diagram_name: type: class|sequence|package|include - # diagram specific options - ... + # Diagram specific options + # ... second_diagram_name: type: class|sequence|package|include - # diagram specific options - ... - ... + # Diagram specific options + # ... + # More diagrams + # ... ``` -The top level common options are inherited by specific diagrams, if the option is applicable to them and they themselves -do not override this option. +The top level common options are inherited by specific diagrams, if the option +is applicable to them and they themselves do not override this option. For detailed reference of all configuration options see [here](./configuration_file.md). -Effective configuration, including default values can be printed out in YAML format using the following option: +Effective configuration, including default values can be printed out in YAML +format using the following option: ```bash clang-uml --dump-config @@ -56,10 +60,11 @@ diagrams: ``` ## Translation unit glob patterns -One of the key options of the diagram configuration is the list of translation units, which should be parsed to -get all necessary information for a diagram. +One of the key options of the diagram configuration is the list of translation +units, which should be parsed to get all necessary information for a diagram. -The syntax is simple and based on glob patterns, which can be added to the configuration file as follows: +The syntax is simple and based on glob patterns, which can be added to the +configuration file as follows: ```yaml glob: @@ -67,13 +72,17 @@ The syntax is simple and based on glob patterns, which can be added to the confi - src/dir3/*.cc ``` -The glob patterns only need to match the translation units, which are also in the `compile_commands.json` file, i.e. -any files that match the glob patterns, but are not in `compile_commands.json` will be ignored. In case the `glob` -pattern set does not match any translation units an error will be printed on the standard output. +The glob patterns only need to match the translation units, which are also in +the `compile_commands.json` file, i.e. any files that match the glob patterns, +but are not in `compile_commands.json` will be ignored. In case the `glob` +pattern set does not match any translation units an error will be printed on +the standard output. -For small projects, the `glob` property can be omitted, which will result in `clang-uml` parsing all translation units -from `compile_commands.json` for the diagram. However, for large projects, constraining the number of translation units -for each diagram to absolute minimum will significantly decrease the diagram generation times. +For small projects, the `glob` property can be omitted, which will result in +`clang-uml` parsing all translation units from `compile_commands.json` for +the diagram. However, for large projects, constraining the number of translation +units for each diagram to minimum necessary to discover all necessary diagram +elements will significantly decrease the diagram generation times. ## Custom directives In case it's necessary to add some custom PlantUML or MermaidJS declarations @@ -122,13 +131,13 @@ the generated PlantUML diagram will contain comments before each line containing the source location of the specific diagram element. ## Resolving include path and compiler flags issues -Due to the fact, that your project can be compiled with different compilers +Due to the fact, that a project can be compiled with different compilers and toolchains, the system paths and compilation flags detected by the Clang version linked to your `clang-uml` installation might differ from the ones actually used to compile your project. > This is often an issue on macOS, when `clang-uml` uses Homebrew version of LLVM -> and your project was built using system Apple Clang +> and a project was built using system Apple Clang. Typically, this results in error messages on the console during diagram generation, such as: diff --git a/docs/diagram_filters.md b/docs/diagram_filters.md index 759b7c49..4e996f4f 100644 --- a/docs/diagram_filters.md +++ b/docs/diagram_filters.md @@ -40,7 +40,7 @@ to your diagram configuration: ``` Some filters accept either specified exact values, some support regular -expressions while some except glob patterns. +expressions while some accept glob patterns. For filters which accept regular expressions, the regular expression has to be provided as a map ```r: 'pattern'``` due to the fact the pointer (```*```) otherwise @@ -54,8 +54,6 @@ exclude: - r: '.*test.*' ``` -`paths` filter is currently the only filter which accepts `glob` like patterns. - The following table specifies the values allowed in each filter: | Filter name | Possible values | Example values | @@ -64,7 +62,7 @@ The following table specifies the values allowed in each filter: | `modules` | Qualified name or regex | ```mod1.mod2:par1```, ```r: '.*impl.*'``` | | `elements` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: '.*detail.*'``` | | `element_types` | Types of diagram elements | ```class```, ```enum```, ```concept``` | -| `paths` | File or dir path or glob pattern | ```src/dir1```, ```src/dir2/a.cpp```, ```src/dir3/*.cpp``` | +| `paths` | File or dir path | ```src/dir1```, ```src/dir2/a.cpp```, ```src/dir3/*.cpp``` | | `context` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` | | `relationships` | Type of relationship | ```inheritance```, ```composition```, ```aggregation```, ```ownership```, ```association```, ```instantiation```, ```friendship```, ```dependency``` | | `subclasses` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` | diff --git a/docs/doxygen/highlight.js b/docs/doxygen/highlight.js index dd0992d4..caf91ac1 100644 --- a/docs/doxygen/highlight.js +++ b/docs/doxygen/highlight.js @@ -1,2129 +1,2136 @@ /*! - Highlight.js v11.7.0 (git: 82688fad18) - (c) 2006-2022 undefined and other contributors + Highlight.js v11.9.0 (git: b7ec4bfafc) + (c) 2006-2023 undefined and other contributors License: BSD-3-Clause */ var hljs = (function () { - 'use strict'; + 'use strict'; - var deepFreezeEs6 = {exports: {}}; + /* eslint-disable no-multi-assign */ - function deepFreeze(obj) { - if (obj instanceof Map) { - obj.clear = obj.delete = obj.set = function () { - throw new Error('map is read-only'); - }; - } else if (obj instanceof Set) { - obj.add = obj.clear = obj.delete = function () { - throw new Error('set is read-only'); - }; - } - - // Freeze self - Object.freeze(obj); - - Object.getOwnPropertyNames(obj).forEach(function (name) { - var prop = obj[name]; - - // Freeze prop if it is an object - if (typeof prop == 'object' && !Object.isFrozen(prop)) { - deepFreeze(prop); - } - }); - - return obj; + function deepFreeze(obj) { + if (obj instanceof Map) { + obj.clear = + obj.delete = + obj.set = + function () { + throw new Error('map is read-only'); + }; + } else if (obj instanceof Set) { + obj.add = + obj.clear = + obj.delete = + function () { + throw new Error('set is read-only'); + }; } - deepFreezeEs6.exports = deepFreeze; - deepFreezeEs6.exports.default = deepFreeze; + // Freeze self + Object.freeze(obj); - /** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */ - /** @typedef {import('highlight.js').CompiledMode} CompiledMode */ - /** @implements CallbackResponse */ + Object.getOwnPropertyNames(obj).forEach((name) => { + const prop = obj[name]; + const type = typeof prop; - class Response { - /** - * @param {CompiledMode} mode - */ - constructor(mode) { - // eslint-disable-next-line no-undefined - if (mode.data === undefined) mode.data = {}; - - this.data = mode.data; - this.isMatchIgnored = false; + // Freeze prop if it is an object or function and also not already frozen + if ((type === 'object' || type === 'function') && !Object.isFrozen(prop)) { + deepFreeze(prop); } + }); - ignoreMatch() { - this.isMatchIgnored = true; - } - } + return obj; + } + /** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */ + /** @typedef {import('highlight.js').CompiledMode} CompiledMode */ + /** @implements CallbackResponse */ + + class Response { /** - * @param {string} value - * @returns {string} + * @param {CompiledMode} mode */ - function escapeHTML(value) { - return value - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); + constructor(mode) { + // eslint-disable-next-line no-undefined + if (mode.data === undefined) mode.data = {}; + + this.data = mode.data; + this.isMatchIgnored = false; } + ignoreMatch() { + this.isMatchIgnored = true; + } + } + + /** + * @param {string} value + * @returns {string} + */ + function escapeHTML(value) { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + /** + * performs a shallow merge of multiple objects into one + * + * @template T + * @param {T} original + * @param {Record[]} objects + * @returns {T} a single new object + */ + function inherit$1(original, ...objects) { + /** @type Record */ + const result = Object.create(null); + + for (const key in original) { + result[key] = original[key]; + } + objects.forEach(function(obj) { + for (const key in obj) { + result[key] = obj[key]; + } + }); + return /** @type {T} */ (result); + } + + /** + * @typedef {object} Renderer + * @property {(text: string) => void} addText + * @property {(node: Node) => void} openNode + * @property {(node: Node) => void} closeNode + * @property {() => string} value + */ + + /** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */ + /** @typedef {{walk: (r: Renderer) => void}} Tree */ + /** */ + + const SPAN_CLOSE = ''; + + /** + * Determines if a node needs to be wrapped in + * + * @param {Node} node */ + const emitsWrappingTags = (node) => { + // rarely we can have a sublanguage where language is undefined + // TODO: track down why + return !!node.scope; + }; + + /** + * + * @param {string} name + * @param {{prefix:string}} options + */ + const scopeToCSSClass = (name, { prefix }) => { + // sub-language + if (name.startsWith("language:")) { + return name.replace("language:", "language-"); + } + // tiered scope: comment.line + if (name.includes(".")) { + const pieces = name.split("."); + return [ + `${prefix}${pieces.shift()}`, + ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`)) + ].join(" "); + } + // simple scope + return `${prefix}${name}`; + }; + + /** @type {Renderer} */ + class HTMLRenderer { /** - * performs a shallow merge of multiple objects into one + * Creates a new HTMLRenderer * - * @template T - * @param {T} original - * @param {Record[]} objects - * @returns {T} a single new object + * @param {Tree} parseTree - the parse tree (must support `walk` API) + * @param {{classPrefix: string}} options */ - function inherit$1(original, ...objects) { - /** @type Record */ - const result = Object.create(null); - - for (const key in original) { - result[key] = original[key]; - } - objects.forEach(function(obj) { - for (const key in obj) { - result[key] = obj[key]; - } - }); - return /** @type {T} */ (result); + constructor(parseTree, options) { + this.buffer = ""; + this.classPrefix = options.classPrefix; + parseTree.walk(this); } /** - * @typedef {object} Renderer - * @property {(text: string) => void} addText - * @property {(node: Node) => void} openNode - * @property {(node: Node) => void} closeNode - * @property {() => string} value - */ - - /** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */ - /** @typedef {{walk: (r: Renderer) => void}} Tree */ - /** */ - - const SPAN_CLOSE = ''; + * Adds texts to the output stream + * + * @param {string} text */ + addText(text) { + this.buffer += escapeHTML(text); + } /** - * Determines if a node needs to be wrapped in + * Adds a node open to the output stream (if needed) * * @param {Node} node */ - const emitsWrappingTags = (node) => { - // rarely we can have a sublanguage where language is undefined - // TODO: track down why - return !!node.scope || (node.sublanguage && node.language); - }; + openNode(node) { + if (!emitsWrappingTags(node)) return; + + const className = scopeToCSSClass(node.scope, + { prefix: this.classPrefix }); + this.span(className); + } /** + * Adds a node close to the output stream (if needed) * - * @param {string} name - * @param {{prefix:string}} options - */ - const scopeToCSSClass = (name, { prefix }) => { - if (name.includes(".")) { - const pieces = name.split("."); - return [ - `${prefix}${pieces.shift()}`, - ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`)) - ].join(" "); - } - return `${prefix}${name}`; - }; + * @param {Node} node */ + closeNode(node) { + if (!emitsWrappingTags(node)) return; - /** @type {Renderer} */ - class HTMLRenderer { - /** - * Creates a new HTMLRenderer - * - * @param {Tree} parseTree - the parse tree (must support `walk` API) - * @param {{classPrefix: string}} options - */ - constructor(parseTree, options) { - this.buffer = ""; - this.classPrefix = options.classPrefix; - parseTree.walk(this); - } - - /** - * Adds texts to the output stream - * - * @param {string} text */ - addText(text) { - this.buffer += escapeHTML(text); - } - - /** - * Adds a node open to the output stream (if needed) - * - * @param {Node} node */ - openNode(node) { - if (!emitsWrappingTags(node)) return; - - let className = ""; - if (node.sublanguage) { - className = `language-${node.language}`; - } else { - className = scopeToCSSClass(node.scope, { prefix: this.classPrefix }); - } - this.span(className); - } - - /** - * Adds a node close to the output stream (if needed) - * - * @param {Node} node */ - closeNode(node) { - if (!emitsWrappingTags(node)) return; - - this.buffer += SPAN_CLOSE; - } - - /** - * returns the accumulated buffer - */ - value() { - return this.buffer; - } - - // helpers - - /** - * Builds a span element - * - * @param {string} className */ - span(className) { - this.buffer += ``; - } - } - - /** @typedef {{scope?: string, language?: string, sublanguage?: boolean, children: Node[]} | string} Node */ - /** @typedef {{scope?: string, language?: string, sublanguage?: boolean, children: Node[]} } DataNode */ - /** @typedef {import('highlight.js').Emitter} Emitter */ - /** */ - - /** @returns {DataNode} */ - const newNode = (opts = {}) => { - /** @type DataNode */ - const result = { children: [] }; - Object.assign(result, opts); - return result; - }; - - class TokenTree { - constructor() { - /** @type DataNode */ - this.rootNode = newNode(); - this.stack = [this.rootNode]; - } - - get top() { - return this.stack[this.stack.length - 1]; - } - - get root() { return this.rootNode; } - - /** @param {Node} node */ - add(node) { - this.top.children.push(node); - } - - /** @param {string} scope */ - openNode(scope) { - /** @type Node */ - const node = newNode({ scope }); - this.add(node); - this.stack.push(node); - } - - closeNode() { - if (this.stack.length > 1) { - return this.stack.pop(); - } - // eslint-disable-next-line no-undefined - return undefined; - } - - closeAllNodes() { - while (this.closeNode()); - } - - toJSON() { - return JSON.stringify(this.rootNode, null, 4); - } - - /** - * @typedef { import("./html_renderer").Renderer } Renderer - * @param {Renderer} builder - */ - walk(builder) { - // this does not - return this.constructor._walk(builder, this.rootNode); - // this works - // return TokenTree._walk(builder, this.rootNode); - } - - /** - * @param {Renderer} builder - * @param {Node} node - */ - static _walk(builder, node) { - if (typeof node === "string") { - builder.addText(node); - } else if (node.children) { - builder.openNode(node); - node.children.forEach((child) => this._walk(builder, child)); - builder.closeNode(node); - } - return builder; - } - - /** - * @param {Node} node - */ - static _collapse(node) { - if (typeof node === "string") return; - if (!node.children) return; - - if (node.children.every(el => typeof el === "string")) { - // node.text = node.children.join(""); - // delete node.children; - node.children = [node.children.join("")]; - } else { - node.children.forEach((child) => { - TokenTree._collapse(child); - }); - } - } + this.buffer += SPAN_CLOSE; } /** - Currently this is all private API, but this is the minimal API necessary - that an Emitter must implement to fully support the parser. - - Minimal interface: - - - addKeyword(text, scope) - - addText(text) - - addSublanguage(emitter, subLanguageName) - - finalize() - - openNode(scope) - - closeNode() - - closeAllNodes() - - toHTML() - + * returns the accumulated buffer */ + value() { + return this.buffer; + } + + // helpers /** - * @implements {Emitter} + * Builds a span element + * + * @param {string} className */ + span(className) { + this.buffer += ``; + } + } + + /** @typedef {{scope?: string, language?: string, children: Node[]} | string} Node */ + /** @typedef {{scope?: string, language?: string, children: Node[]} } DataNode */ + /** @typedef {import('highlight.js').Emitter} Emitter */ + /** */ + + /** @returns {DataNode} */ + const newNode = (opts = {}) => { + /** @type DataNode */ + const result = { children: [] }; + Object.assign(result, opts); + return result; + }; + + class TokenTree { + constructor() { + /** @type DataNode */ + this.rootNode = newNode(); + this.stack = [this.rootNode]; + } + + get top() { + return this.stack[this.stack.length - 1]; + } + + get root() { return this.rootNode; } + + /** @param {Node} node */ + add(node) { + this.top.children.push(node); + } + + /** @param {string} scope */ + openNode(scope) { + /** @type Node */ + const node = newNode({ scope }); + this.add(node); + this.stack.push(node); + } + + closeNode() { + if (this.stack.length > 1) { + return this.stack.pop(); + } + // eslint-disable-next-line no-undefined + return undefined; + } + + closeAllNodes() { + while (this.closeNode()); + } + + toJSON() { + return JSON.stringify(this.rootNode, null, 4); + } + + /** + * @typedef { import("./html_renderer").Renderer } Renderer + * @param {Renderer} builder */ - class TokenTreeEmitter extends TokenTree { + walk(builder) { + // this does not + return this.constructor._walk(builder, this.rootNode); + // this works + // return TokenTree._walk(builder, this.rootNode); + } + + /** + * @param {Renderer} builder + * @param {Node} node + */ + static _walk(builder, node) { + if (typeof node === "string") { + builder.addText(node); + } else if (node.children) { + builder.openNode(node); + node.children.forEach((child) => this._walk(builder, child)); + builder.closeNode(node); + } + return builder; + } + + /** + * @param {Node} node + */ + static _collapse(node) { + if (typeof node === "string") return; + if (!node.children) return; + + if (node.children.every(el => typeof el === "string")) { + // node.text = node.children.join(""); + // delete node.children; + node.children = [node.children.join("")]; + } else { + node.children.forEach((child) => { + TokenTree._collapse(child); + }); + } + } + } + + /** + Currently this is all private API, but this is the minimal API necessary + that an Emitter must implement to fully support the parser. + + Minimal interface: + + - addText(text) + - __addSublanguage(emitter, subLanguageName) + - startScope(scope) + - endScope() + - finalize() + - toHTML() + + */ + + /** + * @implements {Emitter} + */ + class TokenTreeEmitter extends TokenTree { + /** + * @param {*} options + */ + constructor(options) { + super(); + this.options = options; + } + + /** + * @param {string} text + */ + addText(text) { + if (text === "") { return; } + + this.add(text); + } + + /** @param {string} scope */ + startScope(scope) { + this.openNode(scope); + } + + endScope() { + this.closeNode(); + } + + /** + * @param {Emitter & {root: DataNode}} emitter + * @param {string} name + */ + __addSublanguage(emitter, name) { + /** @type DataNode */ + const node = emitter.root; + if (name) node.scope = `language:${name}`; + + this.add(node); + } + + toHTML() { + const renderer = new HTMLRenderer(this, this.options); + return renderer.value(); + } + + finalize() { + this.closeAllNodes(); + return true; + } + } + + /** + * @param {string} value + * @returns {RegExp} + * */ + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function source(re) { + if (!re) return null; + if (typeof re === "string") return re; + + return re.source; + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function lookahead(re) { + return concat('(?=', re, ')'); + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function anyNumberOfTimes(re) { + return concat('(?:', re, ')*'); + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function optional(re) { + return concat('(?:', re, ')?'); + } + + /** + * @param {...(RegExp | string) } args + * @returns {string} + */ + function concat(...args) { + const joined = args.map((x) => source(x)).join(""); + return joined; + } + + /** + * @param { Array } args + * @returns {object} + */ + function stripOptionsFromArgs(args) { + const opts = args[args.length - 1]; + + if (typeof opts === 'object' && opts.constructor === Object) { + args.splice(args.length - 1, 1); + return opts; + } else { + return {}; + } + } + + /** @typedef { {capture?: boolean} } RegexEitherOptions */ + + /** + * Any of the passed expresssions may match + * + * Creates a huge this | this | that | that match + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args + * @returns {string} + */ + function either(...args) { + /** @type { object & {capture?: boolean} } */ + const opts = stripOptionsFromArgs(args); + const joined = '(' + + (opts.capture ? "" : "?:") + + args.map((x) => source(x)).join("|") + ")"; + return joined; + } + + /** + * @param {RegExp | string} re + * @returns {number} + */ + function countMatchGroups(re) { + return (new RegExp(re.toString() + '|')).exec('').length - 1; + } + + /** + * Does lexeme start with a regular expression match at the beginning + * @param {RegExp} re + * @param {string} lexeme + */ + function startsWith(re, lexeme) { + const match = re && re.exec(lexeme); + return match && match.index === 0; + } + + // BACKREF_RE matches an open parenthesis or backreference. To avoid + // an incorrect parse, it additionally matches the following: + // - [...] elements, where the meaning of parentheses and escapes change + // - other escape sequences, so we do not misparse escape sequences as + // interesting elements + // - non-matching or lookahead parentheses, which do not capture. These + // follow the '(' with a '?'. + const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./; + + // **INTERNAL** Not intended for outside usage + // join logically computes regexps.join(separator), but fixes the + // backreferences so they continue to match. + // it also places each individual regular expression into it's own + // match group, keeping track of the sequencing of those match groups + // is currently an exercise for the caller. :-) + /** + * @param {(string | RegExp)[]} regexps + * @param {{joinWith: string}} opts + * @returns {string} + */ + function _rewriteBackreferences(regexps, { joinWith }) { + let numCaptures = 0; + + return regexps.map((regex) => { + numCaptures += 1; + const offset = numCaptures; + let re = source(regex); + let out = ''; + + while (re.length > 0) { + const match = BACKREF_RE.exec(re); + if (!match) { + out += re; + break; + } + out += re.substring(0, match.index); + re = re.substring(match.index + match[0].length); + if (match[0][0] === '\\' && match[1]) { + // Adjust the backreference. + out += '\\' + String(Number(match[1]) + offset); + } else { + out += match[0]; + if (match[0] === '(') { + numCaptures++; + } + } + } + return out; + }).map(re => `(${re})`).join(joinWith); + } + + /** @typedef {import('highlight.js').Mode} Mode */ + /** @typedef {import('highlight.js').ModeCallback} ModeCallback */ + + // Common regexps + const MATCH_NOTHING_RE = /\b\B/; + const IDENT_RE = '[a-zA-Z]\\w*'; + const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; + const NUMBER_RE = '\\b\\d+(\\.\\d+)?'; + const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float + const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... + const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; + + /** + * @param { Partial & {binary?: string | RegExp} } opts + */ + const SHEBANG = (opts = {}) => { + const beginShebang = /^#![ ]*\//; + if (opts.binary) { + opts.begin = concat( + beginShebang, + /.*\b/, + opts.binary, + /\b.*/); + } + return inherit$1({ + scope: 'meta', + begin: beginShebang, + end: /$/, + relevance: 0, + /** @type {ModeCallback} */ + "on:begin": (m, resp) => { + if (m.index !== 0) resp.ignoreMatch(); + } + }, opts); + }; + + // Common modes + const BACKSLASH_ESCAPE = { + begin: '\\\\[\\s\\S]', relevance: 0 + }; + const APOS_STRING_MODE = { + scope: 'string', + begin: '\'', + end: '\'', + illegal: '\\n', + contains: [BACKSLASH_ESCAPE] + }; + const QUOTE_STRING_MODE = { + scope: 'string', + begin: '"', + end: '"', + illegal: '\\n', + contains: [BACKSLASH_ESCAPE] + }; + const PHRASAL_WORDS_MODE = { + begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ + }; + /** + * Creates a comment mode + * + * @param {string | RegExp} begin + * @param {string | RegExp} end + * @param {Mode | {}} [modeOptions] + * @returns {Partial} + */ + const COMMENT = function(begin, end, modeOptions = {}) { + const mode = inherit$1( + { + scope: 'comment', + begin, + end, + contains: [] + }, + modeOptions + ); + mode.contains.push({ + scope: 'doctag', + // hack to avoid the space from being included. the space is necessary to + // match here to prevent the plain text rule below from gobbling up doctags + begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)', + end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/, + excludeBegin: true, + relevance: 0 + }); + const ENGLISH_WORD = either( + // list of common 1 and 2 letter words in English + "I", + "a", + "is", + "so", + "us", + "to", + "at", + "if", + "in", + "it", + "on", + // note: this is not an exhaustive list of contractions, just popular ones + /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc + /[A-Za-z]+[-][a-z]+/, // `no-way`, etc. + /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences + ); + // looking like plain text, more likely to be a comment + mode.contains.push( + { + // TODO: how to include ", (, ) without breaking grammars that use these for + // comment delimiters? + // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/ + // --- + + // this tries to find sequences of 3 english words in a row (without any + // "programming" type syntax) this gives us a strong signal that we've + // TRULY found a comment - vs perhaps scanning with the wrong language. + // It's possible to find something that LOOKS like the start of the + // comment - but then if there is no readable text - good chance it is a + // false match and not a comment. + // + // for a visual example please see: + // https://github.com/highlightjs/highlight.js/issues/2827 + + begin: concat( + /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */ + '(', + ENGLISH_WORD, + /[.]?[:]?([.][ ]|[ ])/, + '){3}') // look for 3 words in a row + } + ); + return mode; + }; + const C_LINE_COMMENT_MODE = COMMENT('//', '$'); + const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/'); + const HASH_COMMENT_MODE = COMMENT('#', '$'); + const NUMBER_MODE = { + scope: 'number', + begin: NUMBER_RE, + relevance: 0 + }; + const C_NUMBER_MODE = { + scope: 'number', + begin: C_NUMBER_RE, + relevance: 0 + }; + const BINARY_NUMBER_MODE = { + scope: 'number', + begin: BINARY_NUMBER_RE, + relevance: 0 + }; + const REGEXP_MODE = { + scope: "regexp", + begin: /\/(?=[^/\n]*\/)/, + end: /\/[gimuy]*/, + contains: [ + BACKSLASH_ESCAPE, + { + begin: /\[/, + end: /\]/, + relevance: 0, + contains: [BACKSLASH_ESCAPE] + } + ] + }; + const TITLE_MODE = { + scope: 'title', + begin: IDENT_RE, + relevance: 0 + }; + const UNDERSCORE_TITLE_MODE = { + scope: 'title', + begin: UNDERSCORE_IDENT_RE, + relevance: 0 + }; + const METHOD_GUARD = { + // excludes method names from keyword processing + begin: '\\.\\s*' + UNDERSCORE_IDENT_RE, + relevance: 0 + }; + + /** + * Adds end same as begin mechanics to a mode + * + * Your mode must include at least a single () match group as that first match + * group is what is used for comparison + * @param {Partial} mode + */ + const END_SAME_AS_BEGIN = function(mode) { + return Object.assign(mode, + { + /** @type {ModeCallback} */ + 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; }, + /** @type {ModeCallback} */ + 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); } + }); + }; + + var MODES = /*#__PURE__*/Object.freeze({ + __proto__: null, + APOS_STRING_MODE: APOS_STRING_MODE, + BACKSLASH_ESCAPE: BACKSLASH_ESCAPE, + BINARY_NUMBER_MODE: BINARY_NUMBER_MODE, + BINARY_NUMBER_RE: BINARY_NUMBER_RE, + COMMENT: COMMENT, + C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE, + C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE, + C_NUMBER_MODE: C_NUMBER_MODE, + C_NUMBER_RE: C_NUMBER_RE, + END_SAME_AS_BEGIN: END_SAME_AS_BEGIN, + HASH_COMMENT_MODE: HASH_COMMENT_MODE, + IDENT_RE: IDENT_RE, + MATCH_NOTHING_RE: MATCH_NOTHING_RE, + METHOD_GUARD: METHOD_GUARD, + NUMBER_MODE: NUMBER_MODE, + NUMBER_RE: NUMBER_RE, + PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE, + QUOTE_STRING_MODE: QUOTE_STRING_MODE, + REGEXP_MODE: REGEXP_MODE, + RE_STARTERS_RE: RE_STARTERS_RE, + SHEBANG: SHEBANG, + TITLE_MODE: TITLE_MODE, + UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE, + UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE + }); + + /** + @typedef {import('highlight.js').CallbackResponse} CallbackResponse + @typedef {import('highlight.js').CompilerExt} CompilerExt + */ + + // Grammar extensions / plugins + // See: https://github.com/highlightjs/highlight.js/issues/2833 + + // Grammar extensions allow "syntactic sugar" to be added to the grammar modes + // without requiring any underlying changes to the compiler internals. + + // `compileMatch` being the perfect small example of now allowing a grammar + // author to write `match` when they desire to match a single expression rather + // than being forced to use `begin`. The extension then just moves `match` into + // `begin` when it runs. Ie, no features have been added, but we've just made + // the experience of writing (and reading grammars) a little bit nicer. + + // ------ + + // TODO: We need negative look-behind support to do this properly + /** + * Skip a match if it has a preceding dot + * + * This is used for `beginKeywords` to prevent matching expressions such as + * `bob.keyword.do()`. The mode compiler automatically wires this up as a + * special _internal_ 'on:begin' callback for modes with `beginKeywords` + * @param {RegExpMatchArray} match + * @param {CallbackResponse} response + */ + function skipIfHasPrecedingDot(match, response) { + const before = match.input[match.index - 1]; + if (before === ".") { + response.ignoreMatch(); + } + } + + /** + * + * @type {CompilerExt} + */ + function scopeClassName(mode, _parent) { + // eslint-disable-next-line no-undefined + if (mode.className !== undefined) { + mode.scope = mode.className; + delete mode.className; + } + } + + /** + * `beginKeywords` syntactic sugar + * @type {CompilerExt} + */ + function beginKeywords(mode, parent) { + if (!parent) return; + if (!mode.beginKeywords) return; + + // for languages with keywords that include non-word characters checking for + // a word boundary is not sufficient, so instead we check for a word boundary + // or whitespace - this does no harm in any case since our keyword engine + // doesn't allow spaces in keywords anyways and we still check for the boundary + // first + mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)'; + mode.__beforeBegin = skipIfHasPrecedingDot; + mode.keywords = mode.keywords || mode.beginKeywords; + delete mode.beginKeywords; + + // prevents double relevance, the keywords themselves provide + // relevance, the mode doesn't need to double it + // eslint-disable-next-line no-undefined + if (mode.relevance === undefined) mode.relevance = 0; + } + + /** + * Allow `illegal` to contain an array of illegal values + * @type {CompilerExt} + */ + function compileIllegal(mode, _parent) { + if (!Array.isArray(mode.illegal)) return; + + mode.illegal = either(...mode.illegal); + } + + /** + * `match` to match a single expression for readability + * @type {CompilerExt} + */ + function compileMatch(mode, _parent) { + if (!mode.match) return; + if (mode.begin || mode.end) throw new Error("begin & end are not supported with match"); + + mode.begin = mode.match; + delete mode.match; + } + + /** + * provides the default 1 relevance to all modes + * @type {CompilerExt} + */ + function compileRelevance(mode, _parent) { + // eslint-disable-next-line no-undefined + if (mode.relevance === undefined) mode.relevance = 1; + } + + // allow beforeMatch to act as a "qualifier" for the match + // the full match begin must be [beforeMatch][begin] + const beforeMatchExt = (mode, parent) => { + if (!mode.beforeMatch) return; + // starts conflicts with endsParent which we need to make sure the child + // rule is not matched multiple times + if (mode.starts) throw new Error("beforeMatch cannot be used with starts"); + + const originalMode = Object.assign({}, mode); + Object.keys(mode).forEach((key) => { delete mode[key]; }); + + mode.keywords = originalMode.keywords; + mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin)); + mode.starts = { + relevance: 0, + contains: [ + Object.assign(originalMode, { endsParent: true }) + ] + }; + mode.relevance = 0; + + delete originalMode.beforeMatch; + }; + + // keywords that should have no default relevance value + const COMMON_KEYWORDS = [ + 'of', + 'and', + 'for', + 'in', + 'not', + 'or', + 'if', + 'then', + 'parent', // common variable name + 'list', // common variable name + 'value' // common variable name + ]; + + const DEFAULT_KEYWORD_SCOPE = "keyword"; + + /** + * Given raw keywords from a language definition, compile them. + * + * @param {string | Record | Array} rawKeywords + * @param {boolean} caseInsensitive + */ + function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) { + /** @type {import("highlight.js/private").KeywordDict} */ + const compiledKeywords = Object.create(null); + + // input can be a string of keywords, an array of keywords, or a object with + // named keys representing scopeName (which can then point to a string or array) + if (typeof rawKeywords === 'string') { + compileList(scopeName, rawKeywords.split(" ")); + } else if (Array.isArray(rawKeywords)) { + compileList(scopeName, rawKeywords); + } else { + Object.keys(rawKeywords).forEach(function(scopeName) { + // collapse all our objects back into the parent object + Object.assign( + compiledKeywords, + compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName) + ); + }); + } + return compiledKeywords; + + // --- + + /** + * Compiles an individual list of keywords + * + * Ex: "for if when while|5" + * + * @param {string} scopeName + * @param {Array} keywordList + */ + function compileList(scopeName, keywordList) { + if (caseInsensitive) { + keywordList = keywordList.map(x => x.toLowerCase()); + } + keywordList.forEach(function(keyword) { + const pair = keyword.split('|'); + compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])]; + }); + } + } + + /** + * Returns the proper score for a given keyword + * + * Also takes into account comment keywords, which will be scored 0 UNLESS + * another score has been manually assigned. + * @param {string} keyword + * @param {string} [providedScore] + */ + function scoreForKeyword(keyword, providedScore) { + // manual scores always win over common keywords + // so you can force a score of 1 if you really insist + if (providedScore) { + return Number(providedScore); + } + + return commonKeyword(keyword) ? 0 : 1; + } + + /** + * Determines if a given keyword is common or not + * + * @param {string} keyword */ + function commonKeyword(keyword) { + return COMMON_KEYWORDS.includes(keyword.toLowerCase()); + } + + /* + + For the reasoning behind this please see: + https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419 + + */ + + /** + * @type {Record} + */ + const seenDeprecations = {}; + + /** + * @param {string} message + */ + const error = (message) => { + console.error(message); + }; + + /** + * @param {string} message + * @param {any} args + */ + const warn = (message, ...args) => { + console.log(`WARN: ${message}`, ...args); + }; + + /** + * @param {string} version + * @param {string} message + */ + const deprecated = (version, message) => { + if (seenDeprecations[`${version}/${message}`]) return; + + console.log(`Deprecated as of ${version}. ${message}`); + seenDeprecations[`${version}/${message}`] = true; + }; + + /* eslint-disable no-throw-literal */ + + /** + @typedef {import('highlight.js').CompiledMode} CompiledMode + */ + + const MultiClassError = new Error(); + + /** + * Renumbers labeled scope names to account for additional inner match + * groups that otherwise would break everything. + * + * Lets say we 3 match scopes: + * + * { 1 => ..., 2 => ..., 3 => ... } + * + * So what we need is a clean match like this: + * + * (a)(b)(c) => [ "a", "b", "c" ] + * + * But this falls apart with inner match groups: + * + * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ] + * + * Our scopes are now "out of alignment" and we're repeating `b` 3 times. + * What needs to happen is the numbers are remapped: + * + * { 1 => ..., 2 => ..., 5 => ... } + * + * We also need to know that the ONLY groups that should be output + * are 1, 2, and 5. This function handles this behavior. + * + * @param {CompiledMode} mode + * @param {Array} regexes + * @param {{key: "beginScope"|"endScope"}} opts + */ + function remapScopeNames(mode, regexes, { key }) { + let offset = 0; + const scopeNames = mode[key]; + /** @type Record */ + const emit = {}; + /** @type Record */ + const positions = {}; + + for (let i = 1; i <= regexes.length; i++) { + positions[i + offset] = scopeNames[i]; + emit[i + offset] = true; + offset += countMatchGroups(regexes[i - 1]); + } + // we use _emit to keep track of which match groups are "top-level" to avoid double + // output from inside match groups + mode[key] = positions; + mode[key]._emit = emit; + mode[key]._multi = true; + } + + /** + * @param {CompiledMode} mode + */ + function beginMultiClass(mode) { + if (!Array.isArray(mode.begin)) return; + + if (mode.skip || mode.excludeBegin || mode.returnBegin) { + error("skip, excludeBegin, returnBegin not compatible with beginScope: {}"); + throw MultiClassError; + } + + if (typeof mode.beginScope !== "object" || mode.beginScope === null) { + error("beginScope must be object"); + throw MultiClassError; + } + + remapScopeNames(mode, mode.begin, { key: "beginScope" }); + mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" }); + } + + /** + * @param {CompiledMode} mode + */ + function endMultiClass(mode) { + if (!Array.isArray(mode.end)) return; + + if (mode.skip || mode.excludeEnd || mode.returnEnd) { + error("skip, excludeEnd, returnEnd not compatible with endScope: {}"); + throw MultiClassError; + } + + if (typeof mode.endScope !== "object" || mode.endScope === null) { + error("endScope must be object"); + throw MultiClassError; + } + + remapScopeNames(mode, mode.end, { key: "endScope" }); + mode.end = _rewriteBackreferences(mode.end, { joinWith: "" }); + } + + /** + * this exists only to allow `scope: {}` to be used beside `match:` + * Otherwise `beginScope` would necessary and that would look weird + + { + match: [ /def/, /\w+/ ] + scope: { 1: "keyword" , 2: "title" } + } + + * @param {CompiledMode} mode + */ + function scopeSugar(mode) { + if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) { + mode.beginScope = mode.scope; + delete mode.scope; + } + } + + /** + * @param {CompiledMode} mode + */ + function MultiClass(mode) { + scopeSugar(mode); + + if (typeof mode.beginScope === "string") { + mode.beginScope = { _wrap: mode.beginScope }; + } + if (typeof mode.endScope === "string") { + mode.endScope = { _wrap: mode.endScope }; + } + + beginMultiClass(mode); + endMultiClass(mode); + } + + /** + @typedef {import('highlight.js').Mode} Mode + @typedef {import('highlight.js').CompiledMode} CompiledMode + @typedef {import('highlight.js').Language} Language + @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin + @typedef {import('highlight.js').CompiledLanguage} CompiledLanguage + */ + + // compilation + + /** + * Compiles a language definition result + * + * Given the raw result of a language definition (Language), compiles this so + * that it is ready for highlighting code. + * @param {Language} language + * @returns {CompiledLanguage} + */ + function compileLanguage(language) { + /** + * Builds a regex with the case sensitivity of the current language + * + * @param {RegExp | string} value + * @param {boolean} [global] + */ + function langRe(value, global) { + return new RegExp( + source(value), + 'm' + + (language.case_insensitive ? 'i' : '') + + (language.unicodeRegex ? 'u' : '') + + (global ? 'g' : '') + ); + } + + /** + Stores multiple regular expressions and allows you to quickly search for + them all in a string simultaneously - returning the first match. It does + this by creating a huge (a|b|c) regex - each individual item wrapped with () + and joined by `|` - using match groups to track position. When a match is + found checking which position in the array has content allows us to figure + out which of the original regexes / match groups triggered the match. + + The match object itself (the result of `Regex.exec`) is returned but also + enhanced by merging in any meta-data that was registered with the regex. + This is how we keep track of which mode matched, and what type of rule + (`illegal`, `begin`, end, etc). + */ + class MultiRegex { + constructor() { + this.matchIndexes = {}; + // @ts-ignore + this.regexes = []; + this.matchAt = 1; + this.position = 0; + } + + // @ts-ignore + addRule(re, opts) { + opts.position = this.position++; + // @ts-ignore + this.matchIndexes[this.matchAt] = opts; + this.regexes.push([opts, re]); + this.matchAt += countMatchGroups(re) + 1; + } + + compile() { + if (this.regexes.length === 0) { + // avoids the need to check length every time exec is called + // @ts-ignore + this.exec = () => null; + } + const terminators = this.regexes.map(el => el[1]); + this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true); + this.lastIndex = 0; + } + + /** @param {string} s */ + exec(s) { + this.matcherRe.lastIndex = this.lastIndex; + const match = this.matcherRe.exec(s); + if (!match) { return null; } + + // eslint-disable-next-line no-undefined + const i = match.findIndex((el, i) => i > 0 && el !== undefined); + // @ts-ignore + const matchData = this.matchIndexes[i]; + // trim off any earlier non-relevant match groups (ie, the other regex + // match groups that make up the multi-matcher) + match.splice(0, i); + + return Object.assign(match, matchData); + } + } + + /* + Created to solve the key deficiently with MultiRegex - there is no way to + test for multiple matches at a single location. Why would we need to do + that? In the future a more dynamic engine will allow certain matches to be + ignored. An example: if we matched say the 3rd regex in a large group but + decided to ignore it - we'd need to started testing again at the 4th + regex... but MultiRegex itself gives us no real way to do that. + + So what this class creates MultiRegexs on the fly for whatever search + position they are needed. + + NOTE: These additional MultiRegex objects are created dynamically. For most + grammars most of the time we will never actually need anything more than the + first MultiRegex - so this shouldn't have too much overhead. + + Say this is our search group, and we match regex3, but wish to ignore it. + + regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0 + + What we need is a new MultiRegex that only includes the remaining + possibilities: + + regex4 | regex5 ' ie, startAt = 3 + + This class wraps all that complexity up in a simple API... `startAt` decides + where in the array of expressions to start doing the matching. It + auto-increments, so if a match is found at position 2, then startAt will be + set to 3. If the end is reached startAt will return to 0. + + MOST of the time the parser will be setting startAt manually to 0. + */ + class ResumableMultiRegex { + constructor() { + // @ts-ignore + this.rules = []; + // @ts-ignore + this.multiRegexes = []; + this.count = 0; + + this.lastIndex = 0; + this.regexIndex = 0; + } + + // @ts-ignore + getMatcher(index) { + if (this.multiRegexes[index]) return this.multiRegexes[index]; + + const matcher = new MultiRegex(); + this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts)); + matcher.compile(); + this.multiRegexes[index] = matcher; + return matcher; + } + + resumingScanAtSamePosition() { + return this.regexIndex !== 0; + } + + considerAll() { + this.regexIndex = 0; + } + + // @ts-ignore + addRule(re, opts) { + this.rules.push([re, opts]); + if (opts.type === "begin") this.count++; + } + + /** @param {string} s */ + exec(s) { + const m = this.getMatcher(this.regexIndex); + m.lastIndex = this.lastIndex; + let result = m.exec(s); + + // The following is because we have no easy way to say "resume scanning at the + // existing position but also skip the current rule ONLY". What happens is + // all prior rules are also skipped which can result in matching the wrong + // thing. Example of matching "booger": + + // our matcher is [string, "booger", number] + // + // ....booger.... + + // if "booger" is ignored then we'd really need a regex to scan from the + // SAME position for only: [string, number] but ignoring "booger" (if it + // was the first match), a simple resume would scan ahead who knows how + // far looking only for "number", ignoring potential string matches (or + // future "booger" matches that might be valid.) + + // So what we do: We execute two matchers, one resuming at the same + // position, but the second full matcher starting at the position after: + + // /--- resume first regex match here (for [number]) + // |/---- full match here for [string, "booger", number] + // vv + // ....booger.... + + // Which ever results in a match first is then used. So this 3-4 step + // process essentially allows us to say "match at this position, excluding + // a prior rule that was ignored". + // + // 1. Match "booger" first, ignore. Also proves that [string] does non match. + // 2. Resume matching for [number] + // 3. Match at index + 1 for [string, "booger", number] + // 4. If #2 and #3 result in matches, which came first? + if (this.resumingScanAtSamePosition()) { + if (result && result.index === this.lastIndex) ; else { // use the second matcher result + const m2 = this.getMatcher(0); + m2.lastIndex = this.lastIndex + 1; + result = m2.exec(s); + } + } + + if (result) { + this.regexIndex += result.position + 1; + if (this.regexIndex === this.count) { + // wrap-around to considering all matches again + this.considerAll(); + } + } + + return result; + } + } + + /** + * Given a mode, builds a huge ResumableMultiRegex that can be used to walk + * the content and find matches. + * + * @param {CompiledMode} mode + * @returns {ResumableMultiRegex} + */ + function buildModeRegex(mode) { + const mm = new ResumableMultiRegex(); + + mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" })); + + if (mode.terminatorEnd) { + mm.addRule(mode.terminatorEnd, { type: "end" }); + } + if (mode.illegal) { + mm.addRule(mode.illegal, { type: "illegal" }); + } + + return mm; + } + + /** skip vs abort vs ignore + * + * @skip - The mode is still entered and exited normally (and contains rules apply), + * but all content is held and added to the parent buffer rather than being + * output when the mode ends. Mostly used with `sublanguage` to build up + * a single large buffer than can be parsed by sublanguage. + * + * - The mode begin ands ends normally. + * - Content matched is added to the parent mode buffer. + * - The parser cursor is moved forward normally. + * + * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it + * never matched) but DOES NOT continue to match subsequent `contains` + * modes. Abort is bad/suboptimal because it can result in modes + * farther down not getting applied because an earlier rule eats the + * content but then aborts. + * + * - The mode does not begin. + * - Content matched by `begin` is added to the mode buffer. + * - The parser cursor is moved forward accordingly. + * + * @ignore - Ignores the mode (as if it never matched) and continues to match any + * subsequent `contains` modes. Ignore isn't technically possible with + * the current parser implementation. + * + * - The mode does not begin. + * - Content matched by `begin` is ignored. + * - The parser cursor is not moved forward. + */ + + /** + * Compiles an individual mode + * + * This can raise an error if the mode contains certain detectable known logic + * issues. + * @param {Mode} mode + * @param {CompiledMode | null} [parent] + * @returns {CompiledMode | never} + */ + function compileMode(mode, parent) { + const cmode = /** @type CompiledMode */ (mode); + if (mode.isCompiled) return cmode; + + [ + scopeClassName, + // do this early so compiler extensions generally don't have to worry about + // the distinction between match/begin + compileMatch, + MultiClass, + beforeMatchExt + ].forEach(ext => ext(mode, parent)); + + language.compilerExtensions.forEach(ext => ext(mode, parent)); + + // __beforeBegin is considered private API, internal use only + mode.__beforeBegin = null; + + [ + beginKeywords, + // do this later so compiler extensions that come earlier have access to the + // raw array if they wanted to perhaps manipulate it, etc. + compileIllegal, + // default to 1 relevance if not specified + compileRelevance + ].forEach(ext => ext(mode, parent)); + + mode.isCompiled = true; + + let keywordPattern = null; + if (typeof mode.keywords === "object" && mode.keywords.$pattern) { + // we need a copy because keywords might be compiled multiple times + // so we can't go deleting $pattern from the original on the first + // pass + mode.keywords = Object.assign({}, mode.keywords); + keywordPattern = mode.keywords.$pattern; + delete mode.keywords.$pattern; + } + keywordPattern = keywordPattern || /\w+/; + + if (mode.keywords) { + mode.keywords = compileKeywords(mode.keywords, language.case_insensitive); + } + + cmode.keywordPatternRe = langRe(keywordPattern, true); + + if (parent) { + if (!mode.begin) mode.begin = /\B|\b/; + cmode.beginRe = langRe(cmode.begin); + if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/; + if (mode.end) cmode.endRe = langRe(cmode.end); + cmode.terminatorEnd = source(cmode.end) || ''; + if (mode.endsWithParent && parent.terminatorEnd) { + cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd; + } + } + if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal)); + if (!mode.contains) mode.contains = []; + + mode.contains = [].concat(...mode.contains.map(function(c) { + return expandOrCloneMode(c === 'self' ? mode : c); + })); + mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); }); + + if (mode.starts) { + compileMode(mode.starts, parent); + } + + cmode.matcher = buildModeRegex(cmode); + return cmode; + } + + if (!language.compilerExtensions) language.compilerExtensions = []; + + // self is not valid at the top-level + if (language.contains && language.contains.includes('self')) { + throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation."); + } + + // we need a null object, which inherit will guarantee + language.classNameAliases = inherit$1(language.classNameAliases || {}); + + return compileMode(/** @type Mode */ (language)); + } + + /** + * Determines if a mode has a dependency on it's parent or not + * + * If a mode does have a parent dependency then often we need to clone it if + * it's used in multiple places so that each copy points to the correct parent, + * where-as modes without a parent can often safely be re-used at the bottom of + * a mode chain. + * + * @param {Mode | null} mode + * @returns {boolean} - is there a dependency on the parent? + * */ + function dependencyOnParent(mode) { + if (!mode) return false; + + return mode.endsWithParent || dependencyOnParent(mode.starts); + } + + /** + * Expands a mode or clones it if necessary + * + * This is necessary for modes with parental dependenceis (see notes on + * `dependencyOnParent`) and for nodes that have `variants` - which must then be + * exploded into their own individual modes at compile time. + * + * @param {Mode} mode + * @returns {Mode | Mode[]} + * */ + function expandOrCloneMode(mode) { + if (mode.variants && !mode.cachedVariants) { + mode.cachedVariants = mode.variants.map(function(variant) { + return inherit$1(mode, { variants: null }, variant); + }); + } + + // EXPAND + // if we have variants then essentially "replace" the mode with the variants + // this happens in compileMode, where this function is called from + if (mode.cachedVariants) { + return mode.cachedVariants; + } + + // CLONE + // if we have dependencies on parents then we need a unique + // instance of ourselves, so we can be reused with many + // different parents without issue + if (dependencyOnParent(mode)) { + return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null }); + } + + if (Object.isFrozen(mode)) { + return inherit$1(mode); + } + + // no special dependency issues, just return ourselves + return mode; + } + + var version = "11.9.0"; + + class HTMLInjectionError extends Error { + constructor(reason, html) { + super(reason); + this.name = "HTMLInjectionError"; + this.html = html; + } + } + + /* + Syntax highlighting with language autodetection. + https://highlightjs.org/ + */ + + + + /** + @typedef {import('highlight.js').Mode} Mode + @typedef {import('highlight.js').CompiledMode} CompiledMode + @typedef {import('highlight.js').CompiledScope} CompiledScope + @typedef {import('highlight.js').Language} Language + @typedef {import('highlight.js').HLJSApi} HLJSApi + @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin + @typedef {import('highlight.js').PluginEvent} PluginEvent + @typedef {import('highlight.js').HLJSOptions} HLJSOptions + @typedef {import('highlight.js').LanguageFn} LanguageFn + @typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement + @typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext + @typedef {import('highlight.js/private').MatchType} MatchType + @typedef {import('highlight.js/private').KeywordData} KeywordData + @typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch + @typedef {import('highlight.js/private').AnnotatedError} AnnotatedError + @typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult + @typedef {import('highlight.js').HighlightOptions} HighlightOptions + @typedef {import('highlight.js').HighlightResult} HighlightResult + */ + + + const escape = escapeHTML; + const inherit = inherit$1; + const NO_MATCH = Symbol("nomatch"); + const MAX_KEYWORD_HITS = 7; + + /** + * @param {any} hljs - object that is extended (legacy) + * @returns {HLJSApi} + */ + const HLJS = function(hljs) { + // Global internal variables used within the highlight.js library. + /** @type {Record} */ + const languages = Object.create(null); + /** @type {Record} */ + const aliases = Object.create(null); + /** @type {HLJSPlugin[]} */ + const plugins = []; + + // safe/production mode - swallows more errors, tries to keep running + // even if a single syntax or parse hits a fatal error + let SAFE_MODE = true; + const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?"; + /** @type {Language} */ + const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] }; + + // Global options used when within external APIs. This is modified when + // calling the `hljs.configure` function. + /** @type HLJSOptions */ + let options = { + ignoreUnescapedHTML: false, + throwUnescapedHTML: false, + noHighlightRe: /^(no-?highlight)$/i, + languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i, + classPrefix: 'hljs-', + cssSelector: 'pre code', + languages: null, + // beta configuration options, subject to change, welcome to discuss + // https://github.com/highlightjs/highlight.js/issues/1086 + __emitter: TokenTreeEmitter + }; + + /* Utility functions */ + + /** + * Tests a language name to see if highlighting should be skipped + * @param {string} languageName + */ + function shouldNotHighlight(languageName) { + return options.noHighlightRe.test(languageName); + } + + /** + * @param {HighlightedHTMLElement} block - the HTML element to determine language for + */ + function blockLanguage(block) { + let classes = block.className + ' '; + + classes += block.parentNode ? block.parentNode.className : ''; + + // language-* takes precedence over non-prefixed class names. + const match = options.languageDetectRe.exec(classes); + if (match) { + const language = getLanguage(match[1]); + if (!language) { + warn(LANGUAGE_NOT_FOUND.replace("{}", match[1])); + warn("Falling back to no-highlight mode for this block.", block); + } + return language ? match[1] : 'no-highlight'; + } + + return classes + .split(/\s+/) + .find((_class) => shouldNotHighlight(_class) || getLanguage(_class)); + } + + /** + * Core highlighting function. + * + * OLD API + * highlight(lang, code, ignoreIllegals, continuation) + * + * NEW API + * highlight(code, {lang, ignoreIllegals}) + * + * @param {string} codeOrLanguageName - the language to use for highlighting + * @param {string | HighlightOptions} optionsOrCode - the code to highlight + * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail + * + * @returns {HighlightResult} Result - an object that represents the result + * @property {string} language - the language name + * @property {number} relevance - the relevance score + * @property {string} value - the highlighted HTML code + * @property {string} code - the original raw code + * @property {CompiledMode} top - top of the current mode stack + * @property {boolean} illegal - indicates whether any illegal matches were found + */ + function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) { + let code = ""; + let languageName = ""; + if (typeof optionsOrCode === "object") { + code = codeOrLanguageName; + ignoreIllegals = optionsOrCode.ignoreIllegals; + languageName = optionsOrCode.language; + } else { + // old API + deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated."); + deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"); + languageName = codeOrLanguageName; + code = optionsOrCode; + } + + // https://github.com/highlightjs/highlight.js/issues/3149 + // eslint-disable-next-line no-undefined + if (ignoreIllegals === undefined) { ignoreIllegals = true; } + + /** @type {BeforeHighlightContext} */ + const context = { + code, + language: languageName + }; + // the plugin can change the desired language or the code to be highlighted + // just be changing the object it was passed + fire("before:highlight", context); + + // a before plugin can usurp the result completely by providing it's own + // in which case we don't even need to call highlight + const result = context.result + ? context.result + : _highlight(context.language, context.code, ignoreIllegals); + + result.code = context.code; + // the plugin can change anything in result to suite it + fire("after:highlight", result); + + return result; + } + + /** + * private highlight that's used internally and does not fire callbacks + * + * @param {string} languageName - the language to use for highlighting + * @param {string} codeToHighlight - the code to highlight + * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail + * @param {CompiledMode?} [continuation] - current continuation mode, if any + * @returns {HighlightResult} - result of the highlight operation + */ + function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) { + const keywordHits = Object.create(null); + /** - * @param {*} options + * Return keyword data if a match is a keyword + * @param {CompiledMode} mode - current mode + * @param {string} matchText - the textual match + * @returns {KeywordData | false} */ - constructor(options) { - super(); - this.options = options; + function keywordData(mode, matchText) { + return mode.keywords[matchText]; + } + + function processKeywords() { + if (!top.keywords) { + emitter.addText(modeBuffer); + return; + } + + let lastIndex = 0; + top.keywordPatternRe.lastIndex = 0; + let match = top.keywordPatternRe.exec(modeBuffer); + let buf = ""; + + while (match) { + buf += modeBuffer.substring(lastIndex, match.index); + const word = language.case_insensitive ? match[0].toLowerCase() : match[0]; + const data = keywordData(top, word); + if (data) { + const [kind, keywordRelevance] = data; + emitter.addText(buf); + buf = ""; + + keywordHits[word] = (keywordHits[word] || 0) + 1; + if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance; + if (kind.startsWith("_")) { + // _ implied for relevance only, do not highlight + // by applying a class name + buf += match[0]; + } else { + const cssClass = language.classNameAliases[kind] || kind; + emitKeyword(match[0], cssClass); + } + } else { + buf += match[0]; + } + lastIndex = top.keywordPatternRe.lastIndex; + match = top.keywordPatternRe.exec(modeBuffer); + } + buf += modeBuffer.substring(lastIndex); + emitter.addText(buf); + } + + function processSubLanguage() { + if (modeBuffer === "") return; + /** @type HighlightResult */ + let result = null; + + if (typeof top.subLanguage === 'string') { + if (!languages[top.subLanguage]) { + emitter.addText(modeBuffer); + return; + } + result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]); + continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top); + } else { + result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null); + } + + // Counting embedded language score towards the host language may be disabled + // with zeroing the containing mode relevance. Use case in point is Markdown that + // allows XML everywhere and makes every XML snippet to have a much larger Markdown + // score. + if (top.relevance > 0) { + relevance += result.relevance; + } + emitter.__addSublanguage(result._emitter, result.language); + } + + function processBuffer() { + if (top.subLanguage != null) { + processSubLanguage(); + } else { + processKeywords(); + } + modeBuffer = ''; } /** * @param {string} text * @param {string} scope */ - addKeyword(text, scope) { - if (text === "") { return; } + function emitKeyword(keyword, scope) { + if (keyword === "") return; - this.openNode(scope); - this.addText(text); - this.closeNode(); + emitter.startScope(scope); + emitter.addText(keyword); + emitter.endScope(); } /** - * @param {string} text + * @param {CompiledScope} scope + * @param {RegExpMatchArray} match */ - addText(text) { - if (text === "") { return; } - - this.add(text); - } - - /** - * @param {Emitter & {root: DataNode}} emitter - * @param {string} name - */ - addSublanguage(emitter, name) { - /** @type DataNode */ - const node = emitter.root; - node.sublanguage = true; - node.language = name; - this.add(node); - } - - toHTML() { - const renderer = new HTMLRenderer(this, this.options); - return renderer.value(); - } - - finalize() { - return true; - } - } - - /** - * @param {string} value - * @returns {RegExp} - * */ - - /** - * @param {RegExp | string } re - * @returns {string} - */ - function source(re) { - if (!re) return null; - if (typeof re === "string") return re; - - return re.source; - } - - /** - * @param {RegExp | string } re - * @returns {string} - */ - function lookahead(re) { - return concat('(?=', re, ')'); - } - - /** - * @param {RegExp | string } re - * @returns {string} - */ - function anyNumberOfTimes(re) { - return concat('(?:', re, ')*'); - } - - /** - * @param {RegExp | string } re - * @returns {string} - */ - function optional(re) { - return concat('(?:', re, ')?'); - } - - /** - * @param {...(RegExp | string) } args - * @returns {string} - */ - function concat(...args) { - const joined = args.map((x) => source(x)).join(""); - return joined; - } - - /** - * @param { Array } args - * @returns {object} - */ - function stripOptionsFromArgs(args) { - const opts = args[args.length - 1]; - - if (typeof opts === 'object' && opts.constructor === Object) { - args.splice(args.length - 1, 1); - return opts; - } else { - return {}; - } - } - - /** @typedef { {capture?: boolean} } RegexEitherOptions */ - - /** - * Any of the passed expresssions may match - * - * Creates a huge this | this | that | that match - * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args - * @returns {string} - */ - function either(...args) { - /** @type { object & {capture?: boolean} } */ - const opts = stripOptionsFromArgs(args); - const joined = '(' - + (opts.capture ? "" : "?:") - + args.map((x) => source(x)).join("|") + ")"; - return joined; - } - - /** - * @param {RegExp | string} re - * @returns {number} - */ - function countMatchGroups(re) { - return (new RegExp(re.toString() + '|')).exec('').length - 1; - } - - /** - * Does lexeme start with a regular expression match at the beginning - * @param {RegExp} re - * @param {string} lexeme - */ - function startsWith(re, lexeme) { - const match = re && re.exec(lexeme); - return match && match.index === 0; - } - - // BACKREF_RE matches an open parenthesis or backreference. To avoid - // an incorrect parse, it additionally matches the following: - // - [...] elements, where the meaning of parentheses and escapes change - // - other escape sequences, so we do not misparse escape sequences as - // interesting elements - // - non-matching or lookahead parentheses, which do not capture. These - // follow the '(' with a '?'. - const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./; - - // **INTERNAL** Not intended for outside usage - // join logically computes regexps.join(separator), but fixes the - // backreferences so they continue to match. - // it also places each individual regular expression into it's own - // match group, keeping track of the sequencing of those match groups - // is currently an exercise for the caller. :-) - /** - * @param {(string | RegExp)[]} regexps - * @param {{joinWith: string}} opts - * @returns {string} - */ - function _rewriteBackreferences(regexps, { joinWith }) { - let numCaptures = 0; - - return regexps.map((regex) => { - numCaptures += 1; - const offset = numCaptures; - let re = source(regex); - let out = ''; - - while (re.length > 0) { - const match = BACKREF_RE.exec(re); - if (!match) { - out += re; - break; - } - out += re.substring(0, match.index); - re = re.substring(match.index + match[0].length); - if (match[0][0] === '\\' && match[1]) { - // Adjust the backreference. - out += '\\' + String(Number(match[1]) + offset); - } else { - out += match[0]; - if (match[0] === '(') { - numCaptures++; - } - } - } - return out; - }).map(re => `(${re})`).join(joinWith); - } - - /** @typedef {import('highlight.js').Mode} Mode */ - /** @typedef {import('highlight.js').ModeCallback} ModeCallback */ - - // Common regexps - const MATCH_NOTHING_RE = /\b\B/; - const IDENT_RE = '[a-zA-Z]\\w*'; - const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; - const NUMBER_RE = '\\b\\d+(\\.\\d+)?'; - const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float - const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... - const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; - - /** - * @param { Partial & {binary?: string | RegExp} } opts - */ - const SHEBANG = (opts = {}) => { - const beginShebang = /^#![ ]*\//; - if (opts.binary) { - opts.begin = concat( - beginShebang, - /.*\b/, - opts.binary, - /\b.*/); - } - return inherit$1({ - scope: 'meta', - begin: beginShebang, - end: /$/, - relevance: 0, - /** @type {ModeCallback} */ - "on:begin": (m, resp) => { - if (m.index !== 0) resp.ignoreMatch(); - } - }, opts); - }; - - // Common modes - const BACKSLASH_ESCAPE = { - begin: '\\\\[\\s\\S]', relevance: 0 - }; - const APOS_STRING_MODE = { - scope: 'string', - begin: '\'', - end: '\'', - illegal: '\\n', - contains: [BACKSLASH_ESCAPE] - }; - const QUOTE_STRING_MODE = { - scope: 'string', - begin: '"', - end: '"', - illegal: '\\n', - contains: [BACKSLASH_ESCAPE] - }; - const PHRASAL_WORDS_MODE = { - begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ - }; - /** - * Creates a comment mode - * - * @param {string | RegExp} begin - * @param {string | RegExp} end - * @param {Mode | {}} [modeOptions] - * @returns {Partial} - */ - const COMMENT = function(begin, end, modeOptions = {}) { - const mode = inherit$1( - { - scope: 'comment', - begin, - end, - contains: [] - }, - modeOptions - ); - mode.contains.push({ - scope: 'doctag', - // hack to avoid the space from being included. the space is necessary to - // match here to prevent the plain text rule below from gobbling up doctags - begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)', - end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/, - excludeBegin: true, - relevance: 0 - }); - const ENGLISH_WORD = either( - // list of common 1 and 2 letter words in English - "I", - "a", - "is", - "so", - "us", - "to", - "at", - "if", - "in", - "it", - "on", - // note: this is not an exhaustive list of contractions, just popular ones - /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc - /[A-Za-z]+[-][a-z]+/, // `no-way`, etc. - /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences - ); - // looking like plain text, more likely to be a comment - mode.contains.push( - { - // TODO: how to include ", (, ) without breaking grammars that use these for - // comment delimiters? - // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/ - // --- - - // this tries to find sequences of 3 english words in a row (without any - // "programming" type syntax) this gives us a strong signal that we've - // TRULY found a comment - vs perhaps scanning with the wrong language. - // It's possible to find something that LOOKS like the start of the - // comment - but then if there is no readable text - good chance it is a - // false match and not a comment. - // - // for a visual example please see: - // https://github.com/highlightjs/highlight.js/issues/2827 - - begin: concat( - /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */ - '(', - ENGLISH_WORD, - /[.]?[:]?([.][ ]|[ ])/, - '){3}') // look for 3 words in a row - } - ); - return mode; - }; - const C_LINE_COMMENT_MODE = COMMENT('//', '$'); - const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/'); - const HASH_COMMENT_MODE = COMMENT('#', '$'); - const NUMBER_MODE = { - scope: 'number', - begin: NUMBER_RE, - relevance: 0 - }; - const C_NUMBER_MODE = { - scope: 'number', - begin: C_NUMBER_RE, - relevance: 0 - }; - const BINARY_NUMBER_MODE = { - scope: 'number', - begin: BINARY_NUMBER_RE, - relevance: 0 - }; - const REGEXP_MODE = { - // this outer rule makes sure we actually have a WHOLE regex and not simply - // an expression such as: - // - // 3 / something - // - // (which will then blow up when regex's `illegal` sees the newline) - begin: /(?=\/[^/\n]*\/)/, - contains: [{ - scope: 'regexp', - begin: /\//, - end: /\/[gimuy]*/, - illegal: /\n/, - contains: [ - BACKSLASH_ESCAPE, - { - begin: /\[/, - end: /\]/, - relevance: 0, - contains: [BACKSLASH_ESCAPE] - } - ] - }] - }; - const TITLE_MODE = { - scope: 'title', - begin: IDENT_RE, - relevance: 0 - }; - const UNDERSCORE_TITLE_MODE = { - scope: 'title', - begin: UNDERSCORE_IDENT_RE, - relevance: 0 - }; - const METHOD_GUARD = { - // excludes method names from keyword processing - begin: '\\.\\s*' + UNDERSCORE_IDENT_RE, - relevance: 0 - }; - - /** - * Adds end same as begin mechanics to a mode - * - * Your mode must include at least a single () match group as that first match - * group is what is used for comparison - * @param {Partial} mode - */ - const END_SAME_AS_BEGIN = function(mode) { - return Object.assign(mode, - { - /** @type {ModeCallback} */ - 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; }, - /** @type {ModeCallback} */ - 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); } - }); - }; - - var MODES = /*#__PURE__*/Object.freeze({ - __proto__: null, - MATCH_NOTHING_RE: MATCH_NOTHING_RE, - IDENT_RE: IDENT_RE, - UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE, - NUMBER_RE: NUMBER_RE, - C_NUMBER_RE: C_NUMBER_RE, - BINARY_NUMBER_RE: BINARY_NUMBER_RE, - RE_STARTERS_RE: RE_STARTERS_RE, - SHEBANG: SHEBANG, - BACKSLASH_ESCAPE: BACKSLASH_ESCAPE, - APOS_STRING_MODE: APOS_STRING_MODE, - QUOTE_STRING_MODE: QUOTE_STRING_MODE, - PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE, - COMMENT: COMMENT, - C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE, - C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE, - HASH_COMMENT_MODE: HASH_COMMENT_MODE, - NUMBER_MODE: NUMBER_MODE, - C_NUMBER_MODE: C_NUMBER_MODE, - BINARY_NUMBER_MODE: BINARY_NUMBER_MODE, - REGEXP_MODE: REGEXP_MODE, - TITLE_MODE: TITLE_MODE, - UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE, - METHOD_GUARD: METHOD_GUARD, - END_SAME_AS_BEGIN: END_SAME_AS_BEGIN - }); - - /** - @typedef {import('highlight.js').CallbackResponse} CallbackResponse - @typedef {import('highlight.js').CompilerExt} CompilerExt - */ - - // Grammar extensions / plugins - // See: https://github.com/highlightjs/highlight.js/issues/2833 - - // Grammar extensions allow "syntactic sugar" to be added to the grammar modes - // without requiring any underlying changes to the compiler internals. - - // `compileMatch` being the perfect small example of now allowing a grammar - // author to write `match` when they desire to match a single expression rather - // than being forced to use `begin`. The extension then just moves `match` into - // `begin` when it runs. Ie, no features have been added, but we've just made - // the experience of writing (and reading grammars) a little bit nicer. - - // ------ - - // TODO: We need negative look-behind support to do this properly - /** - * Skip a match if it has a preceding dot - * - * This is used for `beginKeywords` to prevent matching expressions such as - * `bob.keyword.do()`. The mode compiler automatically wires this up as a - * special _internal_ 'on:begin' callback for modes with `beginKeywords` - * @param {RegExpMatchArray} match - * @param {CallbackResponse} response - */ - function skipIfHasPrecedingDot(match, response) { - const before = match.input[match.index - 1]; - if (before === ".") { - response.ignoreMatch(); - } - } - - /** - * - * @type {CompilerExt} - */ - function scopeClassName(mode, _parent) { - // eslint-disable-next-line no-undefined - if (mode.className !== undefined) { - mode.scope = mode.className; - delete mode.className; - } - } - - /** - * `beginKeywords` syntactic sugar - * @type {CompilerExt} - */ - function beginKeywords(mode, parent) { - if (!parent) return; - if (!mode.beginKeywords) return; - - // for languages with keywords that include non-word characters checking for - // a word boundary is not sufficient, so instead we check for a word boundary - // or whitespace - this does no harm in any case since our keyword engine - // doesn't allow spaces in keywords anyways and we still check for the boundary - // first - mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)'; - mode.__beforeBegin = skipIfHasPrecedingDot; - mode.keywords = mode.keywords || mode.beginKeywords; - delete mode.beginKeywords; - - // prevents double relevance, the keywords themselves provide - // relevance, the mode doesn't need to double it - // eslint-disable-next-line no-undefined - if (mode.relevance === undefined) mode.relevance = 0; - } - - /** - * Allow `illegal` to contain an array of illegal values - * @type {CompilerExt} - */ - function compileIllegal(mode, _parent) { - if (!Array.isArray(mode.illegal)) return; - - mode.illegal = either(...mode.illegal); - } - - /** - * `match` to match a single expression for readability - * @type {CompilerExt} - */ - function compileMatch(mode, _parent) { - if (!mode.match) return; - if (mode.begin || mode.end) throw new Error("begin & end are not supported with match"); - - mode.begin = mode.match; - delete mode.match; - } - - /** - * provides the default 1 relevance to all modes - * @type {CompilerExt} - */ - function compileRelevance(mode, _parent) { - // eslint-disable-next-line no-undefined - if (mode.relevance === undefined) mode.relevance = 1; - } - - // allow beforeMatch to act as a "qualifier" for the match - // the full match begin must be [beforeMatch][begin] - const beforeMatchExt = (mode, parent) => { - if (!mode.beforeMatch) return; - // starts conflicts with endsParent which we need to make sure the child - // rule is not matched multiple times - if (mode.starts) throw new Error("beforeMatch cannot be used with starts"); - - const originalMode = Object.assign({}, mode); - Object.keys(mode).forEach((key) => { delete mode[key]; }); - - mode.keywords = originalMode.keywords; - mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin)); - mode.starts = { - relevance: 0, - contains: [ - Object.assign(originalMode, { endsParent: true }) - ] - }; - mode.relevance = 0; - - delete originalMode.beforeMatch; - }; - - // keywords that should have no default relevance value - const COMMON_KEYWORDS = [ - 'of', - 'and', - 'for', - 'in', - 'not', - 'or', - 'if', - 'then', - 'parent', // common variable name - 'list', // common variable name - 'value' // common variable name - ]; - - const DEFAULT_KEYWORD_SCOPE = "keyword"; - - /** - * Given raw keywords from a language definition, compile them. - * - * @param {string | Record | Array} rawKeywords - * @param {boolean} caseInsensitive - */ - function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) { - /** @type {import("highlight.js/private").KeywordDict} */ - const compiledKeywords = Object.create(null); - - // input can be a string of keywords, an array of keywords, or a object with - // named keys representing scopeName (which can then point to a string or array) - if (typeof rawKeywords === 'string') { - compileList(scopeName, rawKeywords.split(" ")); - } else if (Array.isArray(rawKeywords)) { - compileList(scopeName, rawKeywords); - } else { - Object.keys(rawKeywords).forEach(function(scopeName) { - // collapse all our objects back into the parent object - Object.assign( - compiledKeywords, - compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName) - ); - }); - } - return compiledKeywords; - - // --- - - /** - * Compiles an individual list of keywords - * - * Ex: "for if when while|5" - * - * @param {string} scopeName - * @param {Array} keywordList - */ - function compileList(scopeName, keywordList) { - if (caseInsensitive) { - keywordList = keywordList.map(x => x.toLowerCase()); - } - keywordList.forEach(function(keyword) { - const pair = keyword.split('|'); - compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])]; - }); - } - } - - /** - * Returns the proper score for a given keyword - * - * Also takes into account comment keywords, which will be scored 0 UNLESS - * another score has been manually assigned. - * @param {string} keyword - * @param {string} [providedScore] - */ - function scoreForKeyword(keyword, providedScore) { - // manual scores always win over common keywords - // so you can force a score of 1 if you really insist - if (providedScore) { - return Number(providedScore); - } - - return commonKeyword(keyword) ? 0 : 1; - } - - /** - * Determines if a given keyword is common or not - * - * @param {string} keyword */ - function commonKeyword(keyword) { - return COMMON_KEYWORDS.includes(keyword.toLowerCase()); - } - - /* - - For the reasoning behind this please see: - https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419 - - */ - - /** - * @type {Record} - */ - const seenDeprecations = {}; - - /** - * @param {string} message - */ - const error = (message) => { - console.error(message); - }; - - /** - * @param {string} message - * @param {any} args - */ - const warn = (message, ...args) => { - console.log(`WARN: ${message}`, ...args); - }; - - /** - * @param {string} version - * @param {string} message - */ - const deprecated = (version, message) => { - if (seenDeprecations[`${version}/${message}`]) return; - - console.log(`Deprecated as of ${version}. ${message}`); - seenDeprecations[`${version}/${message}`] = true; - }; - - /* eslint-disable no-throw-literal */ - - /** - @typedef {import('highlight.js').CompiledMode} CompiledMode - */ - - const MultiClassError = new Error(); - - /** - * Renumbers labeled scope names to account for additional inner match - * groups that otherwise would break everything. - * - * Lets say we 3 match scopes: - * - * { 1 => ..., 2 => ..., 3 => ... } - * - * So what we need is a clean match like this: - * - * (a)(b)(c) => [ "a", "b", "c" ] - * - * But this falls apart with inner match groups: - * - * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ] - * - * Our scopes are now "out of alignment" and we're repeating `b` 3 times. - * What needs to happen is the numbers are remapped: - * - * { 1 => ..., 2 => ..., 5 => ... } - * - * We also need to know that the ONLY groups that should be output - * are 1, 2, and 5. This function handles this behavior. - * - * @param {CompiledMode} mode - * @param {Array} regexes - * @param {{key: "beginScope"|"endScope"}} opts - */ - function remapScopeNames(mode, regexes, { key }) { - let offset = 0; - const scopeNames = mode[key]; - /** @type Record */ - const emit = {}; - /** @type Record */ - const positions = {}; - - for (let i = 1; i <= regexes.length; i++) { - positions[i + offset] = scopeNames[i]; - emit[i + offset] = true; - offset += countMatchGroups(regexes[i - 1]); - } - // we use _emit to keep track of which match groups are "top-level" to avoid double - // output from inside match groups - mode[key] = positions; - mode[key]._emit = emit; - mode[key]._multi = true; - } - - /** - * @param {CompiledMode} mode - */ - function beginMultiClass(mode) { - if (!Array.isArray(mode.begin)) return; - - if (mode.skip || mode.excludeBegin || mode.returnBegin) { - error("skip, excludeBegin, returnBegin not compatible with beginScope: {}"); - throw MultiClassError; - } - - if (typeof mode.beginScope !== "object" || mode.beginScope === null) { - error("beginScope must be object"); - throw MultiClassError; - } - - remapScopeNames(mode, mode.begin, { key: "beginScope" }); - mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" }); - } - - /** - * @param {CompiledMode} mode - */ - function endMultiClass(mode) { - if (!Array.isArray(mode.end)) return; - - if (mode.skip || mode.excludeEnd || mode.returnEnd) { - error("skip, excludeEnd, returnEnd not compatible with endScope: {}"); - throw MultiClassError; - } - - if (typeof mode.endScope !== "object" || mode.endScope === null) { - error("endScope must be object"); - throw MultiClassError; - } - - remapScopeNames(mode, mode.end, { key: "endScope" }); - mode.end = _rewriteBackreferences(mode.end, { joinWith: "" }); - } - - /** - * this exists only to allow `scope: {}` to be used beside `match:` - * Otherwise `beginScope` would necessary and that would look weird - - { - match: [ /def/, /\w+/ ] - scope: { 1: "keyword" , 2: "title" } - } - - * @param {CompiledMode} mode - */ - function scopeSugar(mode) { - if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) { - mode.beginScope = mode.scope; - delete mode.scope; - } - } - - /** - * @param {CompiledMode} mode - */ - function MultiClass(mode) { - scopeSugar(mode); - - if (typeof mode.beginScope === "string") { - mode.beginScope = { _wrap: mode.beginScope }; - } - if (typeof mode.endScope === "string") { - mode.endScope = { _wrap: mode.endScope }; - } - - beginMultiClass(mode); - endMultiClass(mode); - } - - /** - @typedef {import('highlight.js').Mode} Mode - @typedef {import('highlight.js').CompiledMode} CompiledMode - @typedef {import('highlight.js').Language} Language - @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin - @typedef {import('highlight.js').CompiledLanguage} CompiledLanguage - */ - - // compilation - - /** - * Compiles a language definition result - * - * Given the raw result of a language definition (Language), compiles this so - * that it is ready for highlighting code. - * @param {Language} language - * @returns {CompiledLanguage} - */ - function compileLanguage(language) { - /** - * Builds a regex with the case sensitivity of the current language - * - * @param {RegExp | string} value - * @param {boolean} [global] - */ - function langRe(value, global) { - return new RegExp( - source(value), - 'm' - + (language.case_insensitive ? 'i' : '') - + (language.unicodeRegex ? 'u' : '') - + (global ? 'g' : '') - ); - } - - /** - Stores multiple regular expressions and allows you to quickly search for - them all in a string simultaneously - returning the first match. It does - this by creating a huge (a|b|c) regex - each individual item wrapped with () - and joined by `|` - using match groups to track position. When a match is - found checking which position in the array has content allows us to figure - out which of the original regexes / match groups triggered the match. - - The match object itself (the result of `Regex.exec`) is returned but also - enhanced by merging in any meta-data that was registered with the regex. - This is how we keep track of which mode matched, and what type of rule - (`illegal`, `begin`, end, etc). - */ - class MultiRegex { - constructor() { - this.matchIndexes = {}; - // @ts-ignore - this.regexes = []; - this.matchAt = 1; - this.position = 0; - } - - // @ts-ignore - addRule(re, opts) { - opts.position = this.position++; - // @ts-ignore - this.matchIndexes[this.matchAt] = opts; - this.regexes.push([opts, re]); - this.matchAt += countMatchGroups(re) + 1; - } - - compile() { - if (this.regexes.length === 0) { - // avoids the need to check length every time exec is called - // @ts-ignore - this.exec = () => null; - } - const terminators = this.regexes.map(el => el[1]); - this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true); - this.lastIndex = 0; - } - - /** @param {string} s */ - exec(s) { - this.matcherRe.lastIndex = this.lastIndex; - const match = this.matcherRe.exec(s); - if (!match) { return null; } - - // eslint-disable-next-line no-undefined - const i = match.findIndex((el, i) => i > 0 && el !== undefined); - // @ts-ignore - const matchData = this.matchIndexes[i]; - // trim off any earlier non-relevant match groups (ie, the other regex - // match groups that make up the multi-matcher) - match.splice(0, i); - - return Object.assign(match, matchData); - } - } - - /* - Created to solve the key deficiently with MultiRegex - there is no way to - test for multiple matches at a single location. Why would we need to do - that? In the future a more dynamic engine will allow certain matches to be - ignored. An example: if we matched say the 3rd regex in a large group but - decided to ignore it - we'd need to started testing again at the 4th - regex... but MultiRegex itself gives us no real way to do that. - - So what this class creates MultiRegexs on the fly for whatever search - position they are needed. - - NOTE: These additional MultiRegex objects are created dynamically. For most - grammars most of the time we will never actually need anything more than the - first MultiRegex - so this shouldn't have too much overhead. - - Say this is our search group, and we match regex3, but wish to ignore it. - - regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0 - - What we need is a new MultiRegex that only includes the remaining - possibilities: - - regex4 | regex5 ' ie, startAt = 3 - - This class wraps all that complexity up in a simple API... `startAt` decides - where in the array of expressions to start doing the matching. It - auto-increments, so if a match is found at position 2, then startAt will be - set to 3. If the end is reached startAt will return to 0. - - MOST of the time the parser will be setting startAt manually to 0. - */ - class ResumableMultiRegex { - constructor() { - // @ts-ignore - this.rules = []; - // @ts-ignore - this.multiRegexes = []; - this.count = 0; - - this.lastIndex = 0; - this.regexIndex = 0; - } - - // @ts-ignore - getMatcher(index) { - if (this.multiRegexes[index]) return this.multiRegexes[index]; - - const matcher = new MultiRegex(); - this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts)); - matcher.compile(); - this.multiRegexes[index] = matcher; - return matcher; - } - - resumingScanAtSamePosition() { - return this.regexIndex !== 0; - } - - considerAll() { - this.regexIndex = 0; - } - - // @ts-ignore - addRule(re, opts) { - this.rules.push([re, opts]); - if (opts.type === "begin") this.count++; - } - - /** @param {string} s */ - exec(s) { - const m = this.getMatcher(this.regexIndex); - m.lastIndex = this.lastIndex; - let result = m.exec(s); - - // The following is because we have no easy way to say "resume scanning at the - // existing position but also skip the current rule ONLY". What happens is - // all prior rules are also skipped which can result in matching the wrong - // thing. Example of matching "booger": - - // our matcher is [string, "booger", number] - // - // ....booger.... - - // if "booger" is ignored then we'd really need a regex to scan from the - // SAME position for only: [string, number] but ignoring "booger" (if it - // was the first match), a simple resume would scan ahead who knows how - // far looking only for "number", ignoring potential string matches (or - // future "booger" matches that might be valid.) - - // So what we do: We execute two matchers, one resuming at the same - // position, but the second full matcher starting at the position after: - - // /--- resume first regex match here (for [number]) - // |/---- full match here for [string, "booger", number] - // vv - // ....booger.... - - // Which ever results in a match first is then used. So this 3-4 step - // process essentially allows us to say "match at this position, excluding - // a prior rule that was ignored". - // - // 1. Match "booger" first, ignore. Also proves that [string] does non match. - // 2. Resume matching for [number] - // 3. Match at index + 1 for [string, "booger", number] - // 4. If #2 and #3 result in matches, which came first? - if (this.resumingScanAtSamePosition()) { - if (result && result.index === this.lastIndex) ; else { // use the second matcher result - const m2 = this.getMatcher(0); - m2.lastIndex = this.lastIndex + 1; - result = m2.exec(s); - } - } - - if (result) { - this.regexIndex += result.position + 1; - if (this.regexIndex === this.count) { - // wrap-around to considering all matches again - this.considerAll(); - } - } - - return result; - } - } - - /** - * Given a mode, builds a huge ResumableMultiRegex that can be used to walk - * the content and find matches. - * - * @param {CompiledMode} mode - * @returns {ResumableMultiRegex} - */ - function buildModeRegex(mode) { - const mm = new ResumableMultiRegex(); - - mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" })); - - if (mode.terminatorEnd) { - mm.addRule(mode.terminatorEnd, { type: "end" }); - } - if (mode.illegal) { - mm.addRule(mode.illegal, { type: "illegal" }); - } - - return mm; - } - - /** skip vs abort vs ignore - * - * @skip - The mode is still entered and exited normally (and contains rules apply), - * but all content is held and added to the parent buffer rather than being - * output when the mode ends. Mostly used with `sublanguage` to build up - * a single large buffer than can be parsed by sublanguage. - * - * - The mode begin ands ends normally. - * - Content matched is added to the parent mode buffer. - * - The parser cursor is moved forward normally. - * - * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it - * never matched) but DOES NOT continue to match subsequent `contains` - * modes. Abort is bad/suboptimal because it can result in modes - * farther down not getting applied because an earlier rule eats the - * content but then aborts. - * - * - The mode does not begin. - * - Content matched by `begin` is added to the mode buffer. - * - The parser cursor is moved forward accordingly. - * - * @ignore - Ignores the mode (as if it never matched) and continues to match any - * subsequent `contains` modes. Ignore isn't technically possible with - * the current parser implementation. - * - * - The mode does not begin. - * - Content matched by `begin` is ignored. - * - The parser cursor is not moved forward. - */ - - /** - * Compiles an individual mode - * - * This can raise an error if the mode contains certain detectable known logic - * issues. - * @param {Mode} mode - * @param {CompiledMode | null} [parent] - * @returns {CompiledMode | never} - */ - function compileMode(mode, parent) { - const cmode = /** @type CompiledMode */ (mode); - if (mode.isCompiled) return cmode; - - [ - scopeClassName, - // do this early so compiler extensions generally don't have to worry about - // the distinction between match/begin - compileMatch, - MultiClass, - beforeMatchExt - ].forEach(ext => ext(mode, parent)); - - language.compilerExtensions.forEach(ext => ext(mode, parent)); - - // __beforeBegin is considered private API, internal use only - mode.__beforeBegin = null; - - [ - beginKeywords, - // do this later so compiler extensions that come earlier have access to the - // raw array if they wanted to perhaps manipulate it, etc. - compileIllegal, - // default to 1 relevance if not specified - compileRelevance - ].forEach(ext => ext(mode, parent)); - - mode.isCompiled = true; - - let keywordPattern = null; - if (typeof mode.keywords === "object" && mode.keywords.$pattern) { - // we need a copy because keywords might be compiled multiple times - // so we can't go deleting $pattern from the original on the first - // pass - mode.keywords = Object.assign({}, mode.keywords); - keywordPattern = mode.keywords.$pattern; - delete mode.keywords.$pattern; - } - keywordPattern = keywordPattern || /\w+/; - - if (mode.keywords) { - mode.keywords = compileKeywords(mode.keywords, language.case_insensitive); - } - - cmode.keywordPatternRe = langRe(keywordPattern, true); - - if (parent) { - if (!mode.begin) mode.begin = /\B|\b/; - cmode.beginRe = langRe(cmode.begin); - if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/; - if (mode.end) cmode.endRe = langRe(cmode.end); - cmode.terminatorEnd = source(cmode.end) || ''; - if (mode.endsWithParent && parent.terminatorEnd) { - cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd; - } - } - if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal)); - if (!mode.contains) mode.contains = []; - - mode.contains = [].concat(...mode.contains.map(function(c) { - return expandOrCloneMode(c === 'self' ? mode : c); - })); - mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); }); - - if (mode.starts) { - compileMode(mode.starts, parent); - } - - cmode.matcher = buildModeRegex(cmode); - return cmode; - } - - if (!language.compilerExtensions) language.compilerExtensions = []; - - // self is not valid at the top-level - if (language.contains && language.contains.includes('self')) { - throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation."); - } - - // we need a null object, which inherit will guarantee - language.classNameAliases = inherit$1(language.classNameAliases || {}); - - return compileMode(/** @type Mode */ (language)); - } - - /** - * Determines if a mode has a dependency on it's parent or not - * - * If a mode does have a parent dependency then often we need to clone it if - * it's used in multiple places so that each copy points to the correct parent, - * where-as modes without a parent can often safely be re-used at the bottom of - * a mode chain. - * - * @param {Mode | null} mode - * @returns {boolean} - is there a dependency on the parent? - * */ - function dependencyOnParent(mode) { - if (!mode) return false; - - return mode.endsWithParent || dependencyOnParent(mode.starts); - } - - /** - * Expands a mode or clones it if necessary - * - * This is necessary for modes with parental dependenceis (see notes on - * `dependencyOnParent`) and for nodes that have `variants` - which must then be - * exploded into their own individual modes at compile time. - * - * @param {Mode} mode - * @returns {Mode | Mode[]} - * */ - function expandOrCloneMode(mode) { - if (mode.variants && !mode.cachedVariants) { - mode.cachedVariants = mode.variants.map(function(variant) { - return inherit$1(mode, { variants: null }, variant); - }); - } - - // EXPAND - // if we have variants then essentially "replace" the mode with the variants - // this happens in compileMode, where this function is called from - if (mode.cachedVariants) { - return mode.cachedVariants; - } - - // CLONE - // if we have dependencies on parents then we need a unique - // instance of ourselves, so we can be reused with many - // different parents without issue - if (dependencyOnParent(mode)) { - return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null }); - } - - if (Object.isFrozen(mode)) { - return inherit$1(mode); - } - - // no special dependency issues, just return ourselves - return mode; - } - - var version = "11.7.0"; - - class HTMLInjectionError extends Error { - constructor(reason, html) { - super(reason); - this.name = "HTMLInjectionError"; - this.html = html; - } - } - - /* - Syntax highlighting with language autodetection. - https://highlightjs.org/ - */ - - /** - @typedef {import('highlight.js').Mode} Mode - @typedef {import('highlight.js').CompiledMode} CompiledMode - @typedef {import('highlight.js').CompiledScope} CompiledScope - @typedef {import('highlight.js').Language} Language - @typedef {import('highlight.js').HLJSApi} HLJSApi - @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin - @typedef {import('highlight.js').PluginEvent} PluginEvent - @typedef {import('highlight.js').HLJSOptions} HLJSOptions - @typedef {import('highlight.js').LanguageFn} LanguageFn - @typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement - @typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext - @typedef {import('highlight.js/private').MatchType} MatchType - @typedef {import('highlight.js/private').KeywordData} KeywordData - @typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch - @typedef {import('highlight.js/private').AnnotatedError} AnnotatedError - @typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult - @typedef {import('highlight.js').HighlightOptions} HighlightOptions - @typedef {import('highlight.js').HighlightResult} HighlightResult - */ - - - const escape = escapeHTML; - const inherit = inherit$1; - const NO_MATCH = Symbol("nomatch"); - const MAX_KEYWORD_HITS = 7; - - /** - * @param {any} hljs - object that is extended (legacy) - * @returns {HLJSApi} - */ - const HLJS = function(hljs) { - // Global internal variables used within the highlight.js library. - /** @type {Record} */ - const languages = Object.create(null); - /** @type {Record} */ - const aliases = Object.create(null); - /** @type {HLJSPlugin[]} */ - const plugins = []; - - // safe/production mode - swallows more errors, tries to keep running - // even if a single syntax or parse hits a fatal error - let SAFE_MODE = true; - const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?"; - /** @type {Language} */ - const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] }; - - // Global options used when within external APIs. This is modified when - // calling the `hljs.configure` function. - /** @type HLJSOptions */ - let options = { - ignoreUnescapedHTML: false, - throwUnescapedHTML: false, - noHighlightRe: /^(no-?highlight)$/i, - languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i, - classPrefix: 'hljs-', - cssSelector: 'pre code', - languages: null, - // beta configuration options, subject to change, welcome to discuss - // https://github.com/highlightjs/highlight.js/issues/1086 - __emitter: TokenTreeEmitter - }; - - /* Utility functions */ - - /** - * Tests a language name to see if highlighting should be skipped - * @param {string} languageName - */ - function shouldNotHighlight(languageName) { - return options.noHighlightRe.test(languageName); - } - - /** - * @param {HighlightedHTMLElement} block - the HTML element to determine language for - */ - function blockLanguage(block) { - let classes = block.className + ' '; - - classes += block.parentNode ? block.parentNode.className : ''; - - // language-* takes precedence over non-prefixed class names. - const match = options.languageDetectRe.exec(classes); - if (match) { - const language = getLanguage(match[1]); - if (!language) { - warn(LANGUAGE_NOT_FOUND.replace("{}", match[1])); - warn("Falling back to no-highlight mode for this block.", block); - } - return language ? match[1] : 'no-highlight'; - } - - return classes - .split(/\s+/) - .find((_class) => shouldNotHighlight(_class) || getLanguage(_class)); - } - - /** - * Core highlighting function. - * - * OLD API - * highlight(lang, code, ignoreIllegals, continuation) - * - * NEW API - * highlight(code, {lang, ignoreIllegals}) - * - * @param {string} codeOrLanguageName - the language to use for highlighting - * @param {string | HighlightOptions} optionsOrCode - the code to highlight - * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail - * - * @returns {HighlightResult} Result - an object that represents the result - * @property {string} language - the language name - * @property {number} relevance - the relevance score - * @property {string} value - the highlighted HTML code - * @property {string} code - the original raw code - * @property {CompiledMode} top - top of the current mode stack - * @property {boolean} illegal - indicates whether any illegal matches were found - */ - function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) { - let code = ""; - let languageName = ""; - if (typeof optionsOrCode === "object") { - code = codeOrLanguageName; - ignoreIllegals = optionsOrCode.ignoreIllegals; - languageName = optionsOrCode.language; - } else { - // old API - deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated."); - deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"); - languageName = codeOrLanguageName; - code = optionsOrCode; - } - - // https://github.com/highlightjs/highlight.js/issues/3149 - // eslint-disable-next-line no-undefined - if (ignoreIllegals === undefined) { ignoreIllegals = true; } - - /** @type {BeforeHighlightContext} */ - const context = { - code, - language: languageName - }; - // the plugin can change the desired language or the code to be highlighted - // just be changing the object it was passed - fire("before:highlight", context); - - // a before plugin can usurp the result completely by providing it's own - // in which case we don't even need to call highlight - const result = context.result - ? context.result - : _highlight(context.language, context.code, ignoreIllegals); - - result.code = context.code; - // the plugin can change anything in result to suite it - fire("after:highlight", result); - - return result; - } - - /** - * private highlight that's used internally and does not fire callbacks - * - * @param {string} languageName - the language to use for highlighting - * @param {string} codeToHighlight - the code to highlight - * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail - * @param {CompiledMode?} [continuation] - current continuation mode, if any - * @returns {HighlightResult} - result of the highlight operation - */ - function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) { - const keywordHits = Object.create(null); - - /** - * Return keyword data if a match is a keyword - * @param {CompiledMode} mode - current mode - * @param {string} matchText - the textual match - * @returns {KeywordData | false} - */ - function keywordData(mode, matchText) { - return mode.keywords[matchText]; - } - - function processKeywords() { - if (!top.keywords) { - emitter.addText(modeBuffer); - return; - } - - let lastIndex = 0; - top.keywordPatternRe.lastIndex = 0; - let match = top.keywordPatternRe.exec(modeBuffer); - let buf = ""; - - while (match) { - buf += modeBuffer.substring(lastIndex, match.index); - const word = language.case_insensitive ? match[0].toLowerCase() : match[0]; - const data = keywordData(top, word); - if (data) { - const [kind, keywordRelevance] = data; - emitter.addText(buf); - buf = ""; - - keywordHits[word] = (keywordHits[word] || 0) + 1; - if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance; - if (kind.startsWith("_")) { - // _ implied for relevance only, do not highlight - // by applying a class name - buf += match[0]; - } else { - const cssClass = language.classNameAliases[kind] || kind; - emitter.addKeyword(match[0], cssClass); - } - } else { - buf += match[0]; - } - lastIndex = top.keywordPatternRe.lastIndex; - match = top.keywordPatternRe.exec(modeBuffer); - } - buf += modeBuffer.substring(lastIndex); - emitter.addText(buf); - } - - function processSubLanguage() { - if (modeBuffer === "") return; - /** @type HighlightResult */ - let result = null; - - if (typeof top.subLanguage === 'string') { - if (!languages[top.subLanguage]) { - emitter.addText(modeBuffer); - return; - } - result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]); - continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top); - } else { - result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null); - } - - // Counting embedded language score towards the host language may be disabled - // with zeroing the containing mode relevance. Use case in point is Markdown that - // allows XML everywhere and makes every XML snippet to have a much larger Markdown - // score. - if (top.relevance > 0) { - relevance += result.relevance; - } - emitter.addSublanguage(result._emitter, result.language); - } - - function processBuffer() { - if (top.subLanguage != null) { - processSubLanguage(); + function emitMultiClass(scope, match) { + let i = 1; + const max = match.length - 1; + while (i <= max) { + if (!scope._emit[i]) { i++; continue; } + const klass = language.classNameAliases[scope[i]] || scope[i]; + const text = match[i]; + if (klass) { + emitKeyword(text, klass); } else { + modeBuffer = text; processKeywords(); + modeBuffer = ""; } - modeBuffer = ''; + i++; } + } - /** - * @param {CompiledScope} scope - * @param {RegExpMatchArray} match - */ - function emitMultiClass(scope, match) { - let i = 1; - const max = match.length - 1; - while (i <= max) { - if (!scope._emit[i]) { i++; continue; } - const klass = language.classNameAliases[scope[i]] || scope[i]; - const text = match[i]; - if (klass) { - emitter.addKeyword(text, klass); - } else { - modeBuffer = text; - processKeywords(); - modeBuffer = ""; - } - i++; + /** + * @param {CompiledMode} mode - new mode to start + * @param {RegExpMatchArray} match + */ + function startNewMode(mode, match) { + if (mode.scope && typeof mode.scope === "string") { + emitter.openNode(language.classNameAliases[mode.scope] || mode.scope); + } + if (mode.beginScope) { + // beginScope just wraps the begin match itself in a scope + if (mode.beginScope._wrap) { + emitKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap); + modeBuffer = ""; + } else if (mode.beginScope._multi) { + // at this point modeBuffer should just be the match + emitMultiClass(mode.beginScope, match); + modeBuffer = ""; } } - /** - * @param {CompiledMode} mode - new mode to start - * @param {RegExpMatchArray} match - */ - function startNewMode(mode, match) { - if (mode.scope && typeof mode.scope === "string") { - emitter.openNode(language.classNameAliases[mode.scope] || mode.scope); - } - if (mode.beginScope) { - // beginScope just wraps the begin match itself in a scope - if (mode.beginScope._wrap) { - emitter.addKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap); - modeBuffer = ""; - } else if (mode.beginScope._multi) { - // at this point modeBuffer should just be the match - emitMultiClass(mode.beginScope, match); - modeBuffer = ""; - } - } + top = Object.create(mode, { parent: { value: top } }); + return top; + } - top = Object.create(mode, { parent: { value: top } }); - return top; - } + /** + * @param {CompiledMode } mode - the mode to potentially end + * @param {RegExpMatchArray} match - the latest match + * @param {string} matchPlusRemainder - match plus remainder of content + * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode + */ + function endOfMode(mode, match, matchPlusRemainder) { + let matched = startsWith(mode.endRe, matchPlusRemainder); - /** - * @param {CompiledMode } mode - the mode to potentially end - * @param {RegExpMatchArray} match - the latest match - * @param {string} matchPlusRemainder - match plus remainder of content - * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode - */ - function endOfMode(mode, match, matchPlusRemainder) { - let matched = startsWith(mode.endRe, matchPlusRemainder); + if (matched) { + if (mode["on:end"]) { + const resp = new Response(mode); + mode["on:end"](match, resp); + if (resp.isMatchIgnored) matched = false; + } if (matched) { - if (mode["on:end"]) { - const resp = new Response(mode); - mode["on:end"](match, resp); - if (resp.isMatchIgnored) matched = false; + while (mode.endsParent && mode.parent) { + mode = mode.parent; } - - if (matched) { - while (mode.endsParent && mode.parent) { - mode = mode.parent; - } - return mode; - } - } - // even if on:end fires an `ignore` it's still possible - // that we might trigger the end node because of a parent mode - if (mode.endsWithParent) { - return endOfMode(mode.parent, match, matchPlusRemainder); + return mode; } } + // even if on:end fires an `ignore` it's still possible + // that we might trigger the end node because of a parent mode + if (mode.endsWithParent) { + return endOfMode(mode.parent, match, matchPlusRemainder); + } + } - /** - * Handle matching but then ignoring a sequence of text - * - * @param {string} lexeme - string containing full match text - */ - function doIgnore(lexeme) { - if (top.matcher.regexIndex === 0) { - // no more regexes to potentially match here, so we move the cursor forward one - // space - modeBuffer += lexeme[0]; - return 1; - } else { - // no need to move the cursor, we still have additional regexes to try and - // match at this very spot - resumeScanAtSamePosition = true; - return 0; - } + /** + * Handle matching but then ignoring a sequence of text + * + * @param {string} lexeme - string containing full match text + */ + function doIgnore(lexeme) { + if (top.matcher.regexIndex === 0) { + // no more regexes to potentially match here, so we move the cursor forward one + // space + modeBuffer += lexeme[0]; + return 1; + } else { + // no need to move the cursor, we still have additional regexes to try and + // match at this very spot + resumeScanAtSamePosition = true; + return 0; + } + } + + /** + * Handle the start of a new potential mode match + * + * @param {EnhancedMatch} match - the current match + * @returns {number} how far to advance the parse cursor + */ + function doBeginMatch(match) { + const lexeme = match[0]; + const newMode = match.rule; + + const resp = new Response(newMode); + // first internal before callbacks, then the public ones + const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]]; + for (const cb of beforeCallbacks) { + if (!cb) continue; + cb(match, resp); + if (resp.isMatchIgnored) return doIgnore(lexeme); } - /** - * Handle the start of a new potential mode match - * - * @param {EnhancedMatch} match - the current match - * @returns {number} how far to advance the parse cursor - */ - function doBeginMatch(match) { - const lexeme = match[0]; - const newMode = match.rule; - - const resp = new Response(newMode); - // first internal before callbacks, then the public ones - const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]]; - for (const cb of beforeCallbacks) { - if (!cb) continue; - cb(match, resp); - if (resp.isMatchIgnored) return doIgnore(lexeme); - } - - if (newMode.skip) { - modeBuffer += lexeme; - } else { - if (newMode.excludeBegin) { - modeBuffer += lexeme; - } - processBuffer(); - if (!newMode.returnBegin && !newMode.excludeBegin) { - modeBuffer = lexeme; - } - } - startNewMode(newMode, match); - return newMode.returnBegin ? 0 : lexeme.length; - } - - /** - * Handle the potential end of mode - * - * @param {RegExpMatchArray} match - the current match - */ - function doEndMatch(match) { - const lexeme = match[0]; - const matchPlusRemainder = codeToHighlight.substring(match.index); - - const endMode = endOfMode(top, match, matchPlusRemainder); - if (!endMode) { return NO_MATCH; } - - const origin = top; - if (top.endScope && top.endScope._wrap) { - processBuffer(); - emitter.addKeyword(lexeme, top.endScope._wrap); - } else if (top.endScope && top.endScope._multi) { - processBuffer(); - emitMultiClass(top.endScope, match); - } else if (origin.skip) { - modeBuffer += lexeme; - } else { - if (!(origin.returnEnd || origin.excludeEnd)) { - modeBuffer += lexeme; - } - processBuffer(); - if (origin.excludeEnd) { - modeBuffer = lexeme; - } - } - do { - if (top.scope) { - emitter.closeNode(); - } - if (!top.skip && !top.subLanguage) { - relevance += top.relevance; - } - top = top.parent; - } while (top !== endMode.parent); - if (endMode.starts) { - startNewMode(endMode.starts, match); - } - return origin.returnEnd ? 0 : lexeme.length; - } - - function processContinuations() { - const list = []; - for (let current = top; current !== language; current = current.parent) { - if (current.scope) { - list.unshift(current.scope); - } - } - list.forEach(item => emitter.openNode(item)); - } - - /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */ - let lastMatch = {}; - - /** - * Process an individual match - * - * @param {string} textBeforeMatch - text preceding the match (since the last match) - * @param {EnhancedMatch} [match] - the match itself - */ - function processLexeme(textBeforeMatch, match) { - const lexeme = match && match[0]; - - // add non-matched text to the current mode buffer - modeBuffer += textBeforeMatch; - - if (lexeme == null) { - processBuffer(); - return 0; - } - - // we've found a 0 width match and we're stuck, so we need to advance - // this happens when we have badly behaved rules that have optional matchers to the degree that - // sometimes they can end up matching nothing at all - // Ref: https://github.com/highlightjs/highlight.js/issues/2140 - if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") { - // spit the "skipped" character that our regex choked on back into the output sequence - modeBuffer += codeToHighlight.slice(match.index, match.index + 1); - if (!SAFE_MODE) { - /** @type {AnnotatedError} */ - const err = new Error(`0 width match regex (${languageName})`); - err.languageName = languageName; - err.badRule = lastMatch.rule; - throw err; - } - return 1; - } - lastMatch = match; - - if (match.type === "begin") { - return doBeginMatch(match); - } else if (match.type === "illegal" && !ignoreIllegals) { - // illegal match, we do not continue processing - /** @type {AnnotatedError} */ - const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '') + '"'); - err.mode = top; - throw err; - } else if (match.type === "end") { - const processed = doEndMatch(match); - if (processed !== NO_MATCH) { - return processed; - } - } - - // edge case for when illegal matches $ (end of line) which is technically - // a 0 width match but not a begin/end match so it's not caught by the - // first handler (when ignoreIllegals is true) - if (match.type === "illegal" && lexeme === "") { - // advance so we aren't stuck in an infinite loop - return 1; - } - - // infinite loops are BAD, this is a last ditch catch all. if we have a - // decent number of iterations yet our index (cursor position in our - // parsing) still 3x behind our index then something is very wrong - // so we bail - if (iterations > 100000 && iterations > match.index * 3) { - const err = new Error('potential infinite loop, way more iterations than matches'); - throw err; - } - - /* - Why might be find ourselves here? An potential end match that was - triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH. - (this could be because a callback requests the match be ignored, etc) - - This causes no real harm other than stopping a few times too many. - */ - + if (newMode.skip) { modeBuffer += lexeme; - return lexeme.length; + } else { + if (newMode.excludeBegin) { + modeBuffer += lexeme; + } + processBuffer(); + if (!newMode.returnBegin && !newMode.excludeBegin) { + modeBuffer = lexeme; + } + } + startNewMode(newMode, match); + return newMode.returnBegin ? 0 : lexeme.length; + } + + /** + * Handle the potential end of mode + * + * @param {RegExpMatchArray} match - the current match + */ + function doEndMatch(match) { + const lexeme = match[0]; + const matchPlusRemainder = codeToHighlight.substring(match.index); + + const endMode = endOfMode(top, match, matchPlusRemainder); + if (!endMode) { return NO_MATCH; } + + const origin = top; + if (top.endScope && top.endScope._wrap) { + processBuffer(); + emitKeyword(lexeme, top.endScope._wrap); + } else if (top.endScope && top.endScope._multi) { + processBuffer(); + emitMultiClass(top.endScope, match); + } else if (origin.skip) { + modeBuffer += lexeme; + } else { + if (!(origin.returnEnd || origin.excludeEnd)) { + modeBuffer += lexeme; + } + processBuffer(); + if (origin.excludeEnd) { + modeBuffer = lexeme; + } + } + do { + if (top.scope) { + emitter.closeNode(); + } + if (!top.skip && !top.subLanguage) { + relevance += top.relevance; + } + top = top.parent; + } while (top !== endMode.parent); + if (endMode.starts) { + startNewMode(endMode.starts, match); + } + return origin.returnEnd ? 0 : lexeme.length; + } + + function processContinuations() { + const list = []; + for (let current = top; current !== language; current = current.parent) { + if (current.scope) { + list.unshift(current.scope); + } + } + list.forEach(item => emitter.openNode(item)); + } + + /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */ + let lastMatch = {}; + + /** + * Process an individual match + * + * @param {string} textBeforeMatch - text preceding the match (since the last match) + * @param {EnhancedMatch} [match] - the match itself + */ + function processLexeme(textBeforeMatch, match) { + const lexeme = match && match[0]; + + // add non-matched text to the current mode buffer + modeBuffer += textBeforeMatch; + + if (lexeme == null) { + processBuffer(); + return 0; } - const language = getLanguage(languageName); - if (!language) { - error(LANGUAGE_NOT_FOUND.replace("{}", languageName)); - throw new Error('Unknown language: "' + languageName + '"'); + // we've found a 0 width match and we're stuck, so we need to advance + // this happens when we have badly behaved rules that have optional matchers to the degree that + // sometimes they can end up matching nothing at all + // Ref: https://github.com/highlightjs/highlight.js/issues/2140 + if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") { + // spit the "skipped" character that our regex choked on back into the output sequence + modeBuffer += codeToHighlight.slice(match.index, match.index + 1); + if (!SAFE_MODE) { + /** @type {AnnotatedError} */ + const err = new Error(`0 width match regex (${languageName})`); + err.languageName = languageName; + err.badRule = lastMatch.rule; + throw err; + } + return 1; + } + lastMatch = match; + + if (match.type === "begin") { + return doBeginMatch(match); + } else if (match.type === "illegal" && !ignoreIllegals) { + // illegal match, we do not continue processing + /** @type {AnnotatedError} */ + const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '') + '"'); + err.mode = top; + throw err; + } else if (match.type === "end") { + const processed = doEndMatch(match); + if (processed !== NO_MATCH) { + return processed; + } } - const md = compileLanguage(language); - let result = ''; - /** @type {CompiledMode} */ - let top = continuation || md; - /** @type Record */ - const continuations = {}; // keep continuations for sub-languages - const emitter = new options.__emitter(options); - processContinuations(); - let modeBuffer = ''; - let relevance = 0; - let index = 0; - let iterations = 0; - let resumeScanAtSamePosition = false; + // edge case for when illegal matches $ (end of line) which is technically + // a 0 width match but not a begin/end match so it's not caught by the + // first handler (when ignoreIllegals is true) + if (match.type === "illegal" && lexeme === "") { + // advance so we aren't stuck in an infinite loop + return 1; + } - try { + // infinite loops are BAD, this is a last ditch catch all. if we have a + // decent number of iterations yet our index (cursor position in our + // parsing) still 3x behind our index then something is very wrong + // so we bail + if (iterations > 100000 && iterations > match.index * 3) { + const err = new Error('potential infinite loop, way more iterations than matches'); + throw err; + } + + /* + Why might be find ourselves here? An potential end match that was + triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH. + (this could be because a callback requests the match be ignored, etc) + + This causes no real harm other than stopping a few times too many. + */ + + modeBuffer += lexeme; + return lexeme.length; + } + + const language = getLanguage(languageName); + if (!language) { + error(LANGUAGE_NOT_FOUND.replace("{}", languageName)); + throw new Error('Unknown language: "' + languageName + '"'); + } + + const md = compileLanguage(language); + let result = ''; + /** @type {CompiledMode} */ + let top = continuation || md; + /** @type Record */ + const continuations = {}; // keep continuations for sub-languages + const emitter = new options.__emitter(options); + processContinuations(); + let modeBuffer = ''; + let relevance = 0; + let index = 0; + let iterations = 0; + let resumeScanAtSamePosition = false; + + try { + if (!language.__emitTokens) { top.matcher.considerAll(); for (;;) { @@ -2147,429 +2154,2880 @@ var hljs = (function () { index = match.index + processedCount; } processLexeme(codeToHighlight.substring(index)); - emitter.closeAllNodes(); - emitter.finalize(); - result = emitter.toHTML(); + } else { + language.__emitTokens(codeToHighlight, emitter); + } + emitter.finalize(); + result = emitter.toHTML(); + + return { + language: languageName, + value: result, + relevance, + illegal: false, + _emitter: emitter, + _top: top + }; + } catch (err) { + if (err.message && err.message.includes('Illegal')) { return { language: languageName, - value: result, - relevance: relevance, + value: escape(codeToHighlight), + illegal: true, + relevance: 0, + _illegalBy: { + message: err.message, + index, + context: codeToHighlight.slice(index - 100, index + 100), + mode: err.mode, + resultSoFar: result + }, + _emitter: emitter + }; + } else if (SAFE_MODE) { + return { + language: languageName, + value: escape(codeToHighlight), illegal: false, + relevance: 0, + errorRaised: err, _emitter: emitter, _top: top }; - } catch (err) { - if (err.message && err.message.includes('Illegal')) { - return { - language: languageName, - value: escape(codeToHighlight), - illegal: true, - relevance: 0, - _illegalBy: { - message: err.message, - index: index, - context: codeToHighlight.slice(index - 100, index + 100), - mode: err.mode, - resultSoFar: result - }, - _emitter: emitter - }; - } else if (SAFE_MODE) { - return { - language: languageName, - value: escape(codeToHighlight), - illegal: false, - relevance: 0, - errorRaised: err, - _emitter: emitter, - _top: top - }; - } else { - throw err; - } + } else { + throw err; } } + } - /** - * returns a valid highlight result, without actually doing any actual work, - * auto highlight starts with this and it's possible for small snippets that - * auto-detection may not find a better match - * @param {string} code - * @returns {HighlightResult} - */ - function justTextHighlightResult(code) { - const result = { - value: escape(code), - illegal: false, - relevance: 0, - _top: PLAINTEXT_LANGUAGE, - _emitter: new options.__emitter(options) - }; - result._emitter.addText(code); - return result; - } - - /** - Highlighting with language detection. Accepts a string with the code to - highlight. Returns an object with the following properties: - - - language (detected language) - - relevance (int) - - value (an HTML string with highlighting markup) - - secondBest (object with the same structure for second-best heuristically - detected language, may be absent) - - @param {string} code - @param {Array} [languageSubset] - @returns {AutoHighlightResult} - */ - function highlightAuto(code, languageSubset) { - languageSubset = languageSubset || options.languages || Object.keys(languages); - const plaintext = justTextHighlightResult(code); - - const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name => - _highlight(name, code, false) - ); - results.unshift(plaintext); // plaintext is always an option - - const sorted = results.sort((a, b) => { - // sort base on relevance - if (a.relevance !== b.relevance) return b.relevance - a.relevance; - - // always award the tie to the base language - // ie if C++ and Arduino are tied, it's more likely to be C++ - if (a.language && b.language) { - if (getLanguage(a.language).supersetOf === b.language) { - return 1; - } else if (getLanguage(b.language).supersetOf === a.language) { - return -1; - } - } - - // otherwise say they are equal, which has the effect of sorting on - // relevance while preserving the original ordering - which is how ties - // have historically been settled, ie the language that comes first always - // wins in the case of a tie - return 0; - }); - - const [best, secondBest] = sorted; - - /** @type {AutoHighlightResult} */ - const result = best; - result.secondBest = secondBest; - - return result; - } - - /** - * Builds new class name for block given the language name - * - * @param {HTMLElement} element - * @param {string} [currentLang] - * @param {string} [resultLang] - */ - function updateClassName(element, currentLang, resultLang) { - const language = (currentLang && aliases[currentLang]) || resultLang; - - element.classList.add("hljs"); - element.classList.add(`language-${language}`); - } - - /** - * Applies highlighting to a DOM node containing code. - * - * @param {HighlightedHTMLElement} element - the HTML element to highlight - */ - function highlightElement(element) { - /** @type HTMLElement */ - let node = null; - const language = blockLanguage(element); - - if (shouldNotHighlight(language)) return; - - fire("before:highlightElement", - { el: element, language: language }); - - // we should be all text, no child nodes (unescaped HTML) - this is possibly - // an HTML injection attack - it's likely too late if this is already in - // production (the code has likely already done its damage by the time - // we're seeing it)... but we yell loudly about this so that hopefully it's - // more likely to be caught in development before making it to production - if (element.children.length > 0) { - if (!options.ignoreUnescapedHTML) { - console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."); - console.warn("https://github.com/highlightjs/highlight.js/wiki/security"); - console.warn("The element with unescaped HTML:"); - console.warn(element); - } - if (options.throwUnescapedHTML) { - const err = new HTMLInjectionError( - "One of your code blocks includes unescaped HTML.", - element.innerHTML - ); - throw err; - } - } - - node = element; - const text = node.textContent; - const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text); - - element.innerHTML = result.value; - updateClassName(element, language, result.language); - element.result = { - language: result.language, - // TODO: remove with version 11.0 - re: result.relevance, - relevance: result.relevance - }; - if (result.secondBest) { - element.secondBest = { - language: result.secondBest.language, - relevance: result.secondBest.relevance - }; - } - - fire("after:highlightElement", { el: element, result, text }); - } - - /** - * Updates highlight.js global options with the passed options - * - * @param {Partial} userOptions - */ - function configure(userOptions) { - options = inherit(options, userOptions); - } - - // TODO: remove v12, deprecated - const initHighlighting = () => { - highlightAll(); - deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now."); + /** + * returns a valid highlight result, without actually doing any actual work, + * auto highlight starts with this and it's possible for small snippets that + * auto-detection may not find a better match + * @param {string} code + * @returns {HighlightResult} + */ + function justTextHighlightResult(code) { + const result = { + value: escape(code), + illegal: false, + relevance: 0, + _top: PLAINTEXT_LANGUAGE, + _emitter: new options.__emitter(options) }; + result._emitter.addText(code); + return result; + } - // TODO: remove v12, deprecated - function initHighlightingOnLoad() { - highlightAll(); - deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now."); - } + /** + Highlighting with language detection. Accepts a string with the code to + highlight. Returns an object with the following properties: - let wantsHighlight = false; + - language (detected language) + - relevance (int) + - value (an HTML string with highlighting markup) + - secondBest (object with the same structure for second-best heuristically + detected language, may be absent) - /** - * auto-highlights all pre>code elements on the page - */ - function highlightAll() { - // if we are called too early in the loading process - if (document.readyState === "loading") { - wantsHighlight = true; - return; - } + @param {string} code + @param {Array} [languageSubset] + @returns {AutoHighlightResult} + */ + function highlightAuto(code, languageSubset) { + languageSubset = languageSubset || options.languages || Object.keys(languages); + const plaintext = justTextHighlightResult(code); - const blocks = document.querySelectorAll(options.cssSelector); - blocks.forEach(highlightElement); - } + const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name => + _highlight(name, code, false) + ); + results.unshift(plaintext); // plaintext is always an option - function boot() { - // if a highlight was requested before DOM was loaded, do now - if (wantsHighlight) highlightAll(); - } + const sorted = results.sort((a, b) => { + // sort base on relevance + if (a.relevance !== b.relevance) return b.relevance - a.relevance; - // make sure we are in the browser environment - if (typeof window !== 'undefined' && window.addEventListener) { - window.addEventListener('DOMContentLoaded', boot, false); - } - - /** - * Register a language grammar module - * - * @param {string} languageName - * @param {LanguageFn} languageDefinition - */ - function registerLanguage(languageName, languageDefinition) { - let lang = null; - try { - lang = languageDefinition(hljs); - } catch (error$1) { - error("Language definition for '{}' could not be registered.".replace("{}", languageName)); - // hard or soft error - if (!SAFE_MODE) { throw error$1; } else { error(error$1); } - // languages that have serious errors are replaced with essentially a - // "plaintext" stand-in so that the code blocks will still get normal - // css classes applied to them - and one bad language won't break the - // entire highlighter - lang = PLAINTEXT_LANGUAGE; - } - // give it a temporary name if it doesn't have one in the meta-data - if (!lang.name) lang.name = languageName; - languages[languageName] = lang; - lang.rawDefinition = languageDefinition.bind(null, hljs); - - if (lang.aliases) { - registerAliases(lang.aliases, { languageName }); - } - } - - /** - * Remove a language grammar module - * - * @param {string} languageName - */ - function unregisterLanguage(languageName) { - delete languages[languageName]; - for (const alias of Object.keys(aliases)) { - if (aliases[alias] === languageName) { - delete aliases[alias]; + // always award the tie to the base language + // ie if C++ and Arduino are tied, it's more likely to be C++ + if (a.language && b.language) { + if (getLanguage(a.language).supersetOf === b.language) { + return 1; + } else if (getLanguage(b.language).supersetOf === a.language) { + return -1; } } - } - /** - * @returns {string[]} List of language internal names - */ - function listLanguages() { - return Object.keys(languages); - } - - /** - * @param {string} name - name of the language to retrieve - * @returns {Language | undefined} - */ - function getLanguage(name) { - name = (name || '').toLowerCase(); - return languages[name] || languages[aliases[name]]; - } - - /** - * - * @param {string|string[]} aliasList - single alias or list of aliases - * @param {{languageName: string}} opts - */ - function registerAliases(aliasList, { languageName }) { - if (typeof aliasList === 'string') { - aliasList = [aliasList]; - } - aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; }); - } - - /** - * Determines if a given language has auto-detection enabled - * @param {string} name - name of the language - */ - function autoDetection(name) { - const lang = getLanguage(name); - return lang && !lang.disableAutodetect; - } - - /** - * Upgrades the old highlightBlock plugins to the new - * highlightElement API - * @param {HLJSPlugin} plugin - */ - function upgradePluginAPI(plugin) { - // TODO: remove with v12 - if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) { - plugin["before:highlightElement"] = (data) => { - plugin["before:highlightBlock"]( - Object.assign({ block: data.el }, data) - ); - }; - } - if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) { - plugin["after:highlightElement"] = (data) => { - plugin["after:highlightBlock"]( - Object.assign({ block: data.el }, data) - ); - }; - } - } - - /** - * @param {HLJSPlugin} plugin - */ - function addPlugin(plugin) { - upgradePluginAPI(plugin); - plugins.push(plugin); - } - - /** - * - * @param {PluginEvent} event - * @param {any} args - */ - function fire(event, args) { - const cb = event; - plugins.forEach(function(plugin) { - if (plugin[cb]) { - plugin[cb](args); - } - }); - } - - /** - * DEPRECATED - * @param {HighlightedHTMLElement} el - */ - function deprecateHighlightBlock(el) { - deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0"); - deprecated("10.7.0", "Please use highlightElement now."); - - return highlightElement(el); - } - - /* Interface definition */ - Object.assign(hljs, { - highlight, - highlightAuto, - highlightAll, - highlightElement, - // TODO: Remove with v12 API - highlightBlock: deprecateHighlightBlock, - configure, - initHighlighting, - initHighlightingOnLoad, - registerLanguage, - unregisterLanguage, - listLanguages, - getLanguage, - registerAliases, - autoDetection, - inherit, - addPlugin + // otherwise say they are equal, which has the effect of sorting on + // relevance while preserving the original ordering - which is how ties + // have historically been settled, ie the language that comes first always + // wins in the case of a tie + return 0; }); - hljs.debugMode = function() { SAFE_MODE = false; }; - hljs.safeMode = function() { SAFE_MODE = true; }; - hljs.versionString = version; + const [best, secondBest] = sorted; - hljs.regex = { - concat: concat, - lookahead: lookahead, - either: either, - optional: optional, - anyNumberOfTimes: anyNumberOfTimes - }; + /** @type {AutoHighlightResult} */ + const result = best; + result.secondBest = secondBest; - for (const key in MODES) { - // @ts-ignore - if (typeof MODES[key] === "object") { - // @ts-ignore - deepFreezeEs6.exports(MODES[key]); + return result; + } + + /** + * Builds new class name for block given the language name + * + * @param {HTMLElement} element + * @param {string} [currentLang] + * @param {string} [resultLang] + */ + function updateClassName(element, currentLang, resultLang) { + const language = (currentLang && aliases[currentLang]) || resultLang; + + element.classList.add("hljs"); + element.classList.add(`language-${language}`); + } + + /** + * Applies highlighting to a DOM node containing code. + * + * @param {HighlightedHTMLElement} element - the HTML element to highlight + */ + function highlightElement(element) { + /** @type HTMLElement */ + let node = null; + const language = blockLanguage(element); + + if (shouldNotHighlight(language)) return; + + fire("before:highlightElement", + { el: element, language }); + + if (element.dataset.highlighted) { + console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.", element); + return; + } + + // we should be all text, no child nodes (unescaped HTML) - this is possibly + // an HTML injection attack - it's likely too late if this is already in + // production (the code has likely already done its damage by the time + // we're seeing it)... but we yell loudly about this so that hopefully it's + // more likely to be caught in development before making it to production + if (element.children.length > 0) { + if (!options.ignoreUnescapedHTML) { + console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."); + console.warn("https://github.com/highlightjs/highlight.js/wiki/security"); + console.warn("The element with unescaped HTML:"); + console.warn(element); + } + if (options.throwUnescapedHTML) { + const err = new HTMLInjectionError( + "One of your code blocks includes unescaped HTML.", + element.innerHTML + ); + throw err; } } - // merge all the modes/regexes into our main object - Object.assign(hljs, MODES); + node = element; + const text = node.textContent; + const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text); - return hljs; + element.innerHTML = result.value; + element.dataset.highlighted = "yes"; + updateClassName(element, language, result.language); + element.result = { + language: result.language, + // TODO: remove with version 11.0 + re: result.relevance, + relevance: result.relevance + }; + if (result.secondBest) { + element.secondBest = { + language: result.secondBest.language, + relevance: result.secondBest.relevance + }; + } + + fire("after:highlightElement", { el: element, result, text }); + } + + /** + * Updates highlight.js global options with the passed options + * + * @param {Partial} userOptions + */ + function configure(userOptions) { + options = inherit(options, userOptions); + } + + // TODO: remove v12, deprecated + const initHighlighting = () => { + highlightAll(); + deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now."); }; - // export an "instance" of the highlighter - var highlight = HLJS({}); + // TODO: remove v12, deprecated + function initHighlightingOnLoad() { + highlightAll(); + deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now."); + } - return highlight; + let wantsHighlight = false; + + /** + * auto-highlights all pre>code elements on the page + */ + function highlightAll() { + // if we are called too early in the loading process + if (document.readyState === "loading") { + wantsHighlight = true; + return; + } + + const blocks = document.querySelectorAll(options.cssSelector); + blocks.forEach(highlightElement); + } + + function boot() { + // if a highlight was requested before DOM was loaded, do now + if (wantsHighlight) highlightAll(); + } + + // make sure we are in the browser environment + if (typeof window !== 'undefined' && window.addEventListener) { + window.addEventListener('DOMContentLoaded', boot, false); + } + + /** + * Register a language grammar module + * + * @param {string} languageName + * @param {LanguageFn} languageDefinition + */ + function registerLanguage(languageName, languageDefinition) { + let lang = null; + try { + lang = languageDefinition(hljs); + } catch (error$1) { + error("Language definition for '{}' could not be registered.".replace("{}", languageName)); + // hard or soft error + if (!SAFE_MODE) { throw error$1; } else { error(error$1); } + // languages that have serious errors are replaced with essentially a + // "plaintext" stand-in so that the code blocks will still get normal + // css classes applied to them - and one bad language won't break the + // entire highlighter + lang = PLAINTEXT_LANGUAGE; + } + // give it a temporary name if it doesn't have one in the meta-data + if (!lang.name) lang.name = languageName; + languages[languageName] = lang; + lang.rawDefinition = languageDefinition.bind(null, hljs); + + if (lang.aliases) { + registerAliases(lang.aliases, { languageName }); + } + } + + /** + * Remove a language grammar module + * + * @param {string} languageName + */ + function unregisterLanguage(languageName) { + delete languages[languageName]; + for (const alias of Object.keys(aliases)) { + if (aliases[alias] === languageName) { + delete aliases[alias]; + } + } + } + + /** + * @returns {string[]} List of language internal names + */ + function listLanguages() { + return Object.keys(languages); + } + + /** + * @param {string} name - name of the language to retrieve + * @returns {Language | undefined} + */ + function getLanguage(name) { + name = (name || '').toLowerCase(); + return languages[name] || languages[aliases[name]]; + } + + /** + * + * @param {string|string[]} aliasList - single alias or list of aliases + * @param {{languageName: string}} opts + */ + function registerAliases(aliasList, { languageName }) { + if (typeof aliasList === 'string') { + aliasList = [aliasList]; + } + aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; }); + } + + /** + * Determines if a given language has auto-detection enabled + * @param {string} name - name of the language + */ + function autoDetection(name) { + const lang = getLanguage(name); + return lang && !lang.disableAutodetect; + } + + /** + * Upgrades the old highlightBlock plugins to the new + * highlightElement API + * @param {HLJSPlugin} plugin + */ + function upgradePluginAPI(plugin) { + // TODO: remove with v12 + if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) { + plugin["before:highlightElement"] = (data) => { + plugin["before:highlightBlock"]( + Object.assign({ block: data.el }, data) + ); + }; + } + if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) { + plugin["after:highlightElement"] = (data) => { + plugin["after:highlightBlock"]( + Object.assign({ block: data.el }, data) + ); + }; + } + } + + /** + * @param {HLJSPlugin} plugin + */ + function addPlugin(plugin) { + upgradePluginAPI(plugin); + plugins.push(plugin); + } + + /** + * @param {HLJSPlugin} plugin + */ + function removePlugin(plugin) { + const index = plugins.indexOf(plugin); + if (index !== -1) { + plugins.splice(index, 1); + } + } + + /** + * + * @param {PluginEvent} event + * @param {any} args + */ + function fire(event, args) { + const cb = event; + plugins.forEach(function(plugin) { + if (plugin[cb]) { + plugin[cb](args); + } + }); + } + + /** + * DEPRECATED + * @param {HighlightedHTMLElement} el + */ + function deprecateHighlightBlock(el) { + deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0"); + deprecated("10.7.0", "Please use highlightElement now."); + + return highlightElement(el); + } + + /* Interface definition */ + Object.assign(hljs, { + highlight, + highlightAuto, + highlightAll, + highlightElement, + // TODO: Remove with v12 API + highlightBlock: deprecateHighlightBlock, + configure, + initHighlighting, + initHighlightingOnLoad, + registerLanguage, + unregisterLanguage, + listLanguages, + getLanguage, + registerAliases, + autoDetection, + inherit, + addPlugin, + removePlugin + }); + + hljs.debugMode = function() { SAFE_MODE = false; }; + hljs.safeMode = function() { SAFE_MODE = true; }; + hljs.versionString = version; + + hljs.regex = { + concat: concat, + lookahead: lookahead, + either: either, + optional: optional, + anyNumberOfTimes: anyNumberOfTimes + }; + + for (const key in MODES) { + // @ts-ignore + if (typeof MODES[key] === "object") { + // @ts-ignore + deepFreeze(MODES[key]); + } + } + + // merge all the modes/regexes into our main object + Object.assign(hljs, MODES); + + return hljs; + }; + + // Other names for the variable may break build script + const highlight = HLJS({}); + + // returns a new instance of the highlighter to be used for extensions + // check https://github.com/wooorm/lowlight/issues/47 + highlight.newInstance = () => HLJS({}); + + return highlight; })(); if (typeof exports === 'object' && typeof module !== 'undefined') { module.exports = hljs; } +/*! `bash` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Bash + Author: vah + Contributrors: Benjamin Pannell + Website: https://www.gnu.org/software/bash/ + Category: common, scripting + */ + + /** @type LanguageFn */ + function bash(hljs) { + const regex = hljs.regex; + const VAR = {}; + const BRACED_VAR = { + begin: /\$\{/, + end: /\}/, + contains: [ + "self", + { + begin: /:-/, + contains: [ VAR ] + } // default values + ] + }; + Object.assign(VAR, { + className: 'variable', + variants: [ + { begin: regex.concat(/\$[\w\d#@][\w\d_]*/, + // negative look-ahead tries to avoid matching patterns that are not + // Perl at all like $ident$, @ident@, etc. + `(?![\\w\\d])(?![$])`) }, + BRACED_VAR + ] + }); + + const SUBST = { + className: 'subst', + begin: /\$\(/, + end: /\)/, + contains: [ hljs.BACKSLASH_ESCAPE ] + }; + const COMMENT = hljs.inherit( + hljs.COMMENT(), + { + match: [ + /(^|\s)/, + /#.*$/ + ], + scope: { + 2: 'comment' + } + } + ); + const HERE_DOC = { + begin: /<<-?\s*(?=\w+)/, + starts: { contains: [ + hljs.END_SAME_AS_BEGIN({ + begin: /(\w+)/, + end: /(\w+)/, + className: 'string' + }) + ] } + }; + const QUOTE_STRING = { + className: 'string', + begin: /"/, + end: /"/, + contains: [ + hljs.BACKSLASH_ESCAPE, + VAR, + SUBST + ] + }; + SUBST.contains.push(QUOTE_STRING); + const ESCAPED_QUOTE = { + match: /\\"/ + }; + const APOS_STRING = { + className: 'string', + begin: /'/, + end: /'/ + }; + const ESCAPED_APOS = { + match: /\\'/ + }; + const ARITHMETIC = { + begin: /\$?\(\(/, + end: /\)\)/, + contains: [ + { + begin: /\d+#[0-9a-f]+/, + className: "number" + }, + hljs.NUMBER_MODE, + VAR + ] + }; + const SH_LIKE_SHELLS = [ + "fish", + "bash", + "zsh", + "sh", + "csh", + "ksh", + "tcsh", + "dash", + "scsh", + ]; + const KNOWN_SHEBANG = hljs.SHEBANG({ + binary: `(${SH_LIKE_SHELLS.join("|")})`, + relevance: 10 + }); + const FUNCTION = { + className: 'function', + begin: /\w[\w\d_]*\s*\(\s*\)\s*\{/, + returnBegin: true, + contains: [ hljs.inherit(hljs.TITLE_MODE, { begin: /\w[\w\d_]*/ }) ], + relevance: 0 + }; + + const KEYWORDS = [ + "if", + "then", + "else", + "elif", + "fi", + "for", + "while", + "until", + "in", + "do", + "done", + "case", + "esac", + "function", + "select" + ]; + + const LITERALS = [ + "true", + "false" + ]; + + // to consume paths to prevent keyword matches inside them + const PATH_MODE = { match: /(\/[a-z._-]+)+/ }; + + // http://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html + const SHELL_BUILT_INS = [ + "break", + "cd", + "continue", + "eval", + "exec", + "exit", + "export", + "getopts", + "hash", + "pwd", + "readonly", + "return", + "shift", + "test", + "times", + "trap", + "umask", + "unset" + ]; + + const BASH_BUILT_INS = [ + "alias", + "bind", + "builtin", + "caller", + "command", + "declare", + "echo", + "enable", + "help", + "let", + "local", + "logout", + "mapfile", + "printf", + "read", + "readarray", + "source", + "type", + "typeset", + "ulimit", + "unalias" + ]; + + const ZSH_BUILT_INS = [ + "autoload", + "bg", + "bindkey", + "bye", + "cap", + "chdir", + "clone", + "comparguments", + "compcall", + "compctl", + "compdescribe", + "compfiles", + "compgroups", + "compquote", + "comptags", + "comptry", + "compvalues", + "dirs", + "disable", + "disown", + "echotc", + "echoti", + "emulate", + "fc", + "fg", + "float", + "functions", + "getcap", + "getln", + "history", + "integer", + "jobs", + "kill", + "limit", + "log", + "noglob", + "popd", + "print", + "pushd", + "pushln", + "rehash", + "sched", + "setcap", + "setopt", + "stat", + "suspend", + "ttyctl", + "unfunction", + "unhash", + "unlimit", + "unsetopt", + "vared", + "wait", + "whence", + "where", + "which", + "zcompile", + "zformat", + "zftp", + "zle", + "zmodload", + "zparseopts", + "zprof", + "zpty", + "zregexparse", + "zsocket", + "zstyle", + "ztcp" + ]; + + const GNU_CORE_UTILS = [ + "chcon", + "chgrp", + "chown", + "chmod", + "cp", + "dd", + "df", + "dir", + "dircolors", + "ln", + "ls", + "mkdir", + "mkfifo", + "mknod", + "mktemp", + "mv", + "realpath", + "rm", + "rmdir", + "shred", + "sync", + "touch", + "truncate", + "vdir", + "b2sum", + "base32", + "base64", + "cat", + "cksum", + "comm", + "csplit", + "cut", + "expand", + "fmt", + "fold", + "head", + "join", + "md5sum", + "nl", + "numfmt", + "od", + "paste", + "ptx", + "pr", + "sha1sum", + "sha224sum", + "sha256sum", + "sha384sum", + "sha512sum", + "shuf", + "sort", + "split", + "sum", + "tac", + "tail", + "tr", + "tsort", + "unexpand", + "uniq", + "wc", + "arch", + "basename", + "chroot", + "date", + "dirname", + "du", + "echo", + "env", + "expr", + "factor", + // "false", // keyword literal already + "groups", + "hostid", + "id", + "link", + "logname", + "nice", + "nohup", + "nproc", + "pathchk", + "pinky", + "printenv", + "printf", + "pwd", + "readlink", + "runcon", + "seq", + "sleep", + "stat", + "stdbuf", + "stty", + "tee", + "test", + "timeout", + // "true", // keyword literal already + "tty", + "uname", + "unlink", + "uptime", + "users", + "who", + "whoami", + "yes" + ]; + + return { + name: 'Bash', + aliases: [ 'sh' ], + keywords: { + $pattern: /\b[a-z][a-z0-9._-]+\b/, + keyword: KEYWORDS, + literal: LITERALS, + built_in: [ + ...SHELL_BUILT_INS, + ...BASH_BUILT_INS, + // Shell modifiers + "set", + "shopt", + ...ZSH_BUILT_INS, + ...GNU_CORE_UTILS + ] + }, + contains: [ + KNOWN_SHEBANG, // to catch known shells and boost relevancy + hljs.SHEBANG(), // to catch unknown shells but still highlight the shebang + FUNCTION, + ARITHMETIC, + COMMENT, + HERE_DOC, + PATH_MODE, + QUOTE_STRING, + ESCAPED_QUOTE, + APOS_STRING, + ESCAPED_APOS, + VAR + ] + }; + } + + return bash; + +})(); + + hljs.registerLanguage('bash', hljsGrammar); + })();/*! `c` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: C + Category: common, system + Website: https://en.wikipedia.org/wiki/C_(programming_language) + */ + + /** @type LanguageFn */ + function c(hljs) { + const regex = hljs.regex; + // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does + // not include such support nor can we be sure all the grammars depending + // on it would desire this behavior + const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] }); + const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)'; + const NAMESPACE_RE = '[a-zA-Z_]\\w*::'; + const TEMPLATE_ARGUMENT_RE = '<[^<>]+>'; + const FUNCTION_TYPE_RE = '(' + + DECLTYPE_AUTO_RE + '|' + + regex.optional(NAMESPACE_RE) + + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE) + + ')'; + + + const TYPES = { + className: 'type', + variants: [ + { begin: '\\b[a-z\\d_]*_t\\b' }, + { match: /\batomic_[a-z]{3,6}\b/ } + ] + + }; + + // https://en.cppreference.com/w/cpp/language/escape + // \\ \x \xFF \u2837 \u00323747 \374 + const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)'; + const STRINGS = { + className: 'string', + variants: [ + { + begin: '(u8?|U|L)?"', + end: '"', + illegal: '\\n', + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + { + begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + "|.)", + end: '\'', + illegal: '.' + }, + hljs.END_SAME_AS_BEGIN({ + begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/, + end: /\)([^()\\ ]{0,16})"/ + }) + ] + }; + + const NUMBERS = { + className: 'number', + variants: [ + { begin: '\\b(0b[01\']+)' }, + { begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)' }, + { begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' } + ], + relevance: 0 + }; + + const PREPROCESSOR = { + className: 'meta', + begin: /#\s*[a-z]+\b/, + end: /$/, + keywords: { keyword: + 'if else elif endif define undef warning error line ' + + 'pragma _Pragma ifdef ifndef include' }, + contains: [ + { + begin: /\\\n/, + relevance: 0 + }, + hljs.inherit(STRINGS, { className: 'string' }), + { + className: 'string', + begin: /<.*?>/ + }, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }; + + const TITLE_MODE = { + className: 'title', + begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE, + relevance: 0 + }; + + const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\('; + + const C_KEYWORDS = [ + "asm", + "auto", + "break", + "case", + "continue", + "default", + "do", + "else", + "enum", + "extern", + "for", + "fortran", + "goto", + "if", + "inline", + "register", + "restrict", + "return", + "sizeof", + "struct", + "switch", + "typedef", + "union", + "volatile", + "while", + "_Alignas", + "_Alignof", + "_Atomic", + "_Generic", + "_Noreturn", + "_Static_assert", + "_Thread_local", + // aliases + "alignas", + "alignof", + "noreturn", + "static_assert", + "thread_local", + // not a C keyword but is, for all intents and purposes, treated exactly like one. + "_Pragma" + ]; + + const C_TYPES = [ + "float", + "double", + "signed", + "unsigned", + "int", + "short", + "long", + "char", + "void", + "_Bool", + "_Complex", + "_Imaginary", + "_Decimal32", + "_Decimal64", + "_Decimal128", + // modifiers + "const", + "static", + // aliases + "complex", + "bool", + "imaginary" + ]; + + const KEYWORDS = { + keyword: C_KEYWORDS, + type: C_TYPES, + literal: 'true false NULL', + // TODO: apply hinting work similar to what was done in cpp.js + built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream ' + + 'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set ' + + 'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos ' + + 'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp ' + + 'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper ' + + 'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow ' + + 'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp ' + + 'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan ' + + 'vfprintf vprintf vsprintf endl initializer_list unique_ptr', + }; + + const EXPRESSION_CONTAINS = [ + PREPROCESSOR, + TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + NUMBERS, + STRINGS + ]; + + const EXPRESSION_CONTEXT = { + // This mode covers expression context where we can't expect a function + // definition and shouldn't highlight anything that looks like one: + // `return some()`, `else if()`, `(x*sum(1, 2))` + variants: [ + { + begin: /=/, + end: /;/ + }, + { + begin: /\(/, + end: /\)/ + }, + { + beginKeywords: 'new throw return else', + end: /;/ + } + ], + keywords: KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ + { + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ 'self' ]), + relevance: 0 + } + ]), + relevance: 0 + }; + + const FUNCTION_DECLARATION = { + begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE, + returnBegin: true, + end: /[{;=]/, + excludeEnd: true, + keywords: KEYWORDS, + illegal: /[^\w\s\*&:<>.]/, + contains: [ + { // to prevent it from being confused as the function title + begin: DECLTYPE_AUTO_RE, + keywords: KEYWORDS, + relevance: 0 + }, + { + begin: FUNCTION_TITLE, + returnBegin: true, + contains: [ hljs.inherit(TITLE_MODE, { className: "title.function" }) ], + relevance: 0 + }, + // allow for multiple declarations, e.g.: + // extern void f(int), g(char); + { + relevance: 0, + match: /,/ + }, + { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + TYPES, + // Count matching parentheses. + { + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ + 'self', + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + TYPES + ] + } + ] + }, + TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + PREPROCESSOR + ] + }; + + return { + name: "C", + aliases: [ 'h' ], + keywords: KEYWORDS, + // Until differentiations are added between `c` and `cpp`, `c` will + // not be auto-detected to avoid auto-detect conflicts between C and C++ + disableAutodetect: true, + illegal: '=]/, + contains: [ + { beginKeywords: "final class struct" }, + hljs.TITLE_MODE + ] + } + ]), + exports: { + preprocessor: PREPROCESSOR, + strings: STRINGS, + keywords: KEYWORDS + } + }; + } + + return c; + +})(); + + hljs.registerLanguage('c', hljsGrammar); + })();/*! `cmake` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: CMake + Description: CMake is an open-source cross-platform system for build automation. + Author: Igor Kalnitsky + Website: https://cmake.org + Category: build-system + */ + + /** @type LanguageFn */ + function cmake(hljs) { + return { + name: 'CMake', + aliases: [ 'cmake.in' ], + case_insensitive: true, + keywords: { keyword: + // scripting commands + 'break cmake_host_system_information cmake_minimum_required cmake_parse_arguments ' + + 'cmake_policy configure_file continue elseif else endforeach endfunction endif endmacro ' + + 'endwhile execute_process file find_file find_library find_package find_path ' + + 'find_program foreach function get_cmake_property get_directory_property ' + + 'get_filename_component get_property if include include_guard list macro ' + + 'mark_as_advanced math message option return separate_arguments ' + + 'set_directory_properties set_property set site_name string unset variable_watch while ' + // project commands + + 'add_compile_definitions add_compile_options add_custom_command add_custom_target ' + + 'add_definitions add_dependencies add_executable add_library add_link_options ' + + 'add_subdirectory add_test aux_source_directory build_command create_test_sourcelist ' + + 'define_property enable_language enable_testing export fltk_wrap_ui ' + + 'get_source_file_property get_target_property get_test_property include_directories ' + + 'include_external_msproject include_regular_expression install link_directories ' + + 'link_libraries load_cache project qt_wrap_cpp qt_wrap_ui remove_definitions ' + + 'set_source_files_properties set_target_properties set_tests_properties source_group ' + + 'target_compile_definitions target_compile_features target_compile_options ' + + 'target_include_directories target_link_directories target_link_libraries ' + + 'target_link_options target_sources try_compile try_run ' + // CTest commands + + 'ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ' + + 'ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ' + + 'ctest_test ctest_update ctest_upload ' + // deprecated commands + + 'build_name exec_program export_library_dependencies install_files install_programs ' + + 'install_targets load_command make_directory output_required_files remove ' + + 'subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file ' + + 'qt5_use_modules qt5_use_package qt5_wrap_cpp ' + // core keywords + + 'on off true false and or not command policy target test exists is_newer_than ' + + 'is_directory is_symlink is_absolute matches less greater equal less_equal ' + + 'greater_equal strless strgreater strequal strless_equal strgreater_equal version_less ' + + 'version_greater version_equal version_less_equal version_greater_equal in_list defined' }, + contains: [ + { + className: 'variable', + begin: /\$\{/, + end: /\}/ + }, + hljs.COMMENT(/#\[\[/, /]]/), + hljs.HASH_COMMENT_MODE, + hljs.QUOTE_STRING_MODE, + hljs.NUMBER_MODE + ] + }; + } + + return cmake; + +})(); + + hljs.registerLanguage('cmake', hljsGrammar); + })();/*! `cpp` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: C++ + Category: common, system + Website: https://isocpp.org + */ + + /** @type LanguageFn */ + function cpp(hljs) { + const regex = hljs.regex; + // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does + // not include such support nor can we be sure all the grammars depending + // on it would desire this behavior + const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] }); + const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)'; + const NAMESPACE_RE = '[a-zA-Z_]\\w*::'; + const TEMPLATE_ARGUMENT_RE = '<[^<>]+>'; + const FUNCTION_TYPE_RE = '(?!struct)(' + + DECLTYPE_AUTO_RE + '|' + + regex.optional(NAMESPACE_RE) + + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE) + + ')'; + + const CPP_PRIMITIVE_TYPES = { + className: 'type', + begin: '\\b[a-z\\d_]*_t\\b' + }; + + // https://en.cppreference.com/w/cpp/language/escape + // \\ \x \xFF \u2837 \u00323747 \374 + const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)'; + const STRINGS = { + className: 'string', + variants: [ + { + begin: '(u8?|U|L)?"', + end: '"', + illegal: '\\n', + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + { + begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + '|.)', + end: '\'', + illegal: '.' + }, + hljs.END_SAME_AS_BEGIN({ + begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/, + end: /\)([^()\\ ]{0,16})"/ + }) + ] + }; + + const NUMBERS = { + className: 'number', + variants: [ + // Floating-point literal. + { begin: + "[+-]?(?:" // Leading sign. + // Decimal. + + "(?:" + +"[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?" + + "|\\.[0-9](?:'?[0-9])*" + + ")(?:[Ee][+-]?[0-9](?:'?[0-9])*)?" + + "|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*" + // Hexadecimal. + + "|0[Xx](?:" + +"[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?" + + "|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*" + + ")[Pp][+-]?[0-9](?:'?[0-9])*" + + ")(?:" // Literal suffixes. + + "[Ff](?:16|32|64|128)?" + + "|(BF|bf)16" + + "|[Ll]" + + "|" // Literal suffix is optional. + + ")" + }, + // Integer literal. + { begin: + "[+-]?\\b(?:" // Leading sign. + + "0[Bb][01](?:'?[01])*" // Binary. + + "|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*" // Hexadecimal. + + "|0(?:'?[0-7])*" // Octal or just a lone zero. + + "|[1-9](?:'?[0-9])*" // Decimal. + + ")(?:" // Literal suffixes. + + "[Uu](?:LL?|ll?)" + + "|[Uu][Zz]?" + + "|(?:LL?|ll?)[Uu]?" + + "|[Zz][Uu]" + + "|" // Literal suffix is optional. + + ")" + // Note: there are user-defined literal suffixes too, but perhaps having the custom suffix not part of the + // literal highlight actually makes it stand out more. + } + ], + relevance: 0 + }; + + const PREPROCESSOR = { + className: 'meta', + begin: /#\s*[a-z]+\b/, + end: /$/, + keywords: { keyword: + 'if else elif endif define undef warning error line ' + + 'pragma _Pragma ifdef ifndef include' }, + contains: [ + { + begin: /\\\n/, + relevance: 0 + }, + hljs.inherit(STRINGS, { className: 'string' }), + { + className: 'string', + begin: /<.*?>/ + }, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }; + + const TITLE_MODE = { + className: 'title', + begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE, + relevance: 0 + }; + + const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\('; + + // https://en.cppreference.com/w/cpp/keyword + const RESERVED_KEYWORDS = [ + 'alignas', + 'alignof', + 'and', + 'and_eq', + 'asm', + 'atomic_cancel', + 'atomic_commit', + 'atomic_noexcept', + 'auto', + 'bitand', + 'bitor', + 'break', + 'case', + 'catch', + 'class', + 'co_await', + 'co_return', + 'co_yield', + 'compl', + 'concept', + 'const_cast|10', + 'consteval', + 'constexpr', + 'constinit', + 'continue', + 'decltype', + 'default', + 'delete', + 'do', + 'dynamic_cast|10', + 'else', + 'enum', + 'explicit', + 'export', + 'extern', + 'false', + 'final', + 'for', + 'friend', + 'goto', + 'if', + 'import', + 'inline', + 'module', + 'mutable', + 'namespace', + 'new', + 'noexcept', + 'not', + 'not_eq', + 'nullptr', + 'operator', + 'or', + 'or_eq', + 'override', + 'private', + 'protected', + 'public', + 'reflexpr', + 'register', + 'reinterpret_cast|10', + 'requires', + 'return', + 'sizeof', + 'static_assert', + 'static_cast|10', + 'struct', + 'switch', + 'synchronized', + 'template', + 'this', + 'thread_local', + 'throw', + 'transaction_safe', + 'transaction_safe_dynamic', + 'true', + 'try', + 'typedef', + 'typeid', + 'typename', + 'union', + 'using', + 'virtual', + 'volatile', + 'while', + 'xor', + 'xor_eq' + ]; + + // https://en.cppreference.com/w/cpp/keyword + const RESERVED_TYPES = [ + 'bool', + 'char', + 'char16_t', + 'char32_t', + 'char8_t', + 'double', + 'float', + 'int', + 'long', + 'short', + 'void', + 'wchar_t', + 'unsigned', + 'signed', + 'const', + 'static' + ]; + + const TYPE_HINTS = [ + 'any', + 'auto_ptr', + 'barrier', + 'binary_semaphore', + 'bitset', + 'complex', + 'condition_variable', + 'condition_variable_any', + 'counting_semaphore', + 'deque', + 'false_type', + 'future', + 'imaginary', + 'initializer_list', + 'istringstream', + 'jthread', + 'latch', + 'lock_guard', + 'multimap', + 'multiset', + 'mutex', + 'optional', + 'ostringstream', + 'packaged_task', + 'pair', + 'promise', + 'priority_queue', + 'queue', + 'recursive_mutex', + 'recursive_timed_mutex', + 'scoped_lock', + 'set', + 'shared_future', + 'shared_lock', + 'shared_mutex', + 'shared_timed_mutex', + 'shared_ptr', + 'stack', + 'string_view', + 'stringstream', + 'timed_mutex', + 'thread', + 'true_type', + 'tuple', + 'unique_lock', + 'unique_ptr', + 'unordered_map', + 'unordered_multimap', + 'unordered_multiset', + 'unordered_set', + 'variant', + 'vector', + 'weak_ptr', + 'wstring', + 'wstring_view' + ]; + + const FUNCTION_HINTS = [ + 'abort', + 'abs', + 'acos', + 'apply', + 'as_const', + 'asin', + 'atan', + 'atan2', + 'calloc', + 'ceil', + 'cerr', + 'cin', + 'clog', + 'cos', + 'cosh', + 'cout', + 'declval', + 'endl', + 'exchange', + 'exit', + 'exp', + 'fabs', + 'floor', + 'fmod', + 'forward', + 'fprintf', + 'fputs', + 'free', + 'frexp', + 'fscanf', + 'future', + 'invoke', + 'isalnum', + 'isalpha', + 'iscntrl', + 'isdigit', + 'isgraph', + 'islower', + 'isprint', + 'ispunct', + 'isspace', + 'isupper', + 'isxdigit', + 'labs', + 'launder', + 'ldexp', + 'log', + 'log10', + 'make_pair', + 'make_shared', + 'make_shared_for_overwrite', + 'make_tuple', + 'make_unique', + 'malloc', + 'memchr', + 'memcmp', + 'memcpy', + 'memset', + 'modf', + 'move', + 'pow', + 'printf', + 'putchar', + 'puts', + 'realloc', + 'scanf', + 'sin', + 'sinh', + 'snprintf', + 'sprintf', + 'sqrt', + 'sscanf', + 'std', + 'stderr', + 'stdin', + 'stdout', + 'strcat', + 'strchr', + 'strcmp', + 'strcpy', + 'strcspn', + 'strlen', + 'strncat', + 'strncmp', + 'strncpy', + 'strpbrk', + 'strrchr', + 'strspn', + 'strstr', + 'swap', + 'tan', + 'tanh', + 'terminate', + 'to_underlying', + 'tolower', + 'toupper', + 'vfprintf', + 'visit', + 'vprintf', + 'vsprintf' + ]; + + const LITERALS = [ + 'NULL', + 'false', + 'nullopt', + 'nullptr', + 'true' + ]; + + // https://en.cppreference.com/w/cpp/keyword + const BUILT_IN = [ '_Pragma' ]; + + const CPP_KEYWORDS = { + type: RESERVED_TYPES, + keyword: RESERVED_KEYWORDS, + literal: LITERALS, + built_in: BUILT_IN, + _type_hints: TYPE_HINTS + }; + + const FUNCTION_DISPATCH = { + className: 'function.dispatch', + relevance: 0, + keywords: { + // Only for relevance, not highlighting. + _hint: FUNCTION_HINTS }, + begin: regex.concat( + /\b/, + /(?!decltype)/, + /(?!if)/, + /(?!for)/, + /(?!switch)/, + /(?!while)/, + hljs.IDENT_RE, + regex.lookahead(/(<[^<>]+>|)\s*\(/)) + }; + + const EXPRESSION_CONTAINS = [ + FUNCTION_DISPATCH, + PREPROCESSOR, + CPP_PRIMITIVE_TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + NUMBERS, + STRINGS + ]; + + const EXPRESSION_CONTEXT = { + // This mode covers expression context where we can't expect a function + // definition and shouldn't highlight anything that looks like one: + // `return some()`, `else if()`, `(x*sum(1, 2))` + variants: [ + { + begin: /=/, + end: /;/ + }, + { + begin: /\(/, + end: /\)/ + }, + { + beginKeywords: 'new throw return else', + end: /;/ + } + ], + keywords: CPP_KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ + { + begin: /\(/, + end: /\)/, + keywords: CPP_KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ 'self' ]), + relevance: 0 + } + ]), + relevance: 0 + }; + + const FUNCTION_DECLARATION = { + className: 'function', + begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE, + returnBegin: true, + end: /[{;=]/, + excludeEnd: true, + keywords: CPP_KEYWORDS, + illegal: /[^\w\s\*&:<>.]/, + contains: [ + { // to prevent it from being confused as the function title + begin: DECLTYPE_AUTO_RE, + keywords: CPP_KEYWORDS, + relevance: 0 + }, + { + begin: FUNCTION_TITLE, + returnBegin: true, + contains: [ TITLE_MODE ], + relevance: 0 + }, + // needed because we do not have look-behind on the below rule + // to prevent it from grabbing the final : in a :: pair + { + begin: /::/, + relevance: 0 + }, + // initializers + { + begin: /:/, + endsWithParent: true, + contains: [ + STRINGS, + NUMBERS + ] + }, + // allow for multiple declarations, e.g.: + // extern void f(int), g(char); + { + relevance: 0, + match: /,/ + }, + { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: CPP_KEYWORDS, + relevance: 0, + contains: [ + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + CPP_PRIMITIVE_TYPES, + // Count matching parentheses. + { + begin: /\(/, + end: /\)/, + keywords: CPP_KEYWORDS, + relevance: 0, + contains: [ + 'self', + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + CPP_PRIMITIVE_TYPES + ] + } + ] + }, + CPP_PRIMITIVE_TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + PREPROCESSOR + ] + }; + + return { + name: 'C++', + aliases: [ + 'cc', + 'c++', + 'h++', + 'hpp', + 'hh', + 'hxx', + 'cxx' + ], + keywords: CPP_KEYWORDS, + illegal: ' rooms (9);` + begin: '\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<(?!<)', + end: '>', + keywords: CPP_KEYWORDS, + contains: [ + 'self', + CPP_PRIMITIVE_TYPES + ] + }, + { + begin: hljs.IDENT_RE + '::', + keywords: CPP_KEYWORDS + }, + { + match: [ + // extra complexity to deal with `enum class` and `enum struct` + /\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/, + /\s+/, + /\w+/ + ], + className: { + 1: 'keyword', + 3: 'title.class' + } + } + ]) + }; + } + + return cpp; + +})(); + + hljs.registerLanguage('cpp', hljsGrammar); + })();/*! `json` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: JSON + Description: JSON (JavaScript Object Notation) is a lightweight data-interchange format. + Author: Ivan Sagalaev + Website: http://www.json.org + Category: common, protocols, web + */ + + function json(hljs) { + const ATTRIBUTE = { + className: 'attr', + begin: /"(\\.|[^\\"\r\n])*"(?=\s*:)/, + relevance: 1.01 + }; + const PUNCTUATION = { + match: /[{}[\],:]/, + className: "punctuation", + relevance: 0 + }; + const LITERALS = [ + "true", + "false", + "null" + ]; + // NOTE: normally we would rely on `keywords` for this but using a mode here allows us + // - to use the very tight `illegal: \S` rule later to flag any other character + // - as illegal indicating that despite looking like JSON we do not truly have + // - JSON and thus improve false-positively greatly since JSON will try and claim + // - all sorts of JSON looking stuff + const LITERALS_MODE = { + scope: "literal", + beginKeywords: LITERALS.join(" "), + }; + + return { + name: 'JSON', + keywords:{ + literal: LITERALS, + }, + contains: [ + ATTRIBUTE, + PUNCTUATION, + hljs.QUOTE_STRING_MODE, + LITERALS_MODE, + hljs.C_NUMBER_MODE, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ], + illegal: '\\S' + }; + } + + return json; + +})(); + + hljs.registerLanguage('json', hljsGrammar); + })();/*! `python` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Python + Description: Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. + Website: https://www.python.org + Category: common + */ + + function python(hljs) { + const regex = hljs.regex; + const IDENT_RE = /[\p{XID_Start}_]\p{XID_Continue}*/u; + const RESERVED_WORDS = [ + 'and', + 'as', + 'assert', + 'async', + 'await', + 'break', + 'case', + 'class', + 'continue', + 'def', + 'del', + 'elif', + 'else', + 'except', + 'finally', + 'for', + 'from', + 'global', + 'if', + 'import', + 'in', + 'is', + 'lambda', + 'match', + 'nonlocal|10', + 'not', + 'or', + 'pass', + 'raise', + 'return', + 'try', + 'while', + 'with', + 'yield' + ]; + + const BUILT_INS = [ + '__import__', + 'abs', + 'all', + 'any', + 'ascii', + 'bin', + 'bool', + 'breakpoint', + 'bytearray', + 'bytes', + 'callable', + 'chr', + 'classmethod', + 'compile', + 'complex', + 'delattr', + 'dict', + 'dir', + 'divmod', + 'enumerate', + 'eval', + 'exec', + 'filter', + 'float', + 'format', + 'frozenset', + 'getattr', + 'globals', + 'hasattr', + 'hash', + 'help', + 'hex', + 'id', + 'input', + 'int', + 'isinstance', + 'issubclass', + 'iter', + 'len', + 'list', + 'locals', + 'map', + 'max', + 'memoryview', + 'min', + 'next', + 'object', + 'oct', + 'open', + 'ord', + 'pow', + 'print', + 'property', + 'range', + 'repr', + 'reversed', + 'round', + 'set', + 'setattr', + 'slice', + 'sorted', + 'staticmethod', + 'str', + 'sum', + 'super', + 'tuple', + 'type', + 'vars', + 'zip' + ]; + + const LITERALS = [ + '__debug__', + 'Ellipsis', + 'False', + 'None', + 'NotImplemented', + 'True' + ]; + + // https://docs.python.org/3/library/typing.html + // TODO: Could these be supplemented by a CamelCase matcher in certain + // contexts, leaving these remaining only for relevance hinting? + const TYPES = [ + "Any", + "Callable", + "Coroutine", + "Dict", + "List", + "Literal", + "Generic", + "Optional", + "Sequence", + "Set", + "Tuple", + "Type", + "Union" + ]; + + const KEYWORDS = { + $pattern: /[A-Za-z]\w+|__\w+__/, + keyword: RESERVED_WORDS, + built_in: BUILT_INS, + literal: LITERALS, + type: TYPES + }; + + const PROMPT = { + className: 'meta', + begin: /^(>>>|\.\.\.) / + }; + + const SUBST = { + className: 'subst', + begin: /\{/, + end: /\}/, + keywords: KEYWORDS, + illegal: /#/ + }; + + const LITERAL_BRACKET = { + begin: /\{\{/, + relevance: 0 + }; + + const STRING = { + className: 'string', + contains: [ hljs.BACKSLASH_ESCAPE ], + variants: [ + { + begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/, + end: /'''/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT + ], + relevance: 10 + }, + { + begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/, + end: /"""/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT + ], + relevance: 10 + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])'''/, + end: /'''/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT, + LITERAL_BRACKET, + SUBST + ] + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])"""/, + end: /"""/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT, + LITERAL_BRACKET, + SUBST + ] + }, + { + begin: /([uU]|[rR])'/, + end: /'/, + relevance: 10 + }, + { + begin: /([uU]|[rR])"/, + end: /"/, + relevance: 10 + }, + { + begin: /([bB]|[bB][rR]|[rR][bB])'/, + end: /'/ + }, + { + begin: /([bB]|[bB][rR]|[rR][bB])"/, + end: /"/ + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])'/, + end: /'/, + contains: [ + hljs.BACKSLASH_ESCAPE, + LITERAL_BRACKET, + SUBST + ] + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])"/, + end: /"/, + contains: [ + hljs.BACKSLASH_ESCAPE, + LITERAL_BRACKET, + SUBST + ] + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ] + }; + + // https://docs.python.org/3.9/reference/lexical_analysis.html#numeric-literals + const digitpart = '[0-9](_?[0-9])*'; + const pointfloat = `(\\b(${digitpart}))?\\.(${digitpart})|\\b(${digitpart})\\.`; + // Whitespace after a number (or any lexical token) is needed only if its absence + // would change the tokenization + // https://docs.python.org/3.9/reference/lexical_analysis.html#whitespace-between-tokens + // We deviate slightly, requiring a word boundary or a keyword + // to avoid accidentally recognizing *prefixes* (e.g., `0` in `0x41` or `08` or `0__1`) + const lookahead = `\\b|${RESERVED_WORDS.join('|')}`; + const NUMBER = { + className: 'number', + relevance: 0, + variants: [ + // exponentfloat, pointfloat + // https://docs.python.org/3.9/reference/lexical_analysis.html#floating-point-literals + // optionally imaginary + // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals + // Note: no leading \b because floats can start with a decimal point + // and we don't want to mishandle e.g. `fn(.5)`, + // no trailing \b for pointfloat because it can end with a decimal point + // and we don't want to mishandle e.g. `0..hex()`; this should be safe + // because both MUST contain a decimal point and so cannot be confused with + // the interior part of an identifier + { + begin: `(\\b(${digitpart})|(${pointfloat}))[eE][+-]?(${digitpart})[jJ]?(?=${lookahead})` + }, + { + begin: `(${pointfloat})[jJ]?` + }, + + // decinteger, bininteger, octinteger, hexinteger + // https://docs.python.org/3.9/reference/lexical_analysis.html#integer-literals + // optionally "long" in Python 2 + // https://docs.python.org/2.7/reference/lexical_analysis.html#integer-and-long-integer-literals + // decinteger is optionally imaginary + // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals + { + begin: `\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${lookahead})` + }, + { + begin: `\\b0[bB](_?[01])+[lL]?(?=${lookahead})` + }, + { + begin: `\\b0[oO](_?[0-7])+[lL]?(?=${lookahead})` + }, + { + begin: `\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${lookahead})` + }, + + // imagnumber (digitpart-based) + // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals + { + begin: `\\b(${digitpart})[jJ](?=${lookahead})` + } + ] + }; + const COMMENT_TYPE = { + className: "comment", + begin: regex.lookahead(/# type:/), + end: /$/, + keywords: KEYWORDS, + contains: [ + { // prevent keywords from coloring `type` + begin: /# type:/ + }, + // comment within a datatype comment includes no keywords + { + begin: /#/, + end: /\b\B/, + endsWithParent: true + } + ] + }; + const PARAMS = { + className: 'params', + variants: [ + // Exclude params in functions without params + { + className: "", + begin: /\(\s*\)/, + skip: true + }, + { + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS, + contains: [ + 'self', + PROMPT, + NUMBER, + STRING, + hljs.HASH_COMMENT_MODE + ] + } + ] + }; + SUBST.contains = [ + STRING, + NUMBER, + PROMPT + ]; + + return { + name: 'Python', + aliases: [ + 'py', + 'gyp', + 'ipython' + ], + unicodeRegex: true, + keywords: KEYWORDS, + illegal: /(<\/|\?)|=>/, + contains: [ + PROMPT, + NUMBER, + { + // very common convention + begin: /\bself\b/ + }, + { + // eat "if" prior to string so that it won't accidentally be + // labeled as an f-string + beginKeywords: "if", + relevance: 0 + }, + { match: /\bor\b/, scope: "keyword" }, + STRING, + COMMENT_TYPE, + hljs.HASH_COMMENT_MODE, + { + match: [ + /\bdef/, /\s+/, + IDENT_RE, + ], + scope: { + 1: "keyword", + 3: "title.function" + }, + contains: [ PARAMS ] + }, + { + variants: [ + { + match: [ + /\bclass/, /\s+/, + IDENT_RE, /\s*/, + /\(\s*/, IDENT_RE,/\s*\)/ + ], + }, + { + match: [ + /\bclass/, /\s+/, + IDENT_RE + ], + } + ], + scope: { + 1: "keyword", + 3: "title.class", + 6: "title.class.inherited", + } + }, + { + className: 'meta', + begin: /^[\t ]*@/, + end: /(?=#)|$/, + contains: [ + NUMBER, + PARAMS, + STRING + ] + } + ] + }; + } + + return python; + +})(); + + hljs.registerLanguage('python', hljsGrammar); + })();/*! `shell` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Shell Session + Requires: bash.js + Author: TSUYUSATO Kitsune + Category: common + Audit: 2020 + */ + + /** @type LanguageFn */ + function shell(hljs) { + return { + name: 'Shell Session', + aliases: [ + 'console', + 'shellsession' + ], + contains: [ + { + className: 'meta.prompt', + // We cannot add \s (spaces) in the regular expression otherwise it will be too broad and produce unexpected result. + // For instance, in the following example, it would match "echo /path/to/home >" as a prompt: + // echo /path/to/home > t.exe + begin: /^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/, + starts: { + end: /[^\\](?=\s*$)/, + subLanguage: 'bash' + } + } + ] + }; + } + + return shell; + +})(); + + hljs.registerLanguage('shell', hljsGrammar); + })();/*! `xml` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: HTML, XML + Website: https://www.w3.org/XML/ + Category: common, web + Audit: 2020 + */ + + /** @type LanguageFn */ + function xml(hljs) { + const regex = hljs.regex; + // XML names can have the following additional letters: https://www.w3.org/TR/xml/#NT-NameChar + // OTHER_NAME_CHARS = /[:\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]/; + // Element names start with NAME_START_CHAR followed by optional other Unicode letters, ASCII digits, hyphens, underscores, and periods + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/);; + // const XML_IDENT_RE = /[A-Z_a-z:\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]+/; + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/); + // however, to cater for performance and more Unicode support rely simply on the Unicode letter class + const TAG_NAME_RE = regex.concat(/[\p{L}_]/u, regex.optional(/[\p{L}0-9_.-]*:/u), /[\p{L}0-9_.-]*/u); + const XML_IDENT_RE = /[\p{L}0-9._:-]+/u; + const XML_ENTITIES = { + className: 'symbol', + begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/ + }; + const XML_META_KEYWORDS = { + begin: /\s/, + contains: [ + { + className: 'keyword', + begin: /#?[a-z_][a-z1-9_-]+/, + illegal: /\n/ + } + ] + }; + const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, { + begin: /\(/, + end: /\)/ + }); + const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, { className: 'string' }); + const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, { className: 'string' }); + const TAG_INTERNALS = { + endsWithParent: true, + illegal: /`]+/ } + ] + } + ] + } + ] + }; + return { + name: 'HTML, XML', + aliases: [ + 'html', + 'xhtml', + 'rss', + 'atom', + 'xjb', + 'xsd', + 'xsl', + 'plist', + 'wsf', + 'svg' + ], + case_insensitive: true, + unicodeRegex: true, + contains: [ + { + className: 'meta', + begin: //, + relevance: 10, + contains: [ + XML_META_KEYWORDS, + QUOTE_META_STRING_MODE, + APOS_META_STRING_MODE, + XML_META_PAR_KEYWORDS, + { + begin: /\[/, + end: /\]/, + contains: [ + { + className: 'meta', + begin: //, + contains: [ + XML_META_KEYWORDS, + XML_META_PAR_KEYWORDS, + QUOTE_META_STRING_MODE, + APOS_META_STRING_MODE + ] + } + ] + } + ] + }, + hljs.COMMENT( + //, + { relevance: 10 } + ), + { + begin: //, + relevance: 10 + }, + XML_ENTITIES, + // xml processing instructions + { + className: 'meta', + end: /\?>/, + variants: [ + { + begin: /<\?xml/, + relevance: 10, + contains: [ + QUOTE_META_STRING_MODE + ] + }, + { + begin: /<\?[a-z][a-z0-9]+/, + } + ] + + }, + { + className: 'tag', + /* + The lookahead pattern (?=...) ensures that 'begin' only matches + ')/, + end: />/, + keywords: { name: 'style' }, + contains: [ TAG_INTERNALS ], + starts: { + end: /<\/style>/, + returnEnd: true, + subLanguage: [ + 'css', + 'xml' + ] + } + }, + { + className: 'tag', + // See the comment in the - - + + A - + - + A() = default : void - + - + A(int i) : void - + - + A(A &&) = default : void - + - + A(const A &) = deleted : void A<T>(T t) : void - + - + ~A() = default : void - + - + operator=(A && other) noexcept : A & - + - + operator=(A & other) noexcept : A & - + - + operator++() : A & - + - + auto_method() : int - + - + basic_method() : void - + - + const_method() const : void - + - + create_from_int(int i) : A - + - + default_int(int i = 12) : int - + - + default_string(int i, std::string s = "abc") : std::string - + - + double_int(const int i) : int - + - + private_method() : void - + - + protected_method() : void - + - + size() constexpr const : std::size_t - + - + static_method() : int - + - + sum(const double a, const double b) : int - + - + a_ : int - + - + auto_member : const unsigned long - + - + b_ : int - + - + c_ : int - + - + compare : std::function<bool (const int)> - + - + private_member : int - + - + protected_member : int - + - + public_member : int - + - + static_const_int : const int - + - + static_int : int diff --git a/docs/test_cases/t00003_class_mermaid.svg b/docs/test_cases/t00003_class_mermaid.svg index 4a6738c4..5c2b56fc 100644 --- a/docs/test_cases/t00003_class_mermaid.svg +++ b/docs/test_cases/t00003_class_mermaid.svg @@ -52,7 +52,7 @@ - + diff --git a/docs/test_cases/t00004_class.svg b/docs/test_cases/t00004_class.svg index f33971f8..f24589e4 100644 --- a/docs/test_cases/t00004_class.svg +++ b/docs/test_cases/t00004_class.svg @@ -1,6 +1,6 @@ - + @@ -9,16 +9,16 @@ - - + + B - - + + B::AA @@ -28,38 +28,38 @@ AA_3 - - + + A - + - + foo() const : void - + - + foo2() const : void - - + + A::AA - - + + A::AA::Lights @@ -69,16 +69,16 @@ Red - - + + A::AA::AAA - - + + C::B @@ -87,8 +87,8 @@ - - + + C @@ -97,38 +97,38 @@ - + - + b_int : B<int> - + - + t : T - - + + C::AA - - + + C::AA::AAA - - + + C::AA::CCC @@ -137,8 +137,8 @@ CCC_2 - - + + C::B @@ -147,15 +147,15 @@ - + - + b : V - - + + C::CC @@ -164,16 +164,16 @@ CC_2 - - + + detail::D - - + + detail::D::AA @@ -183,8 +183,8 @@ AA_3 - - + + detail::D::DD diff --git a/docs/test_cases/t00004_class_mermaid.svg b/docs/test_cases/t00004_class_mermaid.svg index 9494860a..59e5db66 100644 --- a/docs/test_cases/t00004_class_mermaid.svg +++ b/docs/test_cases/t00004_class_mermaid.svg @@ -210,7 +210,7 @@ - + @@ -229,7 +229,7 @@ - + @@ -263,7 +263,7 @@ - + @@ -292,7 +292,7 @@ - + @@ -311,7 +311,7 @@ - + @@ -345,7 +345,7 @@ - + @@ -364,7 +364,7 @@ - + @@ -383,7 +383,7 @@ - + @@ -412,7 +412,7 @@ - + @@ -431,7 +431,7 @@ - + @@ -450,7 +450,7 @@ - + @@ -479,7 +479,7 @@ - + @@ -503,7 +503,7 @@ - + @@ -532,7 +532,7 @@ - + @@ -551,7 +551,7 @@ - + @@ -585,7 +585,7 @@ - + diff --git a/docs/test_cases/t00005_class.svg b/docs/test_cases/t00005_class.svg index 73327fe6..eefabebb 100644 --- a/docs/test_cases/t00005_class.svg +++ b/docs/test_cases/t00005_class.svg @@ -1,6 +1,6 @@ - + @@ -9,205 +9,205 @@ - - + + A - - + + B - - + + C - - + + D - - + + E - - + + F - - + + G - - + + H - - + + I - - + + J - - + + K - - + + R - + - + a : A - + - + b : B * - + - + c : C & - + - + d : const D * - + - + e : const E & - + - + f : F && - + - + g : G ** - + - + h : H *** - + - + i : I *& - + - + j : volatile J * - + - + k : K * - + - + some_int : int - + - + some_int_pointer : int * - + - + some_int_pointer_pointer : int ** - + - + some_int_reference : int & diff --git a/docs/test_cases/t00005_class_mermaid.svg b/docs/test_cases/t00005_class_mermaid.svg index a7ec1db6..14e732ff 100644 --- a/docs/test_cases/t00005_class_mermaid.svg +++ b/docs/test_cases/t00005_class_mermaid.svg @@ -186,7 +186,7 @@ - + @@ -205,7 +205,7 @@ - + @@ -224,7 +224,7 @@ - + @@ -243,7 +243,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -281,7 +281,7 @@ - + @@ -300,7 +300,7 @@ - + @@ -319,7 +319,7 @@ - + @@ -338,7 +338,7 @@ - + @@ -357,7 +357,7 @@ - + @@ -376,7 +376,7 @@ - + @@ -395,7 +395,7 @@ - + diff --git a/docs/test_cases/t00006_class.svg b/docs/test_cases/t00006_class.svg index ca4c7123..26267ffa 100644 --- a/docs/test_cases/t00006_class.svg +++ b/docs/test_cases/t00006_class.svg @@ -1,6 +1,6 @@ - + @@ -9,136 +9,136 @@ - - + + A - - + + B - - + + C - - + + D - - + + E - - + + F - - + + G - - + + H - - + + I - - + + J - - + + K - - + + L - - + + M - - + + N - - + + NN - - + + NNN - - + + custom_container @@ -147,15 +147,15 @@ - + - + data : std::vector<T> - - + + custom_container @@ -164,103 +164,103 @@ - - + + R - + - + a : std::vector<A> - + - + b : std::vector<B *> - + - + c : std::map<int,C> - + - + d : std::map<int,D *> - + - + e : custom_container<E> - + - + f : std::vector<std::vector<F>> - + - + g : std::map<int,std::vector<G *>> - + - + h : std::array<H,10> - + - + i : std::array<I *,5> - + - + j : J[10] - + - + k : K *[20] - + - + lm : std::vector<std::pair<L,M>> - + - + ns : std::tuple<N,NN,NNN> diff --git a/docs/test_cases/t00006_class_mermaid.svg b/docs/test_cases/t00006_class_mermaid.svg index 7fc9b8e1..a71a425d 100644 --- a/docs/test_cases/t00006_class_mermaid.svg +++ b/docs/test_cases/t00006_class_mermaid.svg @@ -270,7 +270,7 @@ - + @@ -289,7 +289,7 @@ - + @@ -308,7 +308,7 @@ - + @@ -327,7 +327,7 @@ - + @@ -346,7 +346,7 @@ - + @@ -365,7 +365,7 @@ - + @@ -384,7 +384,7 @@ - + @@ -403,7 +403,7 @@ - + @@ -422,7 +422,7 @@ - + @@ -441,7 +441,7 @@ - + @@ -460,7 +460,7 @@ - + @@ -479,7 +479,7 @@ - + @@ -498,7 +498,7 @@ - + @@ -517,7 +517,7 @@ - + @@ -536,7 +536,7 @@ - + @@ -555,7 +555,7 @@ - + @@ -574,7 +574,7 @@ - + @@ -598,7 +598,7 @@ - + @@ -617,7 +617,7 @@ - + diff --git a/docs/test_cases/t00007_class.svg b/docs/test_cases/t00007_class.svg index 158081ce..0f5cde04 100644 --- a/docs/test_cases/t00007_class.svg +++ b/docs/test_cases/t00007_class.svg @@ -1,6 +1,6 @@ - + @@ -9,57 +9,57 @@ - - + + A - - + + B - - + + C - - + + R - + - + a : std::unique_ptr<A> - + - + b : std::shared_ptr<B> - + - + c : std::weak_ptr<C> diff --git a/docs/test_cases/t00007_class_mermaid.svg b/docs/test_cases/t00007_class_mermaid.svg index 11c574e2..e2a15ba0 100644 --- a/docs/test_cases/t00007_class_mermaid.svg +++ b/docs/test_cases/t00007_class_mermaid.svg @@ -90,7 +90,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -147,7 +147,7 @@ - + diff --git a/docs/test_cases/t00008_class.svg b/docs/test_cases/t00008_class.svg index 1c821702..32b2cae9 100644 --- a/docs/test_cases/t00008_class.svg +++ b/docs/test_cases/t00008_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,50 +19,50 @@ - + - + comparator : CMP - + - + ints : std::array<int,N> - + - + pointer : T * - + - + reference : T & - + - + value : T - + - + values : std::vector<P> - - + + Vector @@ -71,15 +71,15 @@ - + - + values : std::vector<T> - - + + B @@ -88,15 +88,15 @@ - + - + template_template : C<T> - - + + B @@ -105,8 +105,8 @@ - - + + D @@ -115,31 +115,31 @@ D<Items...>(std::tuple<Items...> *) : void - + - + add(int i) : void - + - + ints : B<int,Vector> - - + + E - - + + E::nested_template @@ -147,16 +147,16 @@ ET - + - + get(ET * d) : DT * - - + + E::nested_template @@ -164,11 +164,11 @@ char - + - + getDecl(char * c) : DeclType * diff --git a/docs/test_cases/t00008_class_mermaid.svg b/docs/test_cases/t00008_class_mermaid.svg index 94e89a38..7cef610e 100644 --- a/docs/test_cases/t00008_class_mermaid.svg +++ b/docs/test_cases/t00008_class_mermaid.svg @@ -114,7 +114,7 @@ - + @@ -163,7 +163,7 @@ - + @@ -187,7 +187,7 @@ - + @@ -211,7 +211,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -264,7 +264,7 @@ - + @@ -283,7 +283,7 @@ - + @@ -307,7 +307,7 @@ - + diff --git a/docs/test_cases/t00009_class.svg b/docs/test_cases/t00009_class.svg index 2041ec8c..7ae0214c 100644 --- a/docs/test_cases/t00009_class.svg +++ b/docs/test_cases/t00009_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,15 +19,15 @@ - + - + value : T - - + + A @@ -36,8 +36,8 @@ - - + + A @@ -46,8 +46,8 @@ - - + + A @@ -56,33 +56,33 @@ - - + + B - + - + aint : A<int> - + - + astring : A<std::string> * - + - + avector : A<std::vector<std::string>> & diff --git a/docs/test_cases/t00009_class_mermaid.svg b/docs/test_cases/t00009_class_mermaid.svg index 0f62edb6..c921e55f 100644 --- a/docs/test_cases/t00009_class_mermaid.svg +++ b/docs/test_cases/t00009_class_mermaid.svg @@ -126,7 +126,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -169,7 +169,7 @@ - + @@ -188,7 +188,7 @@ - + @@ -207,7 +207,7 @@ - + diff --git a/docs/test_cases/t00010_class.svg b/docs/test_cases/t00010_class.svg index b06f506c..d5d21583 100644 --- a/docs/test_cases/t00010_class.svg +++ b/docs/test_cases/t00010_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,22 +19,22 @@ - + - + first : T - + - + second : P - - + + A @@ -43,8 +43,8 @@ - - + + B @@ -53,15 +53,15 @@ - + - + astring : A<T,std::string> - - + + B @@ -70,19 +70,19 @@ - - + + C - + - + aintstring : B<int> diff --git a/docs/test_cases/t00010_class_mermaid.svg b/docs/test_cases/t00010_class_mermaid.svg index 74f1a937..0974117c 100644 --- a/docs/test_cases/t00010_class_mermaid.svg +++ b/docs/test_cases/t00010_class_mermaid.svg @@ -102,7 +102,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -174,7 +174,7 @@ - + @@ -193,7 +193,7 @@ - + diff --git a/docs/test_cases/t00011_class.svg b/docs/test_cases/t00011_class.svg index d5b47987..338a6708 100644 --- a/docs/test_cases/t00011_class.svg +++ b/docs/test_cases/t00011_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + D @@ -19,48 +19,48 @@ - + - + value : T - - + + A - + - + foo() : void - - + + B - + - + foo() : void - + - + m_a : A * diff --git a/docs/test_cases/t00011_class_mermaid.svg b/docs/test_cases/t00011_class_mermaid.svg index a844eb16..bf415cb2 100644 --- a/docs/test_cases/t00011_class_mermaid.svg +++ b/docs/test_cases/t00011_class_mermaid.svg @@ -78,7 +78,7 @@ - + @@ -102,7 +102,7 @@ - + @@ -126,7 +126,7 @@ - + diff --git a/docs/test_cases/t00012_class.svg b/docs/test_cases/t00012_class.svg index ecd3417c..089dd40f 100644 --- a/docs/test_cases/t00012_class.svg +++ b/docs/test_cases/t00012_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,22 +19,22 @@ - + - + value : T - + - + values : std::variant<Ts...> - - + + B @@ -43,15 +43,15 @@ - + - + ints : std::array<int,sizeof...(Is)> - - + + C @@ -60,15 +60,15 @@ - + - + ints : std::array<T,sizeof...(Is)> - - + + A @@ -77,8 +77,8 @@ - - + + A @@ -87,8 +87,8 @@ - - + + B @@ -97,8 +97,8 @@ - - + + B @@ -107,8 +107,8 @@ - - + + C @@ -117,50 +117,50 @@ - - + + R - + - + a1 : A<int,std::string,float> - + - + a2 : A<int,std::string,bool> - + - + b1 : B<3,2,1> - + - + b2 : B<1,1,1,1> - + - + c1 : C<std::map<int,std::vector<std::vector<std::vector<std::string>>>>,3,3,3> - + Long template annotation diff --git a/docs/test_cases/t00012_class_mermaid.svg b/docs/test_cases/t00012_class_mermaid.svg index 0210cbc5..c0eba13a 100644 --- a/docs/test_cases/t00012_class_mermaid.svg +++ b/docs/test_cases/t00012_class_mermaid.svg @@ -174,7 +174,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -227,7 +227,7 @@ - + @@ -251,7 +251,7 @@ - + @@ -270,7 +270,7 @@ - + @@ -289,7 +289,7 @@ - + @@ -308,7 +308,7 @@ - + @@ -327,7 +327,7 @@ - + @@ -346,7 +346,7 @@ - + diff --git a/docs/test_cases/t00013_class.svg b/docs/test_cases/t00013_class.svg index 49f9f54d..f2962917 100644 --- a/docs/test_cases/t00013_class.svg +++ b/docs/test_cases/t00013_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + ABCD::F @@ -19,15 +19,15 @@ - + - + f : T - - + + ABCD::F @@ -36,75 +36,75 @@ - - + + A - + - + a : int - - + + B - + - + b : int - - + + C - + - + c : int - - + + D - + - + print(R * r) : void - + - + d : int - - + + E @@ -113,15 +113,15 @@ - + - + e : T - - + + G @@ -130,22 +130,22 @@ - + - + args : std::tuple<Args...> - + - + g : T - - + + E @@ -154,8 +154,8 @@ - - + + G @@ -164,8 +164,8 @@ - - + + E @@ -174,93 +174,93 @@ - - + + R - + - + get_a(A * a) : int - + - + get_b(B & b) : int - + - + get_c(C c) : int - + - + get_const_b(const B & b) : int - + - + get_d(D && d) : int - + - + get_d2(D && d) : int get_e<T>(E<T> e) : T get_f<T>(const F<T> & f) : T - + - + get_int_e(const E<int> & e) : int - + - + get_int_e2(E<int> & e) : int - + - + get_int_f(const ABCD::F<int> & f) : int - + - + estring : E<std::string> - + - + gintstring : G<int,float,std::string> diff --git a/docs/test_cases/t00013_class_mermaid.svg b/docs/test_cases/t00013_class_mermaid.svg index 4bfa5ef2..2236b38c 100644 --- a/docs/test_cases/t00013_class_mermaid.svg +++ b/docs/test_cases/t00013_class_mermaid.svg @@ -234,7 +234,7 @@ - + @@ -258,7 +258,7 @@ - + @@ -277,7 +277,7 @@ - + @@ -301,7 +301,7 @@ - + @@ -325,7 +325,7 @@ - + @@ -349,7 +349,7 @@ - + @@ -378,7 +378,7 @@ - + @@ -402,7 +402,7 @@ - + @@ -431,7 +431,7 @@ - + @@ -450,7 +450,7 @@ - + @@ -469,7 +469,7 @@ - + @@ -488,7 +488,7 @@ - + diff --git a/docs/test_cases/t00014_class.svg b/docs/test_cases/t00014_class.svg index 1427fa10..df914996 100644 --- a/docs/test_cases/t00014_class.svg +++ b/docs/test_cases/t00014_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,37 +19,37 @@ - + - + p : P - + - + t : T - - + + B - + - + value : std::string - - + + A @@ -58,8 +58,8 @@ - - + + A @@ -68,8 +68,8 @@ - - + + A @@ -78,8 +78,8 @@ - - + + A @@ -88,8 +88,8 @@ - - + + A @@ -98,8 +98,8 @@ - - + + A @@ -108,8 +108,8 @@ - - + + A @@ -118,8 +118,8 @@ - - + + A @@ -128,8 +128,8 @@ - - + + A @@ -138,8 +138,8 @@ - - + + A @@ -148,8 +148,8 @@ - - + + A @@ -158,8 +158,8 @@ - - + + A @@ -168,8 +168,8 @@ - - + + A @@ -178,7 +178,7 @@ - + A @@ -186,7 +186,7 @@ char,std::string - + A @@ -194,8 +194,8 @@ wchar_t,std::string - - + + R @@ -204,116 +204,116 @@ - + - + abool : APtr<bool> - + - + aboolfloat : AAPtr<bool,float> - + - + afloat : ASharedPtr<float> - + - + atfloat : AAPtr<T,float> - + - + bapair : PairPairBA<bool> - + - + boolstring : A<bool,std::string> - + - + bs : BVector - + - + bs2 : BVector2 - + - + bstringstring : BStringString - + - + cb : SimpleCallback<ACharString> - + - + floatstring : AStringPtr<float> - + - + gcb : GenericCallback<AWCharString> - + - + intstring : AIntString - + - + stringstring : AStringString - + - + vcb : VoidCallback - + - + vps : VectorPtr<B> diff --git a/docs/test_cases/t00014_class_mermaid.svg b/docs/test_cases/t00014_class_mermaid.svg index 7ec22149..ff1e52f9 100644 --- a/docs/test_cases/t00014_class_mermaid.svg +++ b/docs/test_cases/t00014_class_mermaid.svg @@ -474,7 +474,7 @@ - + @@ -503,7 +503,7 @@ - + @@ -527,7 +527,7 @@ - + @@ -546,7 +546,7 @@ - + @@ -565,7 +565,7 @@ - + @@ -584,7 +584,7 @@ - + @@ -603,7 +603,7 @@ - + @@ -622,7 +622,7 @@ - + @@ -641,7 +641,7 @@ - + @@ -660,7 +660,7 @@ - + @@ -679,7 +679,7 @@ - + @@ -698,7 +698,7 @@ - + @@ -717,7 +717,7 @@ - + @@ -736,7 +736,7 @@ - + @@ -755,7 +755,7 @@ - + @@ -774,7 +774,7 @@ - + @@ -793,7 +793,7 @@ - + @@ -812,7 +812,7 @@ - + diff --git a/docs/test_cases/t00015_class.svg b/docs/test_cases/t00015_class.svg index 6385f0e2..4ffa62ee 100644 --- a/docs/test_cases/t00015_class.svg +++ b/docs/test_cases/t00015_class.svg @@ -1,6 +1,6 @@ - + @@ -9,40 +9,40 @@ - - + + ns1::A - - + + ns1::ns2_v0_9_0::A - - + + ns1::Anon - - + + ns3::ns1::ns2::Anon - - + + ns3::B diff --git a/docs/test_cases/t00015_class_mermaid.svg b/docs/test_cases/t00015_class_mermaid.svg index 5b7c4b34..e6b9fed5 100644 --- a/docs/test_cases/t00015_class_mermaid.svg +++ b/docs/test_cases/t00015_class_mermaid.svg @@ -84,7 +84,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -122,7 +122,7 @@ - + @@ -141,7 +141,7 @@ - + @@ -160,7 +160,7 @@ - + diff --git a/docs/test_cases/t00016_class.svg b/docs/test_cases/t00016_class.svg index 527c212e..022a4d4c 100644 --- a/docs/test_cases/t00016_class.svg +++ b/docs/test_cases/t00016_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + is_numeric @@ -21,8 +21,8 @@ value : enum - - + + is_numeric @@ -33,8 +33,8 @@ value : enum - - + + is_numeric @@ -45,8 +45,8 @@ value : enum - - + + is_numeric @@ -57,8 +57,8 @@ value : enum - - + + is_numeric @@ -69,8 +69,8 @@ value : enum - - + + is_numeric diff --git a/docs/test_cases/t00016_class_mermaid.svg b/docs/test_cases/t00016_class_mermaid.svg index 5a059006..786430a0 100644 --- a/docs/test_cases/t00016_class_mermaid.svg +++ b/docs/test_cases/t00016_class_mermaid.svg @@ -114,7 +114,7 @@ - + @@ -138,7 +138,7 @@ - + @@ -162,7 +162,7 @@ - + @@ -186,7 +186,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -234,7 +234,7 @@ - + diff --git a/docs/test_cases/t00017_class.svg b/docs/test_cases/t00017_class.svg index 3b668f6d..5a22057f 100644 --- a/docs/test_cases/t00017_class.svg +++ b/docs/test_cases/t00017_class.svg @@ -1,6 +1,6 @@ - + @@ -9,135 +9,135 @@ - - + + A - - + + B - - + + C - - + + D - - + + E - - + + F - - + + G - - + + H - - + + I - - + + J - - + + K - - + + R - + - + R(int & some_int, C & cc, const E & ee, F && ff, I *& ii) : void - + - + some_int : int - + - + some_int_pointer : int * - + - + some_int_pointer_pointer : int ** - + - + some_int_reference : int & diff --git a/docs/test_cases/t00017_class_mermaid.svg b/docs/test_cases/t00017_class_mermaid.svg index fa1ab9a9..c064f02c 100644 --- a/docs/test_cases/t00017_class_mermaid.svg +++ b/docs/test_cases/t00017_class_mermaid.svg @@ -186,7 +186,7 @@ - + @@ -205,7 +205,7 @@ - + @@ -224,7 +224,7 @@ - + @@ -243,7 +243,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -281,7 +281,7 @@ - + @@ -300,7 +300,7 @@ - + @@ -319,7 +319,7 @@ - + @@ -338,7 +338,7 @@ - + @@ -357,7 +357,7 @@ - + @@ -376,7 +376,7 @@ - + @@ -395,7 +395,7 @@ - + diff --git a/docs/test_cases/t00018_class.svg b/docs/test_cases/t00018_class.svg index 6236de28..1811b9a1 100644 --- a/docs/test_cases/t00018_class.svg +++ b/docs/test_cases/t00018_class.svg @@ -1,6 +1,6 @@ - + @@ -9,121 +9,121 @@ - - + + impl::widget - + - + widget(int n) : void - + - + draw(const widget & w) const : void - + - + draw(const widget & w) : void - + - + n : int - - + + widget - + - + widget(int) : void - + - + widget(widget &&) : void - + - + widget(const widget &) = deleted : void - + - + ~widget() : void - + - + operator=(widget &&) : widget & - + - + operator=(const widget &) = deleted : widget & - + - + draw() const : void - + - + draw() : void - + - + shown() const : bool - + - + pImpl : std::unique_ptr<impl::widget> diff --git a/docs/test_cases/t00018_class_mermaid.svg b/docs/test_cases/t00018_class_mermaid.svg index c96b9737..144f83a9 100644 --- a/docs/test_cases/t00018_class_mermaid.svg +++ b/docs/test_cases/t00018_class_mermaid.svg @@ -78,7 +78,7 @@ - + @@ -117,7 +117,7 @@ - + diff --git a/docs/test_cases/t00019_class.svg b/docs/test_cases/t00019_class.svg index 75c61578..5f51ed9d 100644 --- a/docs/test_cases/t00019_class.svg +++ b/docs/test_cases/t00019_class.svg @@ -1,6 +1,6 @@ - + @@ -9,45 +9,45 @@ - - + + Base - + - + Base() = default : void - + - + ~Base() constexpr = default : void - + - + m1() : int - + - + m2() : std::string - - + + Layer1 @@ -55,23 +55,23 @@ LowerLayer - + - + m1() : int - + - + m2() : std::string - - + + Layer2 @@ -79,16 +79,16 @@ LowerLayer - + - + all_calls_count() const : int - - + + Layer3 @@ -96,50 +96,50 @@ LowerLayer - + - + m1() : int - + - + m1_calls() const : int - + - + m2() : std::string - + - + m2_calls() const : int - + - + m_m1_calls : int - + - + m_m2_calls : int - + Layer3 @@ -147,7 +147,7 @@ Base - + Layer2 @@ -155,7 +155,7 @@ Layer3<Base> - + Layer1 @@ -163,19 +163,19 @@ Layer2<Layer3<Base>> - - + + A - + - + layers : std::unique_ptr<Layer1<Layer2<Layer3<Base>>>> diff --git a/docs/test_cases/t00019_class_mermaid.svg b/docs/test_cases/t00019_class_mermaid.svg index 1fe8bb4b..51df1183 100644 --- a/docs/test_cases/t00019_class_mermaid.svg +++ b/docs/test_cases/t00019_class_mermaid.svg @@ -132,7 +132,7 @@ - + @@ -171,7 +171,7 @@ - + @@ -200,7 +200,7 @@ - + @@ -224,7 +224,7 @@ - + @@ -273,7 +273,7 @@ - + @@ -292,7 +292,7 @@ - + @@ -311,7 +311,7 @@ - + @@ -330,7 +330,7 @@ - + diff --git a/docs/test_cases/t00020_class.svg b/docs/test_cases/t00020_class.svg index 4182545a..0fef0b72 100644 --- a/docs/test_cases/t00020_class.svg +++ b/docs/test_cases/t00020_class.svg @@ -1,6 +1,6 @@ - + @@ -9,175 +9,175 @@ - - + + ProductA - + - + ~ProductA() constexpr = default : void - + - + sell(int price) const = 0 : bool - - + + ProductA1 - + - + sell(int price) const : bool - - + + ProductA2 - + - + sell(int price) const : bool - - + + ProductB - + - + ~ProductB() constexpr = default : void - + - + buy(int price) const = 0 : bool - - + + ProductB1 - + - + buy(int price) const : bool - - + + ProductB2 - + - + buy(int price) const : bool - - + + AbstractFactory - + - + make_a() const = 0 : std::unique_ptr<ProductA> - + - + make_b() const = 0 : std::unique_ptr<ProductB> - - + + Factory1 - + - + make_a() const : std::unique_ptr<ProductA> - + - + make_b() const : std::unique_ptr<ProductB> - - + + Factory2 - + - + make_a() const : std::unique_ptr<ProductA> - + - + make_b() const : std::unique_ptr<ProductB> diff --git a/docs/test_cases/t00020_class_mermaid.svg b/docs/test_cases/t00020_class_mermaid.svg index 7d5aea7d..a36f7233 100644 --- a/docs/test_cases/t00020_class_mermaid.svg +++ b/docs/test_cases/t00020_class_mermaid.svg @@ -186,7 +186,7 @@ - + @@ -215,7 +215,7 @@ - + @@ -239,7 +239,7 @@ - + @@ -263,7 +263,7 @@ - + @@ -292,7 +292,7 @@ - + @@ -316,7 +316,7 @@ - + @@ -340,7 +340,7 @@ - + @@ -369,7 +369,7 @@ - + @@ -398,7 +398,7 @@ - + diff --git a/docs/test_cases/t00021_class.svg b/docs/test_cases/t00021_class.svg index da33af35..a1a8f06b 100644 --- a/docs/test_cases/t00021_class.svg +++ b/docs/test_cases/t00021_class.svg @@ -1,6 +1,6 @@ - + @@ -9,152 +9,152 @@ - - + + Visitor - + - + ~Visitor() constexpr = default : void - + - + visit_A(const A & item) const = 0 : void - + - + visit_B(const B & item) const = 0 : void - - + + Visitor1 - + - + visit_A(const A & item) const : void - + - + visit_B(const B & item) const : void - - + + Visitor2 - + - + visit_A(const A & item) const : void - + - + visit_B(const B & item) const : void - - + + Visitor3 - + - + visit_A(const A & item) const : void - + - + visit_B(const B & item) const : void - - + + Item - + - + ~Item() constexpr = default : void - + - + accept(const Visitor & visitor) const = 0 : void - - + + A - + - + accept(const Visitor & visitor) const : void - - + + B - + - + accept(const Visitor & visitor) const : void diff --git a/docs/test_cases/t00021_class_mermaid.svg b/docs/test_cases/t00021_class_mermaid.svg index 3728fc7b..3d4f3dd1 100644 --- a/docs/test_cases/t00021_class_mermaid.svg +++ b/docs/test_cases/t00021_class_mermaid.svg @@ -236,7 +236,7 @@ - + @@ -270,7 +270,7 @@ - + @@ -299,7 +299,7 @@ - + @@ -328,7 +328,7 @@ - + @@ -357,7 +357,7 @@ - + @@ -386,7 +386,7 @@ - + @@ -410,7 +410,7 @@ - + diff --git a/docs/test_cases/t00022_class.svg b/docs/test_cases/t00022_class.svg index e3e76a41..a1066901 100644 --- a/docs/test_cases/t00022_class.svg +++ b/docs/test_cases/t00022_class.svg @@ -1,6 +1,6 @@ - + @@ -9,76 +9,76 @@ - - + + A - + - + method1() = 0 : void - + - + method2() = 0 : void - + - + template_method() : void - - + + A1 - + - + method1() : void - + - + method2() : void - - + + A2 - + - + method1() : void - + - + method2() : void diff --git a/docs/test_cases/t00022_class_mermaid.svg b/docs/test_cases/t00022_class_mermaid.svg index be388cd2..413edf1c 100644 --- a/docs/test_cases/t00022_class_mermaid.svg +++ b/docs/test_cases/t00022_class_mermaid.svg @@ -74,7 +74,7 @@ - + @@ -108,7 +108,7 @@ - + @@ -137,7 +137,7 @@ - + diff --git a/docs/test_cases/t00023_class.svg b/docs/test_cases/t00023_class.svg index 3a600f36..a9135c99 100644 --- a/docs/test_cases/t00023_class.svg +++ b/docs/test_cases/t00023_class.svg @@ -1,6 +1,6 @@ - + @@ -9,102 +9,102 @@ - - + + Strategy - + - + ~Strategy() constexpr = default : void - + - + algorithm() = 0 : void - - + + StrategyA - + - + algorithm() : void - - + + StrategyB - + - + algorithm() : void - - + + StrategyC - + - + algorithm() : void - - + + Context - + - + Context(std::unique_ptr<Strategy> strategy) : void - + - + apply() : void - + - + m_strategy : std::unique_ptr<Strategy> diff --git a/docs/test_cases/t00023_class_mermaid.svg b/docs/test_cases/t00023_class_mermaid.svg index 6858b72c..8852708c 100644 --- a/docs/test_cases/t00023_class_mermaid.svg +++ b/docs/test_cases/t00023_class_mermaid.svg @@ -96,7 +96,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -149,7 +149,7 @@ - + @@ -173,7 +173,7 @@ - + @@ -197,7 +197,7 @@ - + diff --git a/docs/test_cases/t00024_class.svg b/docs/test_cases/t00024_class.svg index aed0df12..ea188ba4 100644 --- a/docs/test_cases/t00024_class.svg +++ b/docs/test_cases/t00024_class.svg @@ -1,6 +1,6 @@ - + @@ -9,115 +9,115 @@ - - + + Target - + - + ~Target() = 0 : void - + - + m1() = 0 : void - + - + m2() = 0 : void - - + + Target1 - + - + m1() : void - + - + m2() : void - - + + Target2 - + - + m1() : void - + - + m2() : void - - + + Proxy - + - + Proxy(std::shared_ptr<Target> target) : void - + - + m1() : void - + - + m2() : void - + - + m_target : std::shared_ptr<Target> diff --git a/docs/test_cases/t00024_class_mermaid.svg b/docs/test_cases/t00024_class_mermaid.svg index 1d0e73f8..692e1e88 100644 --- a/docs/test_cases/t00024_class_mermaid.svg +++ b/docs/test_cases/t00024_class_mermaid.svg @@ -96,7 +96,7 @@ - + @@ -130,7 +130,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -188,7 +188,7 @@ - + diff --git a/docs/test_cases/t00025_class.svg b/docs/test_cases/t00025_class.svg index b94cf7bf..1227a2f4 100644 --- a/docs/test_cases/t00025_class.svg +++ b/docs/test_cases/t00025_class.svg @@ -1,6 +1,6 @@ - + @@ -9,52 +9,52 @@ - - + + Target1 - + - + m1() : void - + - + m2() : void - - + + Target2 - + - + m1() : void - + - + m2() : void - - + + Proxy @@ -62,38 +62,38 @@ T - + - + Proxy(std::shared_ptr<T> target) : void - + - + m1() : void - + - + m2() : void - + - + m_target : std::shared_ptr<T> - - + + Proxy @@ -102,8 +102,8 @@ - - + + Proxy @@ -112,26 +112,26 @@ - - + + ProxyHolder - + - + proxy1 : Proxy<Target1> - + - + proxy2 : Proxy<Target2> diff --git a/docs/test_cases/t00025_class_mermaid.svg b/docs/test_cases/t00025_class_mermaid.svg index 2529af52..4d28ec6c 100644 --- a/docs/test_cases/t00025_class_mermaid.svg +++ b/docs/test_cases/t00025_class_mermaid.svg @@ -126,7 +126,7 @@ - + @@ -155,7 +155,7 @@ - + @@ -184,7 +184,7 @@ - + @@ -223,7 +223,7 @@ - + @@ -242,7 +242,7 @@ - + @@ -261,7 +261,7 @@ - + diff --git a/docs/test_cases/t00026_class.svg b/docs/test_cases/t00026_class.svg index 7ddddf6e..0873afc8 100644 --- a/docs/test_cases/t00026_class.svg +++ b/docs/test_cases/t00026_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + Memento @@ -18,31 +18,31 @@ T - + - + Memento(T && v) : void - + - + value() const : T - + - + m_value : T - - + + Originator @@ -50,52 +50,52 @@ T - + - + Originator(T && v) : void - + - + load(const Memento<T> & m) : void - + - + memoize_value() const : Memento<T> - + - + print() const : void - + - + set(T && v) : void - + - + m_value : T - - + + Caretaker @@ -103,30 +103,30 @@ T - + - + set_state(const std::string & s, Memento<T> && m) : void - + - + state(const std::string & n) : Memento<T> & - + - + m_mementos : std::unordered_map<std::string,Memento<T>> - - + + Caretaker @@ -135,8 +135,8 @@ - - + + Originator @@ -145,26 +145,26 @@ - - + + StringMemento - + - + caretaker : Caretaker<std::string> - + - + originator : Originator<std::string> diff --git a/docs/test_cases/t00026_class_mermaid.svg b/docs/test_cases/t00026_class_mermaid.svg index 8d25ef1d..94b6e471 100644 --- a/docs/test_cases/t00026_class_mermaid.svg +++ b/docs/test_cases/t00026_class_mermaid.svg @@ -126,7 +126,7 @@ - + @@ -160,7 +160,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -243,7 +243,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -281,7 +281,7 @@ - + diff --git a/docs/test_cases/t00027_class.svg b/docs/test_cases/t00027_class.svg index 87dbdca8..a7255699 100644 --- a/docs/test_cases/t00027_class.svg +++ b/docs/test_cases/t00027_class.svg @@ -1,6 +1,6 @@ - + @@ -9,39 +9,39 @@ - - + + Shape - + - + ~Shape() constexpr = default : void - + - + display() = 0 : void - - + + Line - - + + Line @@ -49,24 +49,24 @@ T<>... - + - + display() : void - - + + Text - - + + Text @@ -74,31 +74,31 @@ T<>... - + - + display() : void - - + + ShapeDecorator - + - + display() = 0 : void - - + + Color @@ -106,16 +106,16 @@ T - + - + display() : void - - + + Weight @@ -123,16 +123,16 @@ T - + - + display() : void - - + + Line @@ -141,8 +141,8 @@ - - + + Line @@ -151,8 +151,8 @@ - - + + Text @@ -161,8 +161,8 @@ - - + + Text @@ -171,40 +171,40 @@ - - + + Window - + - + border : Line<Color,Weight> - + - + description : Text<Color> - + - + divider : Line<Color> - + - + title : Text<Color,Weight> diff --git a/docs/test_cases/t00027_class_mermaid.svg b/docs/test_cases/t00027_class_mermaid.svg index 813e3def..21eed449 100644 --- a/docs/test_cases/t00027_class_mermaid.svg +++ b/docs/test_cases/t00027_class_mermaid.svg @@ -190,7 +190,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -238,7 +238,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -281,7 +281,7 @@ - + @@ -305,7 +305,7 @@ - + @@ -329,7 +329,7 @@ - + @@ -353,7 +353,7 @@ - + @@ -377,7 +377,7 @@ - + @@ -396,7 +396,7 @@ - + @@ -415,7 +415,7 @@ - + @@ -434,7 +434,7 @@ - + @@ -453,7 +453,7 @@ - + diff --git a/docs/test_cases/t00028_class.svg b/docs/test_cases/t00028_class.svg index 13f857c4..f549dffe 100644 --- a/docs/test_cases/t00028_class.svg +++ b/docs/test_cases/t00028_class.svg @@ -1,6 +1,6 @@ - + @@ -9,54 +9,54 @@ - - + + A - + A class note. - - + + B - + B class note. - - + + C - + C class note. - - + + D - + D class note. - - + + E @@ -65,26 +65,26 @@ - + - + param : T - + E template class note. - - + + G - - + + F @@ -94,11 +94,11 @@ three - + F enum note. - - + + E @@ -107,70 +107,70 @@ - - + + R - + - + R(C & c) : void - + - + aaa : A - + - + bbb : B * - + - + ccc : C & - + - + ddd : std::vector<std::shared_ptr<D>> - + - + eee : E<int> - + - + ggg : G ** - + R class note. - + R contains an instance of A. - + Reference to C. diff --git a/docs/test_cases/t00028_class_mermaid.svg b/docs/test_cases/t00028_class_mermaid.svg index ed94bcd5..8642531e 100644 --- a/docs/test_cases/t00028_class_mermaid.svg +++ b/docs/test_cases/t00028_class_mermaid.svg @@ -218,7 +218,7 @@ - + @@ -237,7 +237,7 @@ - + @@ -256,7 +256,7 @@ - + @@ -275,7 +275,7 @@ - + @@ -294,7 +294,7 @@ - + @@ -318,7 +318,7 @@ - + @@ -337,7 +337,7 @@ - + @@ -371,7 +371,7 @@ - + @@ -390,7 +390,7 @@ - + diff --git a/docs/test_cases/t00029_class.svg b/docs/test_cases/t00029_class.svg index d24ed9c7..1ce06069 100644 --- a/docs/test_cases/t00029_class.svg +++ b/docs/test_cases/t00029_class.svg @@ -1,6 +1,6 @@ - + @@ -9,16 +9,16 @@ - - + + A - - + + C @@ -27,30 +27,30 @@ - + - + param : T - - + + D - + - + param : T - - + + E @@ -60,65 +60,65 @@ three - - + + G1 - - + + G2 - - + + G3 - - + + G4 - - + + R - + - + g1 : G1 - + - + g3 : G3 & - + - + g4 : std::shared_ptr<G4> diff --git a/docs/test_cases/t00029_class_mermaid.svg b/docs/test_cases/t00029_class_mermaid.svg index 3f77ea70..187538e4 100644 --- a/docs/test_cases/t00029_class_mermaid.svg +++ b/docs/test_cases/t00029_class_mermaid.svg @@ -78,7 +78,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -145,7 +145,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -198,7 +198,7 @@ - + @@ -217,7 +217,7 @@ - + @@ -236,7 +236,7 @@ - + @@ -255,7 +255,7 @@ - + diff --git a/docs/test_cases/t00030_class.svg b/docs/test_cases/t00030_class.svg index a37c35dc..08a001a7 100644 --- a/docs/test_cases/t00030_class.svg +++ b/docs/test_cases/t00030_class.svg @@ -1,6 +1,6 @@ - + @@ -9,87 +9,87 @@ - - + + A - - + + B - - + + C - - + + D - - + + E - - + + R - + - + aaa : A - + - + bbb : std::vector<B> - + - + ccc : std::vector<C> - + - + ddd : D - + - + eee : E * diff --git a/docs/test_cases/t00030_class_mermaid.svg b/docs/test_cases/t00030_class_mermaid.svg index 491b8b0a..339382e3 100644 --- a/docs/test_cases/t00030_class_mermaid.svg +++ b/docs/test_cases/t00030_class_mermaid.svg @@ -164,7 +164,7 @@ - + @@ -183,7 +183,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -221,7 +221,7 @@ - + @@ -240,7 +240,7 @@ - + @@ -259,7 +259,7 @@ - + diff --git a/docs/test_cases/t00031_class.svg b/docs/test_cases/t00031_class.svg index 193abfc5..8f98cd9d 100644 --- a/docs/test_cases/t00031_class.svg +++ b/docs/test_cases/t00031_class.svg @@ -1,33 +1,33 @@ - + - + - + - - - + + + A - - + + B @@ -37,8 +37,8 @@ three - - + + @@ -48,23 +48,23 @@ - + - + ttt : T - - + + D - - + + C @@ -73,47 +73,47 @@ - - + + R - + - + add_b(B b) : void - + - + aaa : A * - + - + bbb : std::vector<B> - + - + ccc : C<int> - + - + ddd : D * diff --git a/docs/test_cases/t00031_class_mermaid.svg b/docs/test_cases/t00031_class_mermaid.svg index 4e2c2a00..4d5a5aa2 100644 --- a/docs/test_cases/t00031_class_mermaid.svg +++ b/docs/test_cases/t00031_class_mermaid.svg @@ -126,7 +126,7 @@ - + @@ -145,7 +145,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -241,7 +241,7 @@ - + diff --git a/docs/test_cases/t00032_class.svg b/docs/test_cases/t00032_class.svg index d8692228..c232241c 100644 --- a/docs/test_cases/t00032_class.svg +++ b/docs/test_cases/t00032_class.svg @@ -1,6 +1,6 @@ - + @@ -9,69 +9,69 @@ - - + + Base - - + + TBase - - + + A - + - + operator()() : void - - + + B - + - + operator()() : void - - + + C - + - + operator()() : void - - + + Overload @@ -80,15 +80,15 @@ - + - + counter : L - - + + Overload @@ -97,19 +97,19 @@ - - + + R - + - + overload : Overload<TBase,int,A,B,C> diff --git a/docs/test_cases/t00032_class_mermaid.svg b/docs/test_cases/t00032_class_mermaid.svg index da665b10..d100116d 100644 --- a/docs/test_cases/t00032_class_mermaid.svg +++ b/docs/test_cases/t00032_class_mermaid.svg @@ -128,7 +128,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -166,7 +166,7 @@ - + @@ -190,7 +190,7 @@ - + @@ -214,7 +214,7 @@ - + @@ -238,7 +238,7 @@ - + @@ -262,7 +262,7 @@ - + @@ -281,7 +281,7 @@ - + diff --git a/docs/test_cases/t00033_class.svg b/docs/test_cases/t00033_class.svg index 50ea3b9d..ab5b8e66 100644 --- a/docs/test_cases/t00033_class.svg +++ b/docs/test_cases/t00033_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,15 +19,15 @@ - + - + aaa : T - - + + B @@ -36,15 +36,15 @@ - + - + bbb : T - - + + C @@ -53,30 +53,30 @@ - + - + ccc : T - - + + D - + - + ddd : int - - + + C @@ -85,8 +85,8 @@ - - + + B @@ -95,8 +95,8 @@ - - + + A @@ -105,19 +105,19 @@ - - + + R - + - + abc : A<B<std::unique_ptr<C<D>>>> diff --git a/docs/test_cases/t00033_class_mermaid.svg b/docs/test_cases/t00033_class_mermaid.svg index 19b7b8c9..724e1dfc 100644 --- a/docs/test_cases/t00033_class_mermaid.svg +++ b/docs/test_cases/t00033_class_mermaid.svg @@ -138,7 +138,7 @@ - + @@ -162,7 +162,7 @@ - + @@ -186,7 +186,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -234,7 +234,7 @@ - + @@ -253,7 +253,7 @@ - + @@ -272,7 +272,7 @@ - + @@ -291,7 +291,7 @@ - + diff --git a/docs/test_cases/t00034_class.svg b/docs/test_cases/t00034_class.svg index 4bff4d5b..61a6448f 100644 --- a/docs/test_cases/t00034_class.svg +++ b/docs/test_cases/t00034_class.svg @@ -1,6 +1,6 @@ - + @@ -9,30 +9,30 @@ - - + + Void - + - + operator!=(const Void &) constexpr const : bool - + - + operator==(const Void &) constexpr const : bool - - + + lift_void @@ -41,8 +41,8 @@ - - + + lift_void @@ -51,8 +51,8 @@ - - + + drop_void @@ -61,8 +61,8 @@ - - + + drop_void @@ -71,34 +71,34 @@ - - + + A - - + + R - + - + la : lift_void_t<A> * - + - + lv : lift_void_t<void> * diff --git a/docs/test_cases/t00034_class_mermaid.svg b/docs/test_cases/t00034_class_mermaid.svg index 02fcdc6f..fc564e3d 100644 --- a/docs/test_cases/t00034_class_mermaid.svg +++ b/docs/test_cases/t00034_class_mermaid.svg @@ -102,7 +102,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -169,7 +169,7 @@ - + @@ -188,7 +188,7 @@ - + @@ -207,7 +207,7 @@ - + @@ -226,7 +226,7 @@ - + diff --git a/docs/test_cases/t00035_class.svg b/docs/test_cases/t00035_class.svg index f58015e4..7be743fa 100644 --- a/docs/test_cases/t00035_class.svg +++ b/docs/test_cases/t00035_class.svg @@ -1,6 +1,6 @@ - + @@ -9,40 +9,40 @@ - - + + Top - - + + Left - - + + Center - - + + Bottom - - + + Right diff --git a/docs/test_cases/t00035_class_mermaid.svg b/docs/test_cases/t00035_class_mermaid.svg index 68f5bb48..15497fba 100644 --- a/docs/test_cases/t00035_class_mermaid.svg +++ b/docs/test_cases/t00035_class_mermaid.svg @@ -52,7 +52,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -128,7 +128,7 @@ - + diff --git a/docs/test_cases/t00036_class.svg b/docs/test_cases/t00036_class.svg index 11ce1d07..eac601a5 100644 --- a/docs/test_cases/t00036_class.svg +++ b/docs/test_cases/t00036_class.svg @@ -1,6 +1,6 @@ - + @@ -9,23 +9,23 @@ - + ns1 - + ns11 - + ns111 - + ns2 - + ns22 - - + + E @@ -34,8 +34,8 @@ yellow - - + + A @@ -44,15 +44,15 @@ - + - + a : T - - + + A @@ -61,23 +61,23 @@ - - + + B - + - + a_int : A<int> - - + + C diff --git a/docs/test_cases/t00036_class_mermaid.svg b/docs/test_cases/t00036_class_mermaid.svg index 29b3608d..51df7ec6 100644 --- a/docs/test_cases/t00036_class_mermaid.svg +++ b/docs/test_cases/t00036_class_mermaid.svg @@ -78,7 +78,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -131,7 +131,7 @@ - + @@ -155,7 +155,7 @@ - + @@ -174,7 +174,7 @@ - + diff --git a/docs/test_cases/t00037_class.svg b/docs/test_cases/t00037_class.svg index 9872ed54..692ba2a5 100644 --- a/docs/test_cases/t00037_class.svg +++ b/docs/test_cases/t00037_class.svg @@ -1,6 +1,6 @@ - + @@ -9,106 +9,106 @@ - - + + ST - + - + dimensions : ST::(anonymous_662) - + - + units : ST::(anonymous_792) - - + + ST::(dimensions) - + - + t : double - + - + x : double - + - + y : double - + - + z : double - - + + ST::(units) - + - + c : double - + - + h : double - - + + A - + - + A() : void - + - + st : ST diff --git a/docs/test_cases/t00037_class_mermaid.svg b/docs/test_cases/t00037_class_mermaid.svg index 92c60481..b0c4773f 100644 --- a/docs/test_cases/t00037_class_mermaid.svg +++ b/docs/test_cases/t00037_class_mermaid.svg @@ -90,7 +90,7 @@ - + @@ -119,7 +119,7 @@ - + @@ -158,7 +158,7 @@ - + @@ -187,7 +187,7 @@ - + diff --git a/docs/test_cases/t00038_class.svg b/docs/test_cases/t00038_class.svg index 8f3acff9..801b958a 100644 --- a/docs/test_cases/t00038_class.svg +++ b/docs/test_cases/t00038_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + thirdparty::ns1::color_t @@ -20,16 +20,16 @@ blue - - + + thirdparty::ns1::E - - + + property_t @@ -39,47 +39,47 @@ property_c - - + + A - - + + B - - + + C - - + + key_t - + - + key : std::string - - + + map @@ -88,8 +88,8 @@ - - + + map @@ -98,8 +98,8 @@ - - + + map @@ -108,8 +108,8 @@ - - + + map @@ -118,8 +118,8 @@ - - + + map diff --git a/docs/test_cases/t00038_class_mermaid.svg b/docs/test_cases/t00038_class_mermaid.svg index ea1bdd4a..50ff9d15 100644 --- a/docs/test_cases/t00038_class_mermaid.svg +++ b/docs/test_cases/t00038_class_mermaid.svg @@ -202,7 +202,7 @@ - + @@ -236,7 +236,7 @@ - + @@ -255,7 +255,7 @@ - + @@ -289,7 +289,7 @@ - + @@ -308,7 +308,7 @@ - + @@ -327,7 +327,7 @@ - + @@ -346,7 +346,7 @@ - + @@ -370,7 +370,7 @@ - + @@ -389,7 +389,7 @@ - + @@ -408,7 +408,7 @@ - + @@ -427,7 +427,7 @@ - + @@ -446,7 +446,7 @@ - + diff --git a/docs/test_cases/t00039_class.svg b/docs/test_cases/t00039_class.svg index 799f9603..702b662c 100644 --- a/docs/test_cases/t00039_class.svg +++ b/docs/test_cases/t00039_class.svg @@ -1,6 +1,6 @@ - + @@ -9,95 +9,95 @@ - - + + C - - + + D - - + + E - - + + CD - - + + DE - - + + CDE - - + + A - - + + AA - - + + AAA - + - + b : B * - - + + ns2::AAAA - - + + ns3::F @@ -106,15 +106,15 @@ - + - + t : T * - - + + ns3::FF @@ -123,15 +123,15 @@ - + - + m : M * - - + + ns3::FE @@ -140,15 +140,15 @@ - + - + m : M * - - + + ns3::FFF @@ -157,11 +157,11 @@ - + - + n : N * diff --git a/docs/test_cases/t00039_class_mermaid.svg b/docs/test_cases/t00039_class_mermaid.svg index 1b69f629..fc5e0def 100644 --- a/docs/test_cases/t00039_class_mermaid.svg +++ b/docs/test_cases/t00039_class_mermaid.svg @@ -184,7 +184,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -241,7 +241,7 @@ - + @@ -260,7 +260,7 @@ - + @@ -279,7 +279,7 @@ - + @@ -298,7 +298,7 @@ - + @@ -317,7 +317,7 @@ - + @@ -336,7 +336,7 @@ - + @@ -360,7 +360,7 @@ - + @@ -379,7 +379,7 @@ - + @@ -403,7 +403,7 @@ - + @@ -427,7 +427,7 @@ - + @@ -451,7 +451,7 @@ - + diff --git a/docs/test_cases/t00040_class.svg b/docs/test_cases/t00040_class.svg index f34bfaba..2a814796 100644 --- a/docs/test_cases/t00040_class.svg +++ b/docs/test_cases/t00040_class.svg @@ -1,6 +1,6 @@ - + @@ -9,70 +9,70 @@ - - + + A - + - + get_a() : int - + - + ii_ : int - - + + AA - - + + AAA - + - + get_aaa() : int - + - + b : B * - - + + R - + - + foo(A * a) : void diff --git a/docs/test_cases/t00040_class_mermaid.svg b/docs/test_cases/t00040_class_mermaid.svg index fdbd067f..1e6902e4 100644 --- a/docs/test_cases/t00040_class_mermaid.svg +++ b/docs/test_cases/t00040_class_mermaid.svg @@ -74,7 +74,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -122,7 +122,7 @@ - + @@ -151,7 +151,7 @@ - + diff --git a/docs/test_cases/t00041_class.svg b/docs/test_cases/t00041_class.svg index 8f2803d7..9263c8fd 100644 --- a/docs/test_cases/t00041_class.svg +++ b/docs/test_cases/t00041_class.svg @@ -1,6 +1,6 @@ - + @@ -9,107 +9,107 @@ - - + + R - - + + D - + - + rr : RR * - - + + E - - + + F - - + + RR - + - + foo(H * h) : void - + - + e : E * - + - + f : F * - + - + g : detail::G * - - + + RRR - - + + ns1::N - - + + ns1::NN - - + + ns1::NM diff --git a/docs/test_cases/t00041_class_mermaid.svg b/docs/test_cases/t00041_class_mermaid.svg index 7516728a..1dd8d20f 100644 --- a/docs/test_cases/t00041_class_mermaid.svg +++ b/docs/test_cases/t00041_class_mermaid.svg @@ -130,7 +130,7 @@ - + @@ -149,7 +149,7 @@ - + @@ -173,7 +173,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -211,7 +211,7 @@ - + @@ -250,7 +250,7 @@ - + @@ -269,7 +269,7 @@ - + @@ -288,7 +288,7 @@ - + @@ -307,7 +307,7 @@ - + diff --git a/docs/test_cases/t00042_class.svg b/docs/test_cases/t00042_class.svg index b9b9748c..1cc113ff 100644 --- a/docs/test_cases/t00042_class.svg +++ b/docs/test_cases/t00042_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,15 +19,15 @@ - + - + a : T - - + + A @@ -36,15 +36,15 @@ - + - + a : void * - - + + B @@ -53,22 +53,22 @@ - + - + b : T - + - + bb : K - - + + A @@ -77,8 +77,8 @@ - - + + A @@ -87,8 +87,8 @@ - - + + B diff --git a/docs/test_cases/t00042_class_mermaid.svg b/docs/test_cases/t00042_class_mermaid.svg index 8d8bb15e..85f7d809 100644 --- a/docs/test_cases/t00042_class_mermaid.svg +++ b/docs/test_cases/t00042_class_mermaid.svg @@ -102,7 +102,7 @@ - + @@ -126,7 +126,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -179,7 +179,7 @@ - + @@ -198,7 +198,7 @@ - + @@ -217,7 +217,7 @@ - + diff --git a/docs/test_cases/t00043_class.svg b/docs/test_cases/t00043_class.svg index cc7625df..82d15aec 100644 --- a/docs/test_cases/t00043_class.svg +++ b/docs/test_cases/t00043_class.svg @@ -1,6 +1,6 @@ - + @@ -9,167 +9,167 @@ - + dependants - + dependencies - - + + A - - + + B - + - + b(A * a) : void - - + + BB - + - + bb(A * a) : void - - + + C - + - + c(B * b) : void - - + + D - + - + d(C * c) : void - + - + dd(BB * bb) : void - - + + E - + - + e(D * d) : void - - + + G - - + + GG - - + + H - + - + h(G * g) : void - + - + hh(GG * gg) : void - - + + I - + - + i(H * h) : void - - + + J - + - + i(I * i) : void diff --git a/docs/test_cases/t00043_class_mermaid.svg b/docs/test_cases/t00043_class_mermaid.svg index 234189b7..e6220a4e 100644 --- a/docs/test_cases/t00043_class_mermaid.svg +++ b/docs/test_cases/t00043_class_mermaid.svg @@ -174,7 +174,7 @@ - + @@ -193,7 +193,7 @@ - + @@ -217,7 +217,7 @@ - + @@ -241,7 +241,7 @@ - + @@ -265,7 +265,7 @@ - + @@ -294,7 +294,7 @@ - + @@ -318,7 +318,7 @@ - + @@ -337,7 +337,7 @@ - + @@ -356,7 +356,7 @@ - + @@ -385,7 +385,7 @@ - + @@ -409,7 +409,7 @@ - + diff --git a/docs/test_cases/t00044_class.svg b/docs/test_cases/t00044_class.svg index 2c035d24..095b5e76 100644 --- a/docs/test_cases/t00044_class.svg +++ b/docs/test_cases/t00044_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + signal_handler @@ -19,8 +19,8 @@ - - + + sink @@ -28,26 +28,26 @@ signal_handler<Ret(Args...),A> - + - + sink(signal_t & sh) : void get_signal<CastTo>() : CastTo * - + - + signal : signal_t * - - + + signal_handler @@ -56,8 +56,8 @@ - - + + sink @@ -66,23 +66,23 @@ - - + + R - + - + sink1 : sink<signal_handler<void (int),bool>> - - + + signal_handler @@ -91,8 +91,8 @@ - - + + sink diff --git a/docs/test_cases/t00044_class_mermaid.svg b/docs/test_cases/t00044_class_mermaid.svg index be08e97c..2bcc28de 100644 --- a/docs/test_cases/t00044_class_mermaid.svg +++ b/docs/test_cases/t00044_class_mermaid.svg @@ -138,7 +138,7 @@ - + @@ -157,7 +157,7 @@ - + @@ -191,7 +191,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -229,7 +229,7 @@ - + @@ -253,7 +253,7 @@ - + @@ -272,7 +272,7 @@ - + diff --git a/docs/test_cases/t00045_class.svg b/docs/test_cases/t00045_class.svg index bdf1538f..e5b72622 100644 --- a/docs/test_cases/t00045_class.svg +++ b/docs/test_cases/t00045_class.svg @@ -1,6 +1,6 @@ - + @@ -9,32 +9,32 @@ - - + + A - - + + AA - - + + AAA - - + + AAAA @@ -43,110 +43,110 @@ - + - + t : T - - + + ns1::A - - + + ns1::ns2::A - - + + ns1::ns2::B - - + + ns1::ns2::C - - + + ns1::ns2::D - - + + ns1::ns2::E - - + + ns1::ns2::AAA - - + + ns1::ns2::R - + - + foo(AA & aa) : void - + - + a : A * - + - + ns1_a : ns1::A * - + - + ns1_ns2_a : ns1::ns2::A * - + - + root_a : ::A * diff --git a/docs/test_cases/t00045_class_mermaid.svg b/docs/test_cases/t00045_class_mermaid.svg index ed575d78..9b6ee1cb 100644 --- a/docs/test_cases/t00045_class_mermaid.svg +++ b/docs/test_cases/t00045_class_mermaid.svg @@ -166,7 +166,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -204,7 +204,7 @@ - + @@ -223,7 +223,7 @@ - + @@ -247,7 +247,7 @@ - + @@ -266,7 +266,7 @@ - + @@ -285,7 +285,7 @@ - + @@ -304,7 +304,7 @@ - + @@ -323,7 +323,7 @@ - + @@ -342,7 +342,7 @@ - + @@ -361,7 +361,7 @@ - + @@ -380,7 +380,7 @@ - + diff --git a/docs/test_cases/t00046_class.svg b/docs/test_cases/t00046_class.svg index 5f2f628b..8e413e84 100644 --- a/docs/test_cases/t00046_class.svg +++ b/docs/test_cases/t00046_class.svg @@ -1,6 +1,6 @@ - + @@ -9,120 +9,120 @@ - + ns1 - + ns2 - - + + A - - + + A - - + + B - - + + C - - + + D - - + + E - - + + R - + - + foo(AA & aa) : void - + - + a : A * - + - + i : std::vector<std::uint8_t> - + - + ns1_a : ns1::A * - + - + ns1_ns2_a : ns1::ns2::A * - + - + root_a : ::A * - - + + A - - + + AA diff --git a/docs/test_cases/t00046_class_mermaid.svg b/docs/test_cases/t00046_class_mermaid.svg index 2db8b147..6913afc6 100644 --- a/docs/test_cases/t00046_class_mermaid.svg +++ b/docs/test_cases/t00046_class_mermaid.svg @@ -154,7 +154,7 @@ - + @@ -173,7 +173,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -211,7 +211,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -249,7 +249,7 @@ - + @@ -268,7 +268,7 @@ - + @@ -287,7 +287,7 @@ - + @@ -306,7 +306,7 @@ - + diff --git a/docs/test_cases/t00047_class.svg b/docs/test_cases/t00047_class.svg index 2abfe84a..1ea64471 100644 --- a/docs/test_cases/t00047_class.svg +++ b/docs/test_cases/t00047_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + conditional_t @@ -19,8 +19,8 @@ - - + + conditional_t @@ -29,8 +29,8 @@ - - + + conditional_t @@ -39,8 +39,8 @@ - - + + conditional_t diff --git a/docs/test_cases/t00047_class_mermaid.svg b/docs/test_cases/t00047_class_mermaid.svg index b325a483..c7d275b7 100644 --- a/docs/test_cases/t00047_class_mermaid.svg +++ b/docs/test_cases/t00047_class_mermaid.svg @@ -90,7 +90,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -147,7 +147,7 @@ - + diff --git a/docs/test_cases/t00048_class.svg b/docs/test_cases/t00048_class.svg index c9bb9833..ab907403 100644 --- a/docs/test_cases/t00048_class.svg +++ b/docs/test_cases/t00048_class.svg @@ -1,6 +1,6 @@ - + @@ -9,30 +9,30 @@ - - + + Base - + - + foo() = 0 : void - + - + base : int - - + + BaseTemplate @@ -40,45 +40,45 @@ T - + - + foo() = 0 : void - + - + base : T - - + + B - + - + foo() : void - + - + b : int - - + + BTemplate @@ -86,45 +86,45 @@ T - + - + foo() : void - + - + b : T - - + + A - + - + foo() : void - + - + a : int - - + + ATemplate @@ -132,19 +132,19 @@ T - + - + foo() : void - + - + a : T diff --git a/docs/test_cases/t00048_class_mermaid.svg b/docs/test_cases/t00048_class_mermaid.svg index 2180b674..6646c1a9 100644 --- a/docs/test_cases/t00048_class_mermaid.svg +++ b/docs/test_cases/t00048_class_mermaid.svg @@ -94,7 +94,7 @@ - + @@ -123,7 +123,7 @@ - + @@ -152,7 +152,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -239,7 +239,7 @@ - + diff --git a/docs/test_cases/t00049_class.svg b/docs/test_cases/t00049_class.svg index 7c56fc73..f0fb0f78 100644 --- a/docs/test_cases/t00049_class.svg +++ b/docs/test_cases/t00049_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -18,23 +18,23 @@ T - + - + get_a() : T & - + - + a : T - - + + A @@ -43,8 +43,8 @@ - - + + A @@ -53,8 +53,8 @@ - - + + A @@ -63,47 +63,47 @@ - - + + R - + - + get_int_map() : A<intmap> - + - + set_int_map(A<intmap> && int_map) : void - + - + a_int_map : A<intmap> - + - + a_string : A<thestring> - + - + a_vector_string : A<string_vector> diff --git a/docs/test_cases/t00049_class_mermaid.svg b/docs/test_cases/t00049_class_mermaid.svg index efdc75ad..a8304379 100644 --- a/docs/test_cases/t00049_class_mermaid.svg +++ b/docs/test_cases/t00049_class_mermaid.svg @@ -126,7 +126,7 @@ - + @@ -155,7 +155,7 @@ - + @@ -174,7 +174,7 @@ - + @@ -193,7 +193,7 @@ - + @@ -212,7 +212,7 @@ - + diff --git a/docs/test_cases/t00050_class.svg b/docs/test_cases/t00050_class.svg index 3b0697a4..222c583e 100644 --- a/docs/test_cases/t00050_class.svg +++ b/docs/test_cases/t00050_class.svg @@ -1,6 +1,6 @@ - + @@ -9,40 +9,40 @@ - - + + A - - + + B - - + + C - - + + utils::D - - + + E @@ -52,8 +52,8 @@ E3 - - + + F @@ -62,43 +62,43 @@ - + - + t : T[N] - + - + v : V - - + + G - - + + NoComment - + Lorem ipsum dolor sit - + Lorem ipsum dolor sit - + Lorem ipsum dolor sit amet consectetur adipiscing elit, urna consequat felis vehicula class ultricies mollis dictumst, aenean non a in donec nulla. @@ -125,50 +125,50 @@ imperdiet praesent magnis ridiculus congue gravida curabitur dictum sagittis, enim et magna sit inceptos sodales parturient pharetra mollis, aenean vel nostra tellus commodo pretium sapien sociosqu. - + This is a short description of class G. - + This is an intermediate description of class G. - + This is a long description of class G. - + Lorem ipsum - + TODO 1. Write meaningful comment - + TODO 2. Write tests - + TODO 3. Implement - + Long comment example - + TODO Implement... - + Simple array wrapper. - + Template parameters diff --git a/docs/test_cases/t00050_class_mermaid.svg b/docs/test_cases/t00050_class_mermaid.svg index 33e20a4b..090ed384 100644 --- a/docs/test_cases/t00050_class_mermaid.svg +++ b/docs/test_cases/t00050_class_mermaid.svg @@ -184,7 +184,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -222,7 +222,7 @@ - + @@ -241,7 +241,7 @@ - + @@ -260,7 +260,7 @@ - + @@ -294,7 +294,7 @@ - + @@ -323,7 +323,7 @@ - + @@ -342,7 +342,7 @@ - + diff --git a/docs/test_cases/t00051_class.svg b/docs/test_cases/t00051_class.svg index ebbe8c93..898783f0 100644 --- a/docs/test_cases/t00051_class.svg +++ b/docs/test_cases/t00051_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + B @@ -18,45 +18,45 @@ F,FF=F - + - + B(F && f, FF && ff) : void - + - + f() : void - + - + ff() : void - + - + f_ : F - + - + ff_ : FF - - + + B @@ -64,81 +64,81 @@ (lambda at t00051.cc:43:18),(lambda at t00051.cc:43:27) - + - + B((lambda at t00051.cc:43:18) && f, (lambda at t00051.cc:43:27) && ff) : void - + - + f() : void - + - + ff() : void - + - + f_ : (lambda at t00051.cc:43:18) - + - + ff_ : (lambda at t00051.cc:43:27) - - + + A - + - + get_function() : (lambda at t00051.cc:48:16) - + - + start_thread1() : custom_thread1 - + - + start_thread2() : custom_thread2 - + - + start_thread3() : B<(lambda at t00051.cc:43:18),(lambda at t00051.cc:43:27)> - - + + A::custom_thread1 @@ -147,18 +147,18 @@ custom_thread1<Function,Args...>(Function && f, Args &&... args) : void - - + + A::custom_thread2 - + - + thread((lambda at t00051.cc:59:27) &&) : void diff --git a/docs/test_cases/t00051_class_mermaid.svg b/docs/test_cases/t00051_class_mermaid.svg index 915a38cd..449546bf 100644 --- a/docs/test_cases/t00051_class_mermaid.svg +++ b/docs/test_cases/t00051_class_mermaid.svg @@ -102,7 +102,7 @@ - + @@ -146,7 +146,7 @@ - + @@ -190,7 +190,7 @@ - + @@ -229,7 +229,7 @@ - + @@ -253,7 +253,7 @@ - + diff --git a/docs/test_cases/t00052_class.svg b/docs/test_cases/t00052_class.svg index c820382f..9d9c6062 100644 --- a/docs/test_cases/t00052_class.svg +++ b/docs/test_cases/t00052_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -21,8 +21,8 @@ aa<F,Q>(F && f, Q q) : void - - + + B @@ -30,18 +30,18 @@ T - + - + b(T t) : T bb<F>(F && f, T t) : T - - + + C @@ -52,8 +52,8 @@ c<P>(P p) : T - - + + B @@ -62,8 +62,8 @@ - - + + C @@ -72,33 +72,33 @@ - - + + R - + - + a : A - + - + b : B<int> - + - + c : C<int> diff --git a/docs/test_cases/t00052_class_mermaid.svg b/docs/test_cases/t00052_class_mermaid.svg index 1b15b8d4..3ae2c8d6 100644 --- a/docs/test_cases/t00052_class_mermaid.svg +++ b/docs/test_cases/t00052_class_mermaid.svg @@ -114,7 +114,7 @@ - + @@ -143,7 +143,7 @@ - + @@ -172,7 +172,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -215,7 +215,7 @@ - + @@ -234,7 +234,7 @@ - + diff --git a/docs/test_cases/t00053_class.svg b/docs/test_cases/t00053_class.svg index 3e798a23..130ffd38 100644 --- a/docs/test_cases/t00053_class.svg +++ b/docs/test_cases/t00053_class.svg @@ -1,6 +1,6 @@ - + @@ -9,72 +9,72 @@ - - + + A - - + + C - - + + E - - + + F - - + + a - - + + c - - + + e - - + + f - - + + h @@ -82,8 +82,8 @@ hhh - - + + j @@ -91,56 +91,56 @@ jjj - - + + b - - + + d - - + + g - - + + B - - + + D - - + + G - - + + i diff --git a/docs/test_cases/t00053_class_mermaid.svg b/docs/test_cases/t00053_class_mermaid.svg index efa4e823..01c51692 100644 --- a/docs/test_cases/t00053_class_mermaid.svg +++ b/docs/test_cases/t00053_class_mermaid.svg @@ -52,7 +52,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -166,7 +166,7 @@ - + @@ -190,7 +190,7 @@ - + @@ -209,7 +209,7 @@ - + @@ -228,7 +228,7 @@ - + @@ -247,7 +247,7 @@ - + @@ -266,7 +266,7 @@ - + @@ -285,7 +285,7 @@ - + @@ -304,7 +304,7 @@ - + @@ -323,7 +323,7 @@ - + @@ -342,7 +342,7 @@ - + @@ -366,7 +366,7 @@ - + diff --git a/docs/test_cases/t00054_class.svg b/docs/test_cases/t00054_class.svg index 8e314079..88ba6ea5 100644 --- a/docs/test_cases/t00054_class.svg +++ b/docs/test_cases/t00054_class.svg @@ -1,6 +1,6 @@ - + @@ -9,28 +9,28 @@ - + detail - + detail2 - + detail3 - + detail4 - - + + d - - + + a @@ -40,8 +40,8 @@ - - + + c @@ -51,8 +51,8 @@ - - + + e @@ -62,40 +62,40 @@ - - + + C - - + + F - - + + D - - + + E - - + + A @@ -104,8 +104,8 @@ - - + + B @@ -114,8 +114,8 @@ - - + + f @@ -124,8 +124,8 @@ - - + + G @@ -133,8 +133,8 @@ - - + + h @@ -143,8 +143,8 @@ hhh - - + + i @@ -153,8 +153,8 @@ iii - - + + j @@ -163,16 +163,16 @@ jjj - - + + b - - + + g diff --git a/docs/test_cases/t00054_class_mermaid.svg b/docs/test_cases/t00054_class_mermaid.svg index 0b04d591..1714699c 100644 --- a/docs/test_cases/t00054_class_mermaid.svg +++ b/docs/test_cases/t00054_class_mermaid.svg @@ -52,7 +52,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -166,7 +166,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -204,7 +204,7 @@ - + @@ -223,7 +223,7 @@ - + @@ -242,7 +242,7 @@ - + @@ -261,7 +261,7 @@ - + @@ -280,7 +280,7 @@ - + @@ -304,7 +304,7 @@ - + @@ -328,7 +328,7 @@ - + @@ -352,7 +352,7 @@ - + @@ -371,7 +371,7 @@ - + diff --git a/docs/test_cases/t00055_class.svg b/docs/test_cases/t00055_class.svg index 3444b97f..872ed89b 100644 --- a/docs/test_cases/t00055_class.svg +++ b/docs/test_cases/t00055_class.svg @@ -1,6 +1,6 @@ - + @@ -9,80 +9,80 @@ - - + + A - - + + B - - + + C - - + + D - - + + E - - + + F - - + + G - - + + H - - + + I - - + + J diff --git a/docs/test_cases/t00055_class_mermaid.svg b/docs/test_cases/t00055_class_mermaid.svg index d56cadda..fdc75e26 100644 --- a/docs/test_cases/t00055_class_mermaid.svg +++ b/docs/test_cases/t00055_class_mermaid.svg @@ -52,7 +52,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -166,7 +166,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -204,7 +204,7 @@ - + @@ -223,7 +223,7 @@ - + diff --git a/docs/test_cases/t00056_class.svg b/docs/test_cases/t00056_class.svg index e15e917c..3e9cc6ae 100644 --- a/docs/test_cases/t00056_class.svg +++ b/docs/test_cases/t00056_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + «concept» @@ -20,8 +20,8 @@ - - + + «concept» @@ -33,8 +33,8 @@ sizeof (l) > sizeof (r) - - + + «concept» @@ -44,8 +44,8 @@ - - + + «concept» @@ -58,8 +58,8 @@ container.begin() container.end() - - + + «concept» @@ -71,8 +71,8 @@ typename T::value_type - - + + «concept» @@ -86,8 +86,8 @@ {std::to_string(s)} noexcept {std::to_string(s)} -> std::same_as<std::string> - - + + «concept» @@ -97,8 +97,8 @@ - - + + «concept» @@ -108,8 +108,8 @@ - - + + A @@ -118,15 +118,15 @@ - + - + a : T - - + + B @@ -135,15 +135,15 @@ - + - + b : T - - + + C @@ -152,15 +152,15 @@ - + - + c : T - - + + D @@ -169,8 +169,8 @@ - - + + E @@ -179,29 +179,29 @@ - + - + e1 : T1 - + - + e2 : T2 - + - + e3 : T3 - - + + F @@ -210,25 +210,25 @@ - + - + f1 : T1 - + - + f2 : T2 - + - + f3 : T3 diff --git a/docs/test_cases/t00056_class_mermaid.svg b/docs/test_cases/t00056_class_mermaid.svg index 6e97e2e8..b542cfce 100644 --- a/docs/test_cases/t00056_class_mermaid.svg +++ b/docs/test_cases/t00056_class_mermaid.svg @@ -222,7 +222,7 @@ - + @@ -241,7 +241,7 @@ - + @@ -270,7 +270,7 @@ - + @@ -289,7 +289,7 @@ - + @@ -323,7 +323,7 @@ - + @@ -352,7 +352,7 @@ - + @@ -391,7 +391,7 @@ - + @@ -410,7 +410,7 @@ - + @@ -429,7 +429,7 @@ - + @@ -453,7 +453,7 @@ - + @@ -477,7 +477,7 @@ - + @@ -501,7 +501,7 @@ - + @@ -520,7 +520,7 @@ - + @@ -554,7 +554,7 @@ - + diff --git a/docs/test_cases/t00057_class.svg b/docs/test_cases/t00057_class.svg index 1ab77db9..08cd3548 100644 --- a/docs/test_cases/t00057_class.svg +++ b/docs/test_cases/t00057_class.svg @@ -1,6 +1,6 @@ - + @@ -9,53 +9,53 @@ - - + + t00057_A - + - + a1 : int - - + + t00057_B - + - + b1 : int - - + + t00057_C - + - + c1 : int - - + + «union» @@ -63,73 +63,73 @@ - + - + d1 : int - + - + d2 : float - - + + t00057_E - + - + coordinates : t00057_E::(anonymous_739) - + - + e : int - + - + height : t00057_E::(anonymous_807) - - + + t00057_E::(coordinates) - + - + x : int - + - + y : int - - + + «union» @@ -137,105 +137,105 @@ - + - + t : double - + - + z : int - - + + t00057_G - + - + g1 : int - - + + t00057_R - + - + a : struct t00057_A - + - + b : t00057_B - + - + c : struct t00057_C * - + - + d : union t00057_D - + - + e : struct t00057_E * - + - + f : struct t00057_F * - + - + g : struct t00057_G * - - + + t00057_F - + - + f1 : int diff --git a/docs/test_cases/t00057_class_mermaid.svg b/docs/test_cases/t00057_class_mermaid.svg index 198adb80..0f0c1cd9 100644 --- a/docs/test_cases/t00057_class_mermaid.svg +++ b/docs/test_cases/t00057_class_mermaid.svg @@ -162,7 +162,7 @@ - + @@ -186,7 +186,7 @@ - + @@ -210,7 +210,7 @@ - + @@ -234,7 +234,7 @@ - + @@ -263,7 +263,7 @@ - + @@ -297,7 +297,7 @@ - + @@ -326,7 +326,7 @@ - + @@ -355,7 +355,7 @@ - + @@ -379,7 +379,7 @@ - + @@ -433,7 +433,7 @@ - + diff --git a/docs/test_cases/t00058_class.svg b/docs/test_cases/t00058_class.svg index 4672d0d9..4f50bd89 100644 --- a/docs/test_cases/t00058_class.svg +++ b/docs/test_cases/t00058_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + first_type @@ -19,8 +19,8 @@ - - + + «concept» @@ -30,8 +30,8 @@ - - + + A @@ -40,15 +40,15 @@ - + - + a : std::vector<T> - - + + B @@ -57,22 +57,22 @@ - + - + b : std::vector<T> - + - + bb : P - - + + A @@ -81,8 +81,8 @@ - - + + A @@ -91,8 +91,8 @@ - - + + B @@ -101,26 +101,26 @@ - - + + R - + - + aa : A<int,int,double,std::string> - + - + bb : B<int,std::string,int,double,A<int,int>> diff --git a/docs/test_cases/t00058_class_mermaid.svg b/docs/test_cases/t00058_class_mermaid.svg index b69c4252..d918b23d 100644 --- a/docs/test_cases/t00058_class_mermaid.svg +++ b/docs/test_cases/t00058_class_mermaid.svg @@ -150,7 +150,7 @@ - + @@ -169,7 +169,7 @@ - + @@ -188,7 +188,7 @@ - + @@ -212,7 +212,7 @@ - + @@ -241,7 +241,7 @@ - + @@ -260,7 +260,7 @@ - + @@ -279,7 +279,7 @@ - + @@ -298,7 +298,7 @@ - + diff --git a/docs/test_cases/t00059_class.svg b/docs/test_cases/t00059_class.svg index 89cef117..c8e6b55d 100644 --- a/docs/test_cases/t00059_class.svg +++ b/docs/test_cases/t00059_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + «concept» @@ -23,8 +23,8 @@ T{} t.get_name() - - + + «concept» @@ -36,8 +36,8 @@ t.get_sweetness() - - + + «concept» @@ -49,96 +49,96 @@ t.get_bitterness() - - + + gala_apple - + - + get_name() const : std::string - + - + get_sweetness() const : float - - + + empire_apple - + - + get_name() const : std::string - + - + get_sweetness() const : float - - + + lima_orange - + - + get_bitterness() const : float - + - + get_name() const : std::string - - + + valencia_orange - + - + get_bitterness() const : float - + - + get_name() const : std::string - - + + fruit_factory @@ -146,23 +146,23 @@ apple_c TA,orange_c TO - + - + create_apple() const : TA - + - + create_orange() const : TO - - + + fruit_factory @@ -171,8 +171,8 @@ - - + + fruit_factory @@ -181,26 +181,26 @@ - - + + R - + - + factory_1 : fruit_factory_1 - + - + factory_2 : fruit_factory_2 diff --git a/docs/test_cases/t00059_class_mermaid.svg b/docs/test_cases/t00059_class_mermaid.svg index 7ba73384..733acf0a 100644 --- a/docs/test_cases/t00059_class_mermaid.svg +++ b/docs/test_cases/t00059_class_mermaid.svg @@ -198,7 +198,7 @@ - + @@ -232,7 +232,7 @@ - + @@ -261,7 +261,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -319,7 +319,7 @@ - + @@ -348,7 +348,7 @@ - + @@ -377,7 +377,7 @@ - + @@ -406,7 +406,7 @@ - + @@ -435,7 +435,7 @@ - + @@ -454,7 +454,7 @@ - + @@ -473,7 +473,7 @@ - + diff --git a/docs/test_cases/t00060_class.svg b/docs/test_cases/t00060_class.svg index 113ee42d..30493956 100644 --- a/docs/test_cases/t00060_class.svg +++ b/docs/test_cases/t00060_class.svg @@ -1,6 +1,6 @@ - + @@ -9,40 +9,40 @@ - - + + A - - + + B - - + + C - - + + D - - + + G @@ -51,15 +51,15 @@ - + - + g : T - - + + H @@ -68,18 +68,18 @@ - + - + h : G<T> - + - + hh : P diff --git a/docs/test_cases/t00060_class_mermaid.svg b/docs/test_cases/t00060_class_mermaid.svg index d26a3c7b..0f89e643 100644 --- a/docs/test_cases/t00060_class_mermaid.svg +++ b/docs/test_cases/t00060_class_mermaid.svg @@ -116,7 +116,7 @@ - + @@ -135,7 +135,7 @@ - + @@ -154,7 +154,7 @@ - + @@ -173,7 +173,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -216,7 +216,7 @@ - + diff --git a/docs/test_cases/t00061_class.svg b/docs/test_cases/t00061_class.svg index dd5fa5e3..ea92b5e3 100644 --- a/docs/test_cases/t00061_class.svg +++ b/docs/test_cases/t00061_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A diff --git a/docs/test_cases/t00061_class_mermaid.svg b/docs/test_cases/t00061_class_mermaid.svg index 5cba1ccf..1a82fe8a 100644 --- a/docs/test_cases/t00061_class_mermaid.svg +++ b/docs/test_cases/t00061_class_mermaid.svg @@ -52,7 +52,7 @@ - + diff --git a/docs/test_cases/t00062_class.svg b/docs/test_cases/t00062_class.svg index fc025f6d..0db32b03 100644 --- a/docs/test_cases/t00062_class.svg +++ b/docs/test_cases/t00062_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A @@ -19,15 +19,15 @@ - + - + u : U & - - + + A @@ -36,15 +36,15 @@ - + - + u : U & - - + + A @@ -53,8 +53,8 @@ - - + + A @@ -63,15 +63,15 @@ - + - + u : U ** - - + + A @@ -80,15 +80,15 @@ - + - + u : U *** - - + + A @@ -97,15 +97,15 @@ - + - + u : U *** - - + + A @@ -114,15 +114,15 @@ - + - + u : U && - - + + A @@ -131,15 +131,15 @@ - + - + u : const U & - - + + A @@ -148,22 +148,22 @@ - + - + c : C & - + - + m : M C::* - - + + A @@ -172,22 +172,22 @@ - + - + c : C && - + - + m : M C::* - - + + A @@ -196,22 +196,22 @@ - + - + c : C & - + - + m : M C::* - - + + A @@ -220,15 +220,15 @@ - + - + c : C & - - + + A @@ -237,22 +237,22 @@ - + - + c : C && - + - + m : M C::* - - + + A @@ -261,22 +261,22 @@ - + - + c : C && - + - + mf : float C::* - - + + A @@ -285,22 +285,22 @@ - + - + c : C & - + - + m : M C::* - - + + A @@ -309,15 +309,15 @@ - + - + n : char[N] - - + + A @@ -326,15 +326,15 @@ - + - + n : std::vector<char> - - + + A @@ -343,15 +343,15 @@ - + - + klm : char[K][L][M] - - + + A @@ -360,15 +360,15 @@ - + - + u : bool - - + + A @@ -377,15 +377,15 @@ - + - + c : C<T> - - + + A @@ -394,22 +394,22 @@ - + - + args : std::tuple<Args...> - + - + c : C<T> - - + + A diff --git a/docs/test_cases/t00062_class_mermaid.svg b/docs/test_cases/t00062_class_mermaid.svg index 586adf8f..78357cce 100644 --- a/docs/test_cases/t00062_class_mermaid.svg +++ b/docs/test_cases/t00062_class_mermaid.svg @@ -306,7 +306,7 @@ - + @@ -330,7 +330,7 @@ - + @@ -354,7 +354,7 @@ - + @@ -373,7 +373,7 @@ - + @@ -397,7 +397,7 @@ - + @@ -421,7 +421,7 @@ - + @@ -445,7 +445,7 @@ - + @@ -469,7 +469,7 @@ - + @@ -493,7 +493,7 @@ - + @@ -522,7 +522,7 @@ - + @@ -551,7 +551,7 @@ - + @@ -580,7 +580,7 @@ - + @@ -604,7 +604,7 @@ - + @@ -633,7 +633,7 @@ - + @@ -662,7 +662,7 @@ - + @@ -691,7 +691,7 @@ - + @@ -715,7 +715,7 @@ - + @@ -739,7 +739,7 @@ - + @@ -763,7 +763,7 @@ - + @@ -787,7 +787,7 @@ - + @@ -811,7 +811,7 @@ - + @@ -840,7 +840,7 @@ - + diff --git a/docs/test_cases/t00063_class.svg b/docs/test_cases/t00063_class.svg index bdfaff82..e0e3e1ea 100644 --- a/docs/test_cases/t00063_class.svg +++ b/docs/test_cases/t00063_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + A diff --git a/docs/test_cases/t00063_class_mermaid.svg b/docs/test_cases/t00063_class_mermaid.svg index fbbd2d5a..a34256d0 100644 --- a/docs/test_cases/t00063_class_mermaid.svg +++ b/docs/test_cases/t00063_class_mermaid.svg @@ -52,7 +52,7 @@ - + diff --git a/docs/test_cases/t00064_class.svg b/docs/test_cases/t00064_class.svg index be457959..914118ad 100644 --- a/docs/test_cases/t00064_class.svg +++ b/docs/test_cases/t00064_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + type_list @@ -19,8 +19,8 @@ - - + + type_list @@ -29,8 +29,8 @@ - - + + type_list @@ -39,8 +39,8 @@ - - + + type_list @@ -49,8 +49,8 @@ - - + + head @@ -59,8 +59,8 @@ - - + + type_list @@ -69,8 +69,8 @@ - - + + type_list @@ -79,8 +79,8 @@ - - + + type_list @@ -89,8 +89,8 @@ - - + + type_group_pair @@ -99,15 +99,15 @@ - + - + size : const size_t - - + + optional_ref @@ -116,8 +116,8 @@ - - + + optional_ref @@ -126,8 +126,8 @@ - - + + type_group_pair_it @@ -135,54 +135,54 @@ It,type_list<First...>,type_list<Second...> - + - + find(const value_type & v) constexpr : unsigned int - + - + get(unsigned int i) : ref_t - + - + getp(unsigned int i) : const value_type * - - + + A - - + + B - - + + C - - + + type_list @@ -191,8 +191,8 @@ - - + + type_list @@ -201,8 +201,8 @@ - - + + type_list @@ -211,8 +211,8 @@ - - + + type_group_pair @@ -221,30 +221,30 @@ - - + + R - + - + abc : type_group_pair<type_list<float,double>,type_list<A,B,C>> - + - + aboolint : type_list<A,bool,int> - - + + type_group_pair @@ -253,8 +253,8 @@ - - + + type_group_pair_it @@ -263,8 +263,8 @@ - - + + head diff --git a/docs/test_cases/t00064_class_mermaid.svg b/docs/test_cases/t00064_class_mermaid.svg index fcc26c77..6d3c6dd2 100644 --- a/docs/test_cases/t00064_class_mermaid.svg +++ b/docs/test_cases/t00064_class_mermaid.svg @@ -390,7 +390,7 @@ - + @@ -409,7 +409,7 @@ - + @@ -428,7 +428,7 @@ - + @@ -447,7 +447,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -485,7 +485,7 @@ - + @@ -504,7 +504,7 @@ - + @@ -523,7 +523,7 @@ - + @@ -542,7 +542,7 @@ - + @@ -566,7 +566,7 @@ - + @@ -585,7 +585,7 @@ - + @@ -604,7 +604,7 @@ - + @@ -638,7 +638,7 @@ - + @@ -657,7 +657,7 @@ - + @@ -676,7 +676,7 @@ - + @@ -695,7 +695,7 @@ - + @@ -714,7 +714,7 @@ - + @@ -733,7 +733,7 @@ - + @@ -752,7 +752,7 @@ - + @@ -771,7 +771,7 @@ - + @@ -800,7 +800,7 @@ - + @@ -819,7 +819,7 @@ - + @@ -838,7 +838,7 @@ - + diff --git a/docs/test_cases/t00065_class.svg b/docs/test_cases/t00065_class.svg index 48ada059..643d9ebd 100644 --- a/docs/test_cases/t00065_class.svg +++ b/docs/test_cases/t00065_class.svg @@ -1,6 +1,6 @@ - + @@ -9,20 +9,20 @@ - + module1 - + submodule1a - + module2 - + concepts - - + + ABC @@ -32,8 +32,8 @@ c - - + + XYZ @@ -43,68 +43,68 @@ z - - + + A - + - + abc : ABC - + - + pimpl : detail::AImpl * - + - + xyz : XYZ - - + + detail::AImpl - - + + B - + - + B() = default : void - + - + b() : void - - + + C @@ -113,15 +113,15 @@ - + - + t : T * - - + + C @@ -130,8 +130,8 @@ - - + + D @@ -140,22 +140,22 @@ - + - + c : C<int> - + - + t : T - - + + C @@ -164,8 +164,8 @@ - - + + D @@ -174,8 +174,8 @@ - - + + «concept» @@ -188,33 +188,33 @@ T{} t.b() - - + + R - + - + a : A * - + - + c : C<B> - + - + d : D<B> diff --git a/docs/test_cases/t00065_class_mermaid.svg b/docs/test_cases/t00065_class_mermaid.svg index 008eaac1..732abc79 100644 --- a/docs/test_cases/t00065_class_mermaid.svg +++ b/docs/test_cases/t00065_class_mermaid.svg @@ -210,7 +210,7 @@ - + @@ -229,7 +229,7 @@ - + @@ -263,7 +263,7 @@ - + @@ -297,7 +297,7 @@ - + @@ -331,7 +331,7 @@ - + @@ -365,7 +365,7 @@ - + @@ -394,7 +394,7 @@ - + @@ -418,7 +418,7 @@ - + @@ -437,7 +437,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -485,7 +485,7 @@ - + @@ -504,7 +504,7 @@ - + diff --git a/docs/test_cases/t00066_class.svg b/docs/test_cases/t00066_class.svg index 133af361..2fee943a 100644 --- a/docs/test_cases/t00066_class.svg +++ b/docs/test_cases/t00066_class.svg @@ -1,6 +1,6 @@ - + @@ -9,222 +9,222 @@ - - + + A - + - + public_member : int - + - + protected_member : int - + - + private_member : int - + - + a_ : int - + - + b_ : int - + - + c_ : int - + - + static_int : int - + - + static_const_int : const int - + - + auto_member : const unsigned long - + - + A() = default : void - + - + A(int i) : void - + - + A(A &&) = default : void - + - + A(const A &) = deleted : void - + - + ~A() = default : void - + - + basic_method() : void - + - + static_method() : int - + - + const_method() const : void - + - + auto_method() : int - + - + operator++() : A & - + - + operator=(A && other) noexcept : A & - + - + operator=(A & other) noexcept : A & - + - + size() const : std::size_t - + - + double_int(const int i) : int - + - + sum(const double a, const double b) : int - + - + default_int(int i = 12) : int - + - + default_string(int i, std::string s = "abc") : std::string - + - + create_from_int(int i) : A - + - + protected_method() : void - + - + private_method() : void - + - + compare : std::function<bool (const int)> diff --git a/docs/test_cases/t00066_class_mermaid.svg b/docs/test_cases/t00066_class_mermaid.svg index 1590b58d..10aab352 100644 --- a/docs/test_cases/t00066_class_mermaid.svg +++ b/docs/test_cases/t00066_class_mermaid.svg @@ -52,7 +52,7 @@ - + diff --git a/docs/test_cases/t00067_class.svg b/docs/test_cases/t00067_class.svg index f4ae540d..2111fcec 100644 --- a/docs/test_cases/t00067_class.svg +++ b/docs/test_cases/t00067_class.svg @@ -1,6 +1,6 @@ - + @@ -9,152 +9,152 @@ - - + + A - + - + auto_method() : int - + - + basic_method() : void - + - + const_method() const : void - + - + default_int(int i = 12) : int - + - + default_string(int i, std::string s = "abc") : std::string - + - + double_int(const int i) : int - + - + private_method() : void - + - + protected_method() : void - + - + size() const : std::size_t - + - + sum(const double a, const double b) : int - + - + a_ : int - + - + auto_member : const unsigned long - + - + b_ : int - + - + c_ : int - + - + compare : std::function<bool (const int)> - + - + private_member : int - + - + protected_member : int - + - + public_member : int - + - + static_const_int : const int - + - + static_int : int diff --git a/docs/test_cases/t00067_class_mermaid.svg b/docs/test_cases/t00067_class_mermaid.svg index 14cec782..b60145fb 100644 --- a/docs/test_cases/t00067_class_mermaid.svg +++ b/docs/test_cases/t00067_class_mermaid.svg @@ -52,7 +52,7 @@ - + diff --git a/docs/test_cases/t00068_r0_class.svg b/docs/test_cases/t00068_r0_class.svg index 38b36a78..ff2e26fb 100644 --- a/docs/test_cases/t00068_r0_class.svg +++ b/docs/test_cases/t00068_r0_class.svg @@ -1,6 +1,6 @@ - + @@ -10,26 +10,26 @@ AAA context of radius 0 - - + + AAA - + - + akind : AKind - + - + bb : BB * diff --git a/docs/test_cases/t00068_r0_class_mermaid.svg b/docs/test_cases/t00068_r0_class_mermaid.svg index d89bfc00..71a25c67 100644 --- a/docs/test_cases/t00068_r0_class_mermaid.svg +++ b/docs/test_cases/t00068_r0_class_mermaid.svg @@ -53,7 +53,7 @@ - + diff --git a/docs/test_cases/t00068_r1_class.svg b/docs/test_cases/t00068_r1_class.svg index 20ab3291..4a79a7f5 100644 --- a/docs/test_cases/t00068_r1_class.svg +++ b/docs/test_cases/t00068_r1_class.svg @@ -1,6 +1,6 @@ - + @@ -10,23 +10,23 @@ AAA context of radius 1 - - + + BB - + - + b : std::vector<B> - - + + AKind @@ -36,49 +36,49 @@ ThreeA - - + + AA - - + + AAA - + - + akind : AKind - + - + bb : BB * - - + + R - + - + aaa : AAA * diff --git a/docs/test_cases/t00068_r1_class_mermaid.svg b/docs/test_cases/t00068_r1_class_mermaid.svg index d099a168..e110e94b 100644 --- a/docs/test_cases/t00068_r1_class_mermaid.svg +++ b/docs/test_cases/t00068_r1_class_mermaid.svg @@ -101,7 +101,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -178,7 +178,7 @@ - + @@ -207,7 +207,7 @@ - + diff --git a/docs/test_cases/t00068_r2_class.svg b/docs/test_cases/t00068_r2_class.svg index deae0386..f2742bf0 100644 --- a/docs/test_cases/t00068_r2_class.svg +++ b/docs/test_cases/t00068_r2_class.svg @@ -1,6 +1,6 @@ - + @@ -10,31 +10,31 @@ AAA context of radius 2 - - + + B - - + + BB - + - + b : std::vector<B> - - + + AKind @@ -44,72 +44,72 @@ ThreeA - - + + A - - + + AA - - + + AAA - + - + akind : AKind - + - + bb : BB * - - + + R - + - + aaa : AAA * - - + + RR - + - + r : std::shared_ptr<R> diff --git a/docs/test_cases/t00068_r2_class_mermaid.svg b/docs/test_cases/t00068_r2_class_mermaid.svg index 0e74c325..6642cc2f 100644 --- a/docs/test_cases/t00068_r2_class_mermaid.svg +++ b/docs/test_cases/t00068_r2_class_mermaid.svg @@ -135,7 +135,7 @@ - + @@ -154,7 +154,7 @@ - + @@ -178,7 +178,7 @@ - + @@ -212,7 +212,7 @@ - + @@ -231,7 +231,7 @@ - + @@ -250,7 +250,7 @@ - + @@ -279,7 +279,7 @@ - + @@ -303,7 +303,7 @@ - + diff --git a/docs/test_cases/t00069_class.svg b/docs/test_cases/t00069_class.svg index fc6254ed..507fdb11 100644 --- a/docs/test_cases/t00069_class.svg +++ b/docs/test_cases/t00069_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + generator @@ -18,96 +18,96 @@ T - + - + generator(handle_type h) : void - + - + ~generator() : void - + - + full_ : bool - + - + h_ : handle_type - - + + generator::promise_type - + - + final_suspend() noexcept : std::suspend_always - + - + get_return_object() : generator<T> - + - + initial_suspend() : std::suspend_always - + - + return_void() : void - + - + unhandled_exception() : void yield_value<std::convertible_to From>(From && from) : std::suspend_always - + - + exception_ : std::exception_ptr - + - + value_ : T - - + + generator @@ -116,33 +116,33 @@ - - + + A - + - + iota() [coroutine] : generator<unsigned long> - + - + seed() [coroutine] : generator<unsigned long> - + - + counter_ : unsigned long diff --git a/docs/test_cases/t00069_class_mermaid.svg b/docs/test_cases/t00069_class_mermaid.svg index 3b1e739b..6babe6da 100644 --- a/docs/test_cases/t00069_class_mermaid.svg +++ b/docs/test_cases/t00069_class_mermaid.svg @@ -90,7 +90,7 @@ - + @@ -129,7 +129,7 @@ - + @@ -188,7 +188,7 @@ - + @@ -207,7 +207,7 @@ - + diff --git a/docs/test_cases/t00070_class.svg b/docs/test_cases/t00070_class.svg index 3ef4fcf0..47beb5b4 100644 --- a/docs/test_cases/t00070_class.svg +++ b/docs/test_cases/t00070_class.svg @@ -1,6 +1,6 @@ - + @@ -9,16 +9,16 @@ - - + + B - - + + BB @@ -27,15 +27,15 @@ - + - + t : T - - + + BBB @@ -44,26 +44,26 @@ bbb2 - - + + A - + - + get() : int - + - + a : int diff --git a/docs/test_cases/t00070_class_mermaid.svg b/docs/test_cases/t00070_class_mermaid.svg index 1bc82bc6..b42a71b4 100644 --- a/docs/test_cases/t00070_class_mermaid.svg +++ b/docs/test_cases/t00070_class_mermaid.svg @@ -52,7 +52,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -124,7 +124,7 @@ - + diff --git a/docs/test_cases/t00071_class.svg b/docs/test_cases/t00071_class.svg index 518c4789..e7c75a6f 100644 --- a/docs/test_cases/t00071_class.svg +++ b/docs/test_cases/t00071_class.svg @@ -1,6 +1,6 @@ - + @@ -9,53 +9,53 @@ - + app - + lib1 - + mod1 - + mod2 - + lib2 - - + + A - + - + get() : int - + - + a : int - - + + B - - + + BB @@ -64,15 +64,15 @@ - + - + t : T - - + + detail::BBB @@ -81,32 +81,32 @@ bbb2 - - + + D - - + + E - - + + C - - + + CC @@ -115,15 +115,15 @@ - + - + t : T - - + + detail::CCC @@ -132,33 +132,33 @@ ccc2 - - + + R - + - + a : A * - + - + b : B * - + - + c : C * diff --git a/docs/test_cases/t00071_class_mermaid.svg b/docs/test_cases/t00071_class_mermaid.svg index 90f10ba1..b90e9459 100644 --- a/docs/test_cases/t00071_class_mermaid.svg +++ b/docs/test_cases/t00071_class_mermaid.svg @@ -90,7 +90,7 @@ - + @@ -109,7 +109,7 @@ - + @@ -133,7 +133,7 @@ - + @@ -162,7 +162,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -200,7 +200,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -243,7 +243,7 @@ - + @@ -272,7 +272,7 @@ - + @@ -301,7 +301,7 @@ - + diff --git a/docs/test_cases/t00072_class.svg b/docs/test_cases/t00072_class.svg index c6121ade..fa4ad3ba 100644 --- a/docs/test_cases/t00072_class.svg +++ b/docs/test_cases/t00072_class.svg @@ -1,6 +1,6 @@ - + @@ -9,53 +9,53 @@ - + app - + :lib1 - + mod1 - + mod2 - + :lib2 - - + + A - + - + get() : int - + - + a : int - - + + B - - + + BB @@ -64,15 +64,15 @@ - + - + t : T - - + + detail::BBB @@ -81,32 +81,32 @@ bbb2 - - + + D - - + + E - - + + C - - + + CC @@ -115,15 +115,15 @@ - + - + t : T - - + + detail::CCC diff --git a/docs/test_cases/t00072_class_mermaid.svg b/docs/test_cases/t00072_class_mermaid.svg index 67063a51..ef51c5a1 100644 --- a/docs/test_cases/t00072_class_mermaid.svg +++ b/docs/test_cases/t00072_class_mermaid.svg @@ -52,7 +52,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -124,7 +124,7 @@ - + @@ -143,7 +143,7 @@ - + @@ -162,7 +162,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -205,7 +205,7 @@ - + @@ -234,7 +234,7 @@ - + diff --git a/docs/test_cases/t00073_class.svg b/docs/test_cases/t00073_class.svg index acecebcd..6fb8ba30 100644 --- a/docs/test_cases/t00073_class.svg +++ b/docs/test_cases/t00073_class.svg @@ -1,6 +1,6 @@ - + @@ -9,70 +9,70 @@ - - + + A - - + + AHandler - + - + operator()(A & a) const : void - + - + handle(A & a) const : void - - + + B - - + + BHandler - + - + operator()(B & b) const : void - + - + handle(B & b) const : void - - + + Overload @@ -81,8 +81,8 @@ - - + + Overload @@ -91,19 +91,19 @@ - - + + R - + - + dispatch : Overload<AHandler,BHandler> diff --git a/docs/test_cases/t00073_class_mermaid.svg b/docs/test_cases/t00073_class_mermaid.svg index 96f4fb44..d72d2dc5 100644 --- a/docs/test_cases/t00073_class_mermaid.svg +++ b/docs/test_cases/t00073_class_mermaid.svg @@ -122,7 +122,7 @@ - + @@ -141,7 +141,7 @@ - + @@ -170,7 +170,7 @@ - + @@ -189,7 +189,7 @@ - + @@ -218,7 +218,7 @@ - + @@ -237,7 +237,7 @@ - + @@ -256,7 +256,7 @@ - + diff --git a/docs/test_cases/t00074_class.svg b/docs/test_cases/t00074_class.svg index d51e9715..103716d7 100644 --- a/docs/test_cases/t00074_class.svg +++ b/docs/test_cases/t00074_class.svg @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ - - + + «concept» @@ -20,8 +20,8 @@ - - + + «concept» @@ -31,8 +31,8 @@ - - + + «concept» diff --git a/docs/test_cases/t00074_class_mermaid.svg b/docs/test_cases/t00074_class_mermaid.svg index 1a29bcef..3eff4679 100644 --- a/docs/test_cases/t00074_class_mermaid.svg +++ b/docs/test_cases/t00074_class_mermaid.svg @@ -78,7 +78,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -116,7 +116,7 @@ - + diff --git a/docs/test_cases/t00075_class.svg b/docs/test_cases/t00075_class.svg index bbf2c5d3..2f35ef5b 100644 --- a/docs/test_cases/t00075_class.svg +++ b/docs/test_cases/t00075_class.svg @@ -1,6 +1,6 @@ - + @@ -9,14 +9,14 @@ - + ns1 - + ns2 - - + + @@ -30,8 +30,8 @@ T{} t.e() - - + + E @@ -40,40 +40,40 @@ k2 - - + + A - + - + e() const : E - - + + B - + - + e() const : E - - + + @@ -83,15 +83,15 @@ - + - + a_or_b : T - - + + @@ -101,8 +101,8 @@ - - + + @@ -112,8 +112,8 @@ - - + + @@ -121,18 +121,18 @@ - + - + a : ABE<A> - + - + b : ABE<B> diff --git a/docs/test_cases/t00075_class_mermaid.svg b/docs/test_cases/t00075_class_mermaid.svg index 202f9771..88049162 100644 --- a/docs/test_cases/t00075_class_mermaid.svg +++ b/docs/test_cases/t00075_class_mermaid.svg @@ -162,7 +162,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -225,7 +225,7 @@ - + @@ -249,7 +249,7 @@ - + @@ -273,7 +273,7 @@ - + @@ -297,7 +297,7 @@ - + @@ -316,7 +316,7 @@ - + @@ -335,7 +335,7 @@ - + diff --git a/docs/test_cases/t20001_sequence.svg b/docs/test_cases/t20001_sequence.svg index d6885e9b..3aec474c 100644 --- a/docs/test_cases/t20001_sequence.svg +++ b/docs/test_cases/t20001_sequence.svg @@ -1,6 +1,6 @@ - + @@ -10,79 +10,79 @@ Basic sequence diagram example - - - - - - - - - + + + + + + + + + - - + + tmain() - + tmain() - - + + A - + A - - + + B - + B - - - - - - - - - - + + + + + + + + + + A() - + B(A &) - + Just add 2 numbers - + add(int,int) - + And now add another 2 - + wrap_add3(int,int,int) - + add3(int,int,int) - + @@ -93,7 +93,7 @@ - + @@ -102,14 +102,14 @@ - + log_result(int) - + Main test function diff --git a/docs/test_cases/t20002_sequence.svg b/docs/test_cases/t20002_sequence.svg index ba28c35a..b65e1849 100644 --- a/docs/test_cases/t20002_sequence.svg +++ b/docs/test_cases/t20002_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,51 +9,51 @@ - - - - + + + + - - + + m1() - + m1() - - + + m2() - + m2() - - + + m3() - + m3() - - + + m4() - + m4() - - - - - + + + + + - + - + diff --git a/docs/test_cases/t20003_sequence.svg b/docs/test_cases/t20003_sequence.svg index b743e488..853b855c 100644 --- a/docs/test_cases/t20003_sequence.svg +++ b/docs/test_cases/t20003_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,51 +9,51 @@ - - - - + + + + - - + + m1<T>(T) - + m1<T>(T) - - + + m2<T>(T) - + m2<T>(T) - - + + m3<T>(T) - + m3<T>(T) - - + + m4<T>(T) - + m4<T>(T) - - - - - + + + + + - + - + diff --git a/docs/test_cases/t20004_sequence.svg b/docs/test_cases/t20004_sequence.svg index fe39087b..ba76d91d 100644 --- a/docs/test_cases/t20004_sequence.svg +++ b/docs/test_cases/t20004_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,16 +9,16 @@ - - - - - - - - - - + + + + + + + + + + @@ -29,87 +29,87 @@ - - + + main() - + main() - - + + m1<float>(float) - + m1<float>(float) - - + + m1<unsigned long>(unsigned long) - + m1<unsigned long>(unsigned long) - - + + m4<unsigned long>(unsigned long) - + m4<unsigned long>(unsigned long) - - + + m1<std::string>(std::string) - + m1<std::string>(std::string) - - + + m2<std::string>(std::string) - + m2<std::string>(std::string) - - + + m1<int>(int) - + m1<int>(int) - - + + m2<int>(int) - + m2<int>(int) - - + + m3<int>(int) - + m3<int>(int) - - + + m4<int>(int) - + m4<int>(int) - - - - - - - - - - - + + + + + + + + + + + - + - + @@ -117,11 +117,11 @@ - + - + @@ -129,19 +129,19 @@ - + - + - + - + diff --git a/docs/test_cases/t20005_sequence.svg b/docs/test_cases/t20005_sequence.svg index d640065a..4ff68e5c 100644 --- a/docs/test_cases/t20005_sequence.svg +++ b/docs/test_cases/t20005_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,42 +9,42 @@ - - - + + + - - + + C<T> - + C<T> - - + + B<T> - + B<T> - - + + A<T> - + A<T> - - - + + + c(T) - + b(T) - + a(T) diff --git a/docs/test_cases/t20006_sequence.svg b/docs/test_cases/t20006_sequence.svg index 86f3a8d0..fe3339da 100644 --- a/docs/test_cases/t20006_sequence.svg +++ b/docs/test_cases/t20006_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,24 +9,24 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -36,84 +36,84 @@ - - + + tmain() - + tmain() - - + + B<int> - + B<int> - - + + A<int> - + A<int> - - + + B<std::string> - + B<std::string> - - + + A<std::string> - + A<std::string> - - + + BB<int,std::string> - + BB<int,std::string> - - + + BB<int,float> - + BB<int,float> - - + + BB<int,int> - + BB<int,int> - - + + AA<int> - + AA<int> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + b(int) - + a1(int) @@ -122,12 +122,12 @@ - + b(std::string) - + a2(std::string) @@ -136,69 +136,69 @@ - + BB(AA<int> *) - + BB(AA<int> &) - + bb1(int,int) - + aa1(int) - + bb2(int,int) - + aa2(int) - + bb1(int,std::string) - + aa2(int) - + bb2(int,std::string) - + aa1(int) - + bb1(int,float) - + bb2(int,float) - + aa2(int) diff --git a/docs/test_cases/t20007_sequence.svg b/docs/test_cases/t20007_sequence.svg index 9b62e1fb..4e026834 100644 --- a/docs/test_cases/t20007_sequence.svg +++ b/docs/test_cases/t20007_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,57 +9,57 @@ - - - - + + + + - - + + tmain() - + tmain() - - + + Adder<int,int> - + Adder<int,int> - - + + Adder<int,float,double> - + Adder<int,float,double> - - + + Adder<std::string,std::string,std::string> - + Adder<std::string,std::string,std::string> - - - - - + + + + + add(int &&,int &&) - + add(int &&,float &&,double &&) - + add(std::string &&,std::string &&,std::string &&) diff --git a/docs/test_cases/t20008_sequence.svg b/docs/test_cases/t20008_sequence.svg index 753299e6..7ff4a8c9 100644 --- a/docs/test_cases/t20008_sequence.svg +++ b/docs/test_cases/t20008_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,13 +9,13 @@ - - - - - - - + + + + + + + @@ -23,81 +23,81 @@ - - + + tmain() - + tmain() - - + + B<int> - + B<int> - - + + A<int> - + A<int> - - + + B<const char *> - + B<const char *> - - + + A<const char *> - + A<const char *> - - + + B<std::string> - + B<std::string> - - + + A<std::string> - + A<std::string> - - - - - - - - + + + + + + + + b(int) - + a1(int) - + b(const char *) - + a2(const char *) - + b(std::string) - + a3(std::string) diff --git a/docs/test_cases/t20009_sequence.svg b/docs/test_cases/t20009_sequence.svg index 3c1cda8b..9ee8dbe9 100644 --- a/docs/test_cases/t20009_sequence.svg +++ b/docs/test_cases/t20009_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,13 +9,13 @@ - - - - - - - + + + + + + + @@ -23,81 +23,81 @@ - - + + tmain() - + tmain() - - + + B<std::string> - + B<std::string> - - + + A<std::string> - + A<std::string> - - + + B<int> - + B<int> - - + + A<int> - + A<int> - - + + B<float> - + B<float> - - + + A<float> - + A<float> - - - - - - - - + + + + + + + + b(std::string) - + a(std::string) - + b(int) - + a(int) - + b(float) - + a(float) diff --git a/docs/test_cases/t20010_sequence.svg b/docs/test_cases/t20010_sequence.svg index 0904f0f3..f37888c9 100644 --- a/docs/test_cases/t20010_sequence.svg +++ b/docs/test_cases/t20010_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,81 +9,81 @@ - - - - - - - - - + + + + + + + + + - - + + tmain() - + tmain() - - + + B<int> - + B<int> - - + + A - + A - - - - - - - - - - + + + + + + + + + + b1() - + a1() - + b2() - + a2() - + b3() - + a3() - + b4() - + a4() diff --git a/docs/test_cases/t20011_sequence.svg b/docs/test_cases/t20011_sequence.svg index 61563c23..1f0cef76 100644 --- a/docs/test_cases/t20011_sequence.svg +++ b/docs/test_cases/t20011_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,42 +9,42 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - + + tmain() - + tmain() - - + + A - + A - - - - - - - - - - + + + + + + + + + + a(int) @@ -52,26 +52,26 @@ alt - + a(int) - + b(int) - + c(int) - + @@ -81,14 +81,14 @@ alt - + b(int) - + @@ -98,7 +98,7 @@ alt - + diff --git a/docs/test_cases/t20012_sequence.svg b/docs/test_cases/t20012_sequence.svg index 35f716c2..adb8132d 100644 --- a/docs/test_cases/t20012_sequence.svg +++ b/docs/test_cases/t20012_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,31 +9,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -42,116 +42,116 @@ - - + + tmain() - + tmain() - - + + tmain()::(lambda t20012.cc:67:20) - + tmain()::(lambda t20012.cc:67:20) - - + + A - + A - - + + B - + B - - + + tmain()::(lambda t20012.cc:80:20) - + tmain()::(lambda t20012.cc:80:20) - - + + C - + C - - + + R<(lambda at t20012.cc:86:9)> - + R<(lambda at t20012.cc:86:9)> - - + + tmain()::(lambda t20012.cc:86:9) - + tmain()::(lambda t20012.cc:86:9) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + operator()() - + a() - + aa() - + aaa() - + b() - + bb() - + @@ -160,67 +160,67 @@ - + operator()() - + c() - + cc() - + ccc() - + operator()() - + a() - + aa() - + aaa() - + b() - + bb() - + @@ -231,34 +231,34 @@ - + R((lambda at t20012.cc:86:9) &&) - + r() - + operator()() - + c() - + cc() - + diff --git a/docs/test_cases/t20013_sequence.svg b/docs/test_cases/t20013_sequence.svg index 0140e0c2..484a808c 100644 --- a/docs/test_cases/t20013_sequence.svg +++ b/docs/test_cases/t20013_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,47 +9,47 @@ - - - - - - - + + + + + + + - - + + tmain(int,char **) - + tmain(int,char **) - - + + B - + B - - + + A - + A - - - - - - - - + + + + + + + + b(int) - + a1(int) @@ -58,12 +58,12 @@ - + b(double) - + a2(double) @@ -72,12 +72,12 @@ - + b(const char *) - + a3(const char *) diff --git a/docs/test_cases/t20014_sequence.svg b/docs/test_cases/t20014_sequence.svg index 114ec67d..027b0923 100644 --- a/docs/test_cases/t20014_sequence.svg +++ b/docs/test_cases/t20014_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,56 +9,56 @@ - - - - - - - - + + + + + + + + - - + + tmain() - + tmain() - - + + B - + B - - + + A - + A - - + + C<B,int> - + C<B,int> - - - - - - - - - + + + + + + + + + b1(int,int) - + a1(int,int) @@ -67,12 +67,12 @@ - + b2(int,int) - + a2(int,int) @@ -81,17 +81,17 @@ - + c1(int,int) - + b1(int,int) - + a1(int,int) diff --git a/docs/test_cases/t20015_sequence.svg b/docs/test_cases/t20015_sequence.svg index 0390bd71..e11dad3c 100644 --- a/docs/test_cases/t20015_sequence.svg +++ b/docs/test_cases/t20015_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,25 +9,25 @@ - - + + - - + + tmain() - + tmain() - - + + B - + B - - - + + + setup_a(std::shared_ptr<detail::A> &) diff --git a/docs/test_cases/t20016_sequence.svg b/docs/test_cases/t20016_sequence.svg index f5081c3b..962dce47 100644 --- a/docs/test_cases/t20016_sequence.svg +++ b/docs/test_cases/t20016_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,53 +9,53 @@ - - - - - + + + + + - - + + tmain() - + tmain() - - + + B<long> - + B<long> - - + + A - + A - - - - - - + + + + + + b1(long) - + a1(int) - + b2(long) - + a2(const long &) diff --git a/docs/test_cases/t20017_sequence.svg b/docs/test_cases/t20017_sequence.svg index b89b3337..cdaed217 100644 --- a/docs/test_cases/t20017_sequence.svg +++ b/docs/test_cases/t20017_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,65 +9,65 @@ - - - - - - + + + + + + - + t20017.cc - + t20017.cc - + include/t20017_a.h - + include/t20017_a.h - + include/t20017_b.h - + include/t20017_b.h - - - - - - + + + + + + tmain() - + a3(int,int) - + b1(int,int) - + a2(int,int) - + a1(int,int) - + b2<int>(int,int) diff --git a/docs/test_cases/t20018_sequence.svg b/docs/test_cases/t20018_sequence.svg index 9b44f8bf..bc2c08cd 100644 --- a/docs/test_cases/t20018_sequence.svg +++ b/docs/test_cases/t20018_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,14 +9,14 @@ - - - - - - - - + + + + + + + + @@ -25,93 +25,93 @@ - - + + tmain() - + tmain() - - + + Answer<Factorial<5>,120> - + Answer<Factorial<5>,120> - - + + Factorial<5> - + Factorial<5> - - + + Factorial<4> - + Factorial<4> - - + + Factorial<3> - + Factorial<3> - - + + Factorial<2> - + Factorial<2> - - + + Factorial<1> - + Factorial<1> - - + + Factorial<0> - + Factorial<0> - - - - - - - - - + + + + + + + + + print() - + print(int) - + print(int) - + print(int) - + print(int) - + print(int) - + print(int) diff --git a/docs/test_cases/t20019_sequence.svg b/docs/test_cases/t20019_sequence.svg index cd8b929e..14396154 100644 --- a/docs/test_cases/t20019_sequence.svg +++ b/docs/test_cases/t20019_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,95 +9,95 @@ - - - - - - - - - + + + + + + + + + - - + + tmain() - + tmain() - - + + Base<D1> - + Base<D1> - - + + D1 - + D1 - - + + Base<D2> - + Base<D2> - - + + D2 - + D2 - - - - - - - - - - + + + + + + + + + + name() - + impl() - + name() - + impl() - + name() - + impl() - + name() - + impl() diff --git a/docs/test_cases/t20020_sequence.svg b/docs/test_cases/t20020_sequence.svg index 2112460f..fc2b5802 100644 --- a/docs/test_cases/t20020_sequence.svg +++ b/docs/test_cases/t20020_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,82 +9,82 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - - - + + + - - + + tmain() - + tmain() - - + + A - + A - - + + C - + C - - + + B - + B - - + + D<int> - + D<int> - - - - - - - - - - - - - - + + + + + + + + + + + + + + alt - + a1() @@ -92,7 +92,7 @@ - + a5() @@ -103,7 +103,7 @@ alt - + [ @@ -112,7 +112,7 @@ - + [ @@ -121,7 +121,7 @@ - + b1() @@ -129,7 +129,7 @@ - + [ @@ -138,7 +138,7 @@ - + b2() @@ -146,14 +146,14 @@ - + a4() - + log() @@ -161,7 +161,7 @@ alt - + c1() const @@ -169,7 +169,7 @@ alt - + @@ -182,7 +182,7 @@ - + @@ -192,7 +192,7 @@ alt - + d1(int,int) diff --git a/docs/test_cases/t20021_sequence.svg b/docs/test_cases/t20021_sequence.svg index 97528f44..92c17a29 100644 --- a/docs/test_cases/t20021_sequence.svg +++ b/docs/test_cases/t20021_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,74 +9,74 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + tmain() - + tmain() - - + + C - + C - - + + A - + A - - + + B - + B - - - - - - - - - - - - + + + + + + + + + + + + loop - + [ c4() ] - + @@ -89,7 +89,7 @@ - + a3() @@ -102,7 +102,7 @@ loop - + [ @@ -111,7 +111,7 @@ - + [ @@ -120,7 +120,7 @@ - + [ @@ -129,14 +129,14 @@ - + a1() - + [ @@ -148,7 +148,7 @@ loop - + b2() const @@ -158,7 +158,7 @@ loop - + [ @@ -167,7 +167,7 @@ - + b2() const diff --git a/docs/test_cases/t20022_sequence.svg b/docs/test_cases/t20022_sequence.svg index 1477609d..91986e1a 100644 --- a/docs/test_cases/t20022_sequence.svg +++ b/docs/test_cases/t20022_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,47 +9,47 @@ - - - - + + + + - - + + tmain() - + tmain() - - + + A - + A - - + + B - + B - - - - - + + + + + A(std::unique_ptr ) - + a() - + b() diff --git a/docs/test_cases/t20023.md b/docs/test_cases/t20023.md index 2c6e8223..badfc94d 100644 --- a/docs/test_cases/t20023.md +++ b/docs/test_cases/t20023.md @@ -10,7 +10,7 @@ diagrams: namespaces: - clanguml::t20023 using_namespace: clanguml::t20023 - start_from: + from: - function: "clanguml::t20023::tmain()" ``` ## Source code diff --git a/docs/test_cases/t20023_sequence.svg b/docs/test_cases/t20023_sequence.svg index f117304f..c3310108 100644 --- a/docs/test_cases/t20023_sequence.svg +++ b/docs/test_cases/t20023_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,37 +9,37 @@ - - - - - - - + + + + + + + - - + + tmain() - + tmain() - - + + A - + A - - - - - - - + + + + + + + a() @@ -47,7 +47,7 @@ try - + @@ -60,7 +60,7 @@ [std::runtime_error &] - + @@ -73,7 +73,7 @@ [std::logic_error &] - + @@ -86,7 +86,7 @@ [...] - + diff --git a/docs/test_cases/t20024_sequence.svg b/docs/test_cases/t20024_sequence.svg index 7540c26e..6e5bd5ba 100644 --- a/docs/test_cases/t20024_sequence.svg +++ b/docs/test_cases/t20024_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,23 +9,23 @@ - - - - - - - - - - - - + + + + + + + + + + + + - + @@ -33,36 +33,36 @@ - - + + tmain() - + tmain() - - + + A - + A - - + + B - + B - - - - - - - - - - - - + + + + + + + + + + + + select(enum_a) @@ -72,7 +72,7 @@ switch [zero] - + @@ -85,7 +85,7 @@ [one] - + @@ -98,7 +98,7 @@ [two] - + @@ -111,7 +111,7 @@ [default] - + @@ -124,7 +124,7 @@ - + select(colors) @@ -134,7 +134,7 @@ switch [enum colors::red] - + @@ -143,7 +143,7 @@ [enum colors::orange] - + @@ -152,7 +152,7 @@ [enum colors::green] - + @@ -161,7 +161,7 @@ [default] - + diff --git a/docs/test_cases/t20025_sequence.svg b/docs/test_cases/t20025_sequence.svg index 91b42521..d58cf084 100644 --- a/docs/test_cases/t20025_sequence.svg +++ b/docs/test_cases/t20025_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,41 +9,41 @@ - - - + + + - - + + tmain() - + tmain() - - + + A - + A - - + + add(int,int) - + add(int,int) - - - - + + + + a() - + diff --git a/docs/test_cases/t20026_sequence.svg b/docs/test_cases/t20026_sequence.svg index ccf59e20..eb1f94d7 100644 --- a/docs/test_cases/t20026_sequence.svg +++ b/docs/test_cases/t20026_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,25 +9,25 @@ - - + + - - + + tmain() - + tmain() - - + + A - + A - - - + + + a() diff --git a/docs/test_cases/t20027_sequence.svg b/docs/test_cases/t20027_sequence.svg index 80fbbdb1..1d62b95c 100644 --- a/docs/test_cases/t20027_sequence.svg +++ b/docs/test_cases/t20027_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,25 +9,25 @@ - - + + - - + + tmain() - + tmain() - - + + A - + A - - - + + + a() diff --git a/docs/test_cases/t20028_sequence.svg b/docs/test_cases/t20028_sequence.svg index 02db5a02..2bf5af90 100644 --- a/docs/test_cases/t20028_sequence.svg +++ b/docs/test_cases/t20028_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,36 +9,36 @@ - - - - - - + + + + + + - - + + tmain() - + tmain() - - + + A - + A - - - - - + + + + + alt - + [ @@ -47,14 +47,14 @@ - + b() - + c() @@ -62,7 +62,7 @@ - + d() diff --git a/docs/test_cases/t20029_sequence.svg b/docs/test_cases/t20029_sequence.svg index a1fdb75a..6dfd0bd8 100644 --- a/docs/test_cases/t20029_sequence.svg +++ b/docs/test_cases/t20029_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,69 +9,69 @@ - - - - - - - - - - - + + + + + + + + + + + - - + + tmain() - + tmain() - - + + Encoder<Retrier<ConnectionPool>> - + Encoder<Retrier<ConnectionPool>> - - + + Retrier<ConnectionPool> - + Retrier<ConnectionPool> - - + + ConnectionPool - + ConnectionPool - - + + encode_b64(std::string &&) - + encode_b64(std::string &&) - - - - - - - - + + + + + + + + Establish connection to the remote server synchronously - + connect() - + Repeat for each line in the input stream @@ -81,26 +81,26 @@ alt - + [ send(std::string &&) ] - + Encode the message using Base64 encoding and pass it to the next layer - + encode(std::string &&) - + @@ -110,12 +110,12 @@ - + send(std::string &&) - + Repeat until send() succeeds or retry count is exceeded @@ -125,7 +125,7 @@ alt - + [ diff --git a/docs/test_cases/t20030_sequence.svg b/docs/test_cases/t20030_sequence.svg index fcd836fe..49241797 100644 --- a/docs/test_cases/t20030_sequence.svg +++ b/docs/test_cases/t20030_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,81 +9,81 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + tmain(int) - + tmain(int) - - + + magic() - + magic() - - + + A - + A - - + + tmain(bool,int) - + tmain(bool,int) - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + A(int) - + operator+=(int) - + @@ -92,36 +92,36 @@ - + A() - + create() - + A() - + create() - + operator+=(int) - + @@ -130,12 +130,12 @@ - + operator=(const A &) - + @@ -144,7 +144,7 @@ - + value() const diff --git a/docs/test_cases/t20031_sequence.svg b/docs/test_cases/t20031_sequence.svg index f6455804..037b46f8 100644 --- a/docs/test_cases/t20031_sequence.svg +++ b/docs/test_cases/t20031_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,64 +9,64 @@ - - - - - + + + + + - - + + tmain(int) - + tmain(int) - - + + magic() - + magic() - - + + tmain(bool,int) - + tmain(bool,int) - - + + execute(std::function<int ()>) - + execute(std::function<int ()>) - - + + A - + A - - - - - - + + + + + + - + - + value() const diff --git a/docs/test_cases/t20032_sequence.svg b/docs/test_cases/t20032_sequence.svg index a04166a3..97f7ce2b 100644 --- a/docs/test_cases/t20032_sequence.svg +++ b/docs/test_cases/t20032_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,47 +9,47 @@ - - - - - - - + + + + + + + - - + + tmain(int,char **) - + tmain(int,char **) - - + + B - + B - - + + A - + A - - - - - - - - + + + + + + + + b(int) - + a1(int) @@ -60,12 +60,12 @@ int - + b(double) - + a2(double) @@ -76,12 +76,12 @@ double - + b(const char *) - + a3(const char *) diff --git a/docs/test_cases/t20033_sequence.svg b/docs/test_cases/t20033_sequence.svg index a7c0bb38..891f620a 100644 --- a/docs/test_cases/t20033_sequence.svg +++ b/docs/test_cases/t20033_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,73 +9,73 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - + + + + + - + - - + + tmain() - + tmain() - - + + A - + A - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + alt [false] [reinterpret_cast<uint64_t>(&a) % 100 == 0ULL] - + a1() @@ -84,7 +84,7 @@ [reinterpret_cast<uint64_t>(&a) % 64 == 0ULL] - + a2() @@ -93,7 +93,7 @@ [a.a2() == 2 && a.a3() == 3] - + [ @@ -102,7 +102,7 @@ - + [ @@ -111,7 +111,7 @@ - + a3() @@ -119,7 +119,7 @@ - + a4() @@ -130,7 +130,7 @@ alt [int i = a.a2(); i != 2] - + [ @@ -139,7 +139,7 @@ - + a3() @@ -150,7 +150,7 @@ loop [int i = 0; i < a.a2(); i++] - + [ @@ -159,14 +159,14 @@ - + a3() - + a3() @@ -177,7 +177,7 @@ loop [retry_count--] - + a2() @@ -188,14 +188,14 @@ loop [retry_count++ < a.a3()] - + a4() - + [ @@ -208,7 +208,7 @@ alt [a.a4() % 6] - + [ @@ -222,7 +222,7 @@ loop [ints] - + a4() diff --git a/docs/test_cases/t20033_sequence_mermaid.svg b/docs/test_cases/t20033_sequence_mermaid.svg index 95d14083..8d2b358d 100644 --- a/docs/test_cases/t20033_sequence_mermaid.svg +++ b/docs/test_cases/t20033_sequence_mermaid.svg @@ -1,18 +1,18 @@ - + - - + + A - - + + tmain() - + @@ -21,7 +21,7 @@ - + @@ -68,7 +68,7 @@ - + @@ -112,108 +112,111 @@ a.a3() == 3] - + - + - - - + + + alt - [int i = a.a2(); + [int i = - i != 2] + a.a2()&; i != + + + 2] - + - + - - - - - - loop - - [int i = 0; i < - + + + + + + loop - a.a2(); i++] + [int i = 0&; i < + + + a.a2()&; i++] - + - + - - - - - - loop - + + + + + + loop + [retry_count--] - + - + - - - - - - loop - + + + + + + loop + [retry_count++ < - + a.a3()] - + - - - - - - - alt - + + + + + + + alt + [a.a4() % 6] - + - - - - - - loop - + + + + + + loop + [ints] @@ -241,44 +244,44 @@ ​ - [a2()] - - ​ - - a3() - - ​ - - [a2()] - - ​ - - a3() - - ​ - - a3() - - ​ - - a2() - - ​ - - a4() - - ​ - - [a3()] - - ​ - - [a4()] - - ​ - - a4() - - ​ - + [a2()] + + ​ + + a3() + + ​ + + [a2()] + + ​ + + a3() + + ​ + + a3() + + ​ + + a2() + + ​ + + a4() + + ​ + + [a3()] + + ​ + + [a4()] + + ​ + + a4() + + ​ + diff --git a/docs/test_cases/t20034_sequence.svg b/docs/test_cases/t20034_sequence.svg index e01cb20e..8199a3de 100644 --- a/docs/test_cases/t20034_sequence.svg +++ b/docs/test_cases/t20034_sequence.svg @@ -1,6 +1,6 @@ - + @@ -14,154 +14,154 @@ - - + + D - + D - - + + C - + C - - + + B - + B - - + + A - + A - - + + D::d2()::(lambda t20034.cc:56:18) - + D::d2()::(lambda t20034.cc:56:18) d2() - + c2() - + b2() - + a2() - + d2() - + a2() - + d2() - + operator()() - + a2() - + d2() - + c4() - + b4() - + b2() - + a2() - + d2() - + c1() - + b1() - + a2() - + d2() - + c3() - + c2() - + b2() - + a2() diff --git a/docs/test_cases/t20035_sequence.svg b/docs/test_cases/t20035_sequence.svg index a9a8975a..7b4681e5 100644 --- a/docs/test_cases/t20035_sequence.svg +++ b/docs/test_cases/t20035_sequence.svg @@ -1,6 +1,6 @@ - + @@ -13,39 +13,39 @@ - - + + tmain(int,char **) - + tmain(int,char **) - - + + a(int) - + a(int) - - + + b1(int) - + b1(int) - - + + c(int) - + c(int) - + - + - + diff --git a/docs/test_cases/t20036_sequence.svg b/docs/test_cases/t20036_sequence.svg index 11ce0451..b37d6f13 100644 --- a/docs/test_cases/t20036_sequence.svg +++ b/docs/test_cases/t20036_sequence.svg @@ -1,6 +1,6 @@ - + @@ -13,131 +13,131 @@ - - + + C - + C - - + + B - + B - - + + A - + A - - + + D - + D c1() - + b1() - + a2() - + d1() - + c2() - + b2() - + a2() - + d3() - + a2() - + c4() - + b2() - + a2() - + c3() - + c2() - + b2() - + a2() - + d2() - + c2() - + b2() - + a2() diff --git a/docs/test_cases/t20037_sequence.svg b/docs/test_cases/t20037_sequence.svg index 3f95d0cb..456b5ff2 100644 --- a/docs/test_cases/t20037_sequence.svg +++ b/docs/test_cases/t20037_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,95 +9,95 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - + + tmain(int,char **) - + tmain(int,char **) - - + + a() - + a() - - + + A - + A - - + + initb() - + initb() - - + + B - + B - - + + c() - + c() - - - - - - - - - - - - - + + + + + + + + + + + + + - + A() - + - + get() - + @@ -105,18 +105,18 @@ - + - + get() - + @@ -124,18 +124,18 @@ - + - + get() - + diff --git a/docs/test_cases/t20038_sequence.svg b/docs/test_cases/t20038_sequence.svg index 2b71e19d..8974e5ef 100644 --- a/docs/test_cases/t20038_sequence.svg +++ b/docs/test_cases/t20038_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,29 +9,29 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + @@ -39,62 +39,62 @@ - - + + tmain() - + tmain() - - + + B - + B - - + + A - + A - - + + add<int>(int,int) - + add<int>(int,int) - - + + add_impl<int>(int,int) - + add_impl<int>(int,int) - - + + add_impl<double>(double,double) - + add_impl<double>(double,double) - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + Nisl purus in mollis nunc sed id semper. Varius vel pharetra vel turpis. Arcu @@ -111,18 +111,18 @@ alt - + Repeat 5 times... loop - + b() - + a() @@ -132,15 +132,15 @@ - + ... or just once - + b() - + a() @@ -149,12 +149,12 @@ - + bbb() - + aaa() @@ -163,24 +163,24 @@ - + bbbb() - + aaaa() - + - + Invoke 'add' implementation - + @@ -192,47 +192,47 @@ - + This comment should be rendered only once - + wrap(int) - + What is 2 + 2? - + - + Calling B::bbbbb() - + bbbbb() - + aaaa() - + - + Invoke 'add' implementation - + @@ -244,20 +244,20 @@ - + This is a conditional operator alt - + [ bbb() ] - + aaa() diff --git a/docs/test_cases/t20039_sequence.svg b/docs/test_cases/t20039_sequence.svg index 5f6ae479..bc8c47e0 100644 --- a/docs/test_cases/t20039_sequence.svg +++ b/docs/test_cases/t20039_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,13 +9,13 @@ - - - - - - - + + + + + + + @@ -23,89 +23,89 @@ - - + + tmain() - + tmain() - - + + R - + R - - + + A<int> - + A<int> - - + + A<int_vec_t> - + A<int_vec_t> - - + + A<string_vec_t> - + A<string_vec_t> - - + + A<int_map_t> - + A<int_map_t> - - + + A<string_map_t> - + A<string_map_t> - - - - - - - - + + + + + + + + run() - + a(int) - + a(int_vec_t) - + a(string_vec_t) - + a(int_map_t) - + a(string_map_t) diff --git a/docs/test_cases/t20040_sequence.svg b/docs/test_cases/t20040_sequence.svg index 08a3f72c..5816cb24 100644 --- a/docs/test_cases/t20040_sequence.svg +++ b/docs/test_cases/t20040_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,15 +9,15 @@ - - - - - - - - - + + + + + + + + + @@ -26,92 +26,92 @@ - - + + tmain() - + tmain() - - + + print<int,double,std::string>(int,double,std::string) - + print<int,double,std::string>(int,double,std::string) - - + + print<double,std::string>(double,std::string) - + print<double,std::string>(double,std::string) - - + + print<std::string>(std::string) - + print<std::string>(std::string) - - + + print() - + print() - - + + doublePrint<std::string,int>(std::string,int) - + doublePrint<std::string,int>(std::string,int) - - + + print<std::string,int>(std::string,int) - + print<std::string,int>(std::string,int) - - + + print<int>(int) - + print<int>(int) - - - - - - - - - - + + + + + + + + + + - + - + - + - + - + - + - + diff --git a/docs/test_cases/t20041_sequence.svg b/docs/test_cases/t20041_sequence.svg index d9329c18..4bfe6bd4 100644 --- a/docs/test_cases/t20041_sequence.svg +++ b/docs/test_cases/t20041_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,67 +9,67 @@ - - - - - + + + + + - - + + tmain() - + tmain() - - + + A<int,double,std::string> - + A<int,double,std::string> - - + + A<double,std::string> - + A<double,std::string> - - + + A<std::string> - + A<std::string> - - + + A - + A - - - - - - + + + + + + print(int,double,std::string) - + print(double,std::string) - + print(std::string) - + print() diff --git a/docs/test_cases/t20042_sequence.svg b/docs/test_cases/t20042_sequence.svg index 29576e62..98a1c34f 100644 --- a/docs/test_cases/t20042_sequence.svg +++ b/docs/test_cases/t20042_sequence.svg @@ -1,6 +1,6 @@ - + @@ -9,55 +9,55 @@ - - - - - + + + + + - - + + tmain() - + tmain() - - + + AHandler - + AHandler - - + + BHandler - + BHandler - - - - - - + + + + + + operator()(A &) const - + handle(A &) const - + operator()(B &) const - + diff --git a/docs/test_cases/t20043.md b/docs/test_cases/t20043.md new file mode 100644 index 00000000..3c780e31 --- /dev/null +++ b/docs/test_cases/t20043.md @@ -0,0 +1,206 @@ +# t20043 - Test case for elements diagram filter in sequence diagrams +## Config +```yaml +diagrams: + t20043_sequence: + type: sequence + glob: + - t20043.cc + include: + namespaces: + - clanguml::t20043 + exclude: + elements: + - clanguml::t20043::B + - clanguml::t20043::F + namespaces: + - clanguml::t20043::detail + using_namespace: clanguml::t20043 + from: + - function: "clanguml::t20043::tmain()" + +``` +## Source code +File `tests/t20043/t20043.cc` +```cpp +namespace clanguml { +namespace t20043 { +struct A { + int a() { return 1; } +}; + +struct B { + A a; + int b() { return a.a(); } +}; + +struct C { + B b; + int c() { return b.b(); } +}; + +namespace detail { +struct E { + void e() { } +}; +} // namespace detail + +struct D { + C c; + detail::E e; + int d() + { + e.e(); + return c.c(); + } +}; + +struct F { + void f() { } +}; + +int tmain() +{ + D d; + F f; + + f.f(); + + return d.d(); +} +} +} +``` +## Generated PlantUML diagrams +![t20043_sequence](./t20043_sequence.svg "Test case for elements diagram filter in sequence diagrams") +## Generated Mermaid diagrams +![t20043_sequence](./t20043_sequence_mermaid.svg "Test case for elements diagram filter in sequence diagrams") +## Generated JSON models +```json +{ + "diagram_type": "sequence", + "name": "t20043_sequence", + "participants": [ + { + "display_name": "tmain()", + "id": "1396184337601679046", + "name": "tmain", + "namespace": "clanguml::t20043", + "source_location": { + "column": 5, + "file": "t20043.cc", + "line": 37, + "translation_unit": "t20043.cc" + }, + "type": "function" + }, + { + "activities": [ + { + "display_name": "d()", + "id": "60379393461478854", + "name": "d", + "namespace": "", + "source_location": { + "column": 9, + "file": "t20043.cc", + "line": 26, + "translation_unit": "t20043.cc" + }, + "type": "method" + } + ], + "display_name": "D", + "id": "1632049250551188852", + "name": "D", + "namespace": "clanguml::t20043", + "source_location": { + "column": 8, + "file": "t20043.cc", + "line": 23, + "translation_unit": "t20043.cc" + }, + "type": "class" + }, + { + "activities": [ + { + "display_name": "c()", + "id": "998868776840486830", + "name": "c", + "namespace": "", + "source_location": { + "column": 9, + "file": "t20043.cc", + "line": 14, + "translation_unit": "t20043.cc" + }, + "type": "method" + } + ], + "display_name": "C", + "id": "605388621050971304", + "name": "C", + "namespace": "clanguml::t20043", + "source_location": { + "column": 8, + "file": "t20043.cc", + "line": 12, + "translation_unit": "t20043.cc" + }, + "type": "class" + } + ], + "sequences": [ + { + "messages": [ + { + "from": { + "activity_id": "1396184337601679046", + "participant_id": "1396184337601679046" + }, + "name": "d()", + "return_type": "int", + "scope": "normal", + "source_location": { + "column": 12, + "file": "t20043.cc", + "line": 44, + "translation_unit": "t20043.cc" + }, + "to": { + "activity_id": "60379393461478854", + "participant_id": "1632049250551188852" + }, + "type": "message" + }, + { + "from": { + "activity_id": "60379393461478854", + "participant_id": "1632049250551188852" + }, + "name": "c()", + "return_type": "int", + "scope": "normal", + "source_location": { + "column": 16, + "file": "t20043.cc", + "line": 29, + "translation_unit": "t20043.cc" + }, + "to": { + "activity_id": "998868776840486830", + "participant_id": "605388621050971304" + }, + "type": "message" + } + ], + "start_from": { + "id": 1396184337601679046, + "location": "clanguml::t20043::tmain()" + } + } + ], + "using_namespace": "clanguml::t20043" +} +``` diff --git a/docs/test_cases/t20043_sequence.svg b/docs/test_cases/t20043_sequence.svg new file mode 100644 index 00000000..c8ace2c2 --- /dev/null +++ b/docs/test_cases/t20043_sequence.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + tmain() + + tmain() + + + + D + + D + + + + C + + C + + + + + + + + d() + + + + + c() + + + + + + + diff --git a/docs/test_cases/t20043_sequence_mermaid.svg b/docs/test_cases/t20043_sequence_mermaid.svg new file mode 100644 index 00000000..ff9c194d --- /dev/null +++ b/docs/test_cases/t20043_sequence_mermaid.svg @@ -0,0 +1,102 @@ + + + + + C + + + + + + D + + + + + + tmain() + + + + + + + + C + + + + + + + + + D + + + + + + + + + tmain() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d() + + c() + + ​ + + ​ + + diff --git a/docs/test_cases/t30001_package.svg b/docs/test_cases/t30001_package.svg index fedeabf6..0d215c7f 100644 --- a/docs/test_cases/t30001_package.svg +++ b/docs/test_cases/t30001_package.svg @@ -1,6 +1,6 @@ - + @@ -10,63 +10,63 @@ Basic package diagram example - - + + A - - + + AA - - + + B - - + + AA - - + + AAA - - + + BBB - - + + BB - - + + AAA - - + + BBB - - + + BB - + A AAA note... - + This is namespace AA in namespace A - + This is namespace AA in namespace B diff --git a/docs/test_cases/t30002_package.svg b/docs/test_cases/t30002_package.svg index 4542afcb..42e29e0a 100644 --- a/docs/test_cases/t30002_package.svg +++ b/docs/test_cases/t30002_package.svg @@ -1,6 +1,6 @@ - + @@ -9,118 +9,118 @@ - - + + A - - + + AA - - + + B - - + + BB - - + + A1 - - + + A2 - - + + A3 - - + + A4 - - + + A5 - - + + A6 - - + + A7 - - + + A8 - - + + A9 - - + + A10 - - + + A11 - - + + A12 - - + + A13 - - + + A14 - - + + A15 - - + + A16 - - + + A17 - - + + A18 - - + + BBB diff --git a/docs/test_cases/t30003_package.svg b/docs/test_cases/t30003_package.svg index cde0fa53..870b0e1f 100644 --- a/docs/test_cases/t30003_package.svg +++ b/docs/test_cases/t30003_package.svg @@ -1,6 +1,6 @@ - + @@ -9,35 +9,35 @@ - - + + ns1 - - + + ns3 «deprecated» - - + + ns1 - - + + ns2_v1_0_0 - - + + ns2_v0_9_0 «deprecated» - - + + ns2 diff --git a/docs/test_cases/t30004_package.svg b/docs/test_cases/t30004_package.svg index 457ec0a7..7fb0ed2b 100644 --- a/docs/test_cases/t30004_package.svg +++ b/docs/test_cases/t30004_package.svg @@ -1,6 +1,6 @@ - + @@ -9,40 +9,40 @@ - - + + A - + Package AAA. - + Package BBB. - + CCCC package note. - + We skipped DDD. - - + + AAA - - + + BBB - - + + CCC - - + + EEE diff --git a/docs/test_cases/t30005_package.svg b/docs/test_cases/t30005_package.svg index 3b253ec5..73947e17 100644 --- a/docs/test_cases/t30005_package.svg +++ b/docs/test_cases/t30005_package.svg @@ -1,6 +1,6 @@ - + @@ -9,48 +9,48 @@ - - + + A - - + + AA - - + + B - - + + BB - - + + C - - + + CC - - + + AAA - - + + BBB - - + + CCC diff --git a/docs/test_cases/t30006_package.svg b/docs/test_cases/t30006_package.svg index 45a4a817..2554545d 100644 --- a/docs/test_cases/t30006_package.svg +++ b/docs/test_cases/t30006_package.svg @@ -1,6 +1,6 @@ - + @@ -9,22 +9,22 @@ - - + + B - - + + A - - + + C - + Top A note. diff --git a/docs/test_cases/t30007_package.svg b/docs/test_cases/t30007_package.svg index 40ee9f12..918b7f09 100644 --- a/docs/test_cases/t30007_package.svg +++ b/docs/test_cases/t30007_package.svg @@ -1,6 +1,6 @@ - + @@ -9,27 +9,27 @@ - - + + A - - + + B - - + + AA - - + + C - + Compare layout with t30006. diff --git a/docs/test_cases/t30008_package.svg b/docs/test_cases/t30008_package.svg index bab60079..dacda4a0 100644 --- a/docs/test_cases/t30008_package.svg +++ b/docs/test_cases/t30008_package.svg @@ -1,6 +1,6 @@ - + @@ -9,43 +9,43 @@ - - + + dependants - - + + dependencies - - + + A - - + + B - - + + C - - + + D - - + + E - - + + F diff --git a/docs/test_cases/t30009_package.svg b/docs/test_cases/t30009_package.svg index d5d136dd..a24c4f1c 100644 --- a/docs/test_cases/t30009_package.svg +++ b/docs/test_cases/t30009_package.svg @@ -1,6 +1,6 @@ - + @@ -9,53 +9,53 @@ - - + + One - - + + Two - - + + B - - + + D - - + + A - - + + C - - + + A - - + + B - - + + C - - + + D diff --git a/docs/test_cases/t30010_package.svg b/docs/test_cases/t30010_package.svg index 20f38928..55a88e19 100644 --- a/docs/test_cases/t30010_package.svg +++ b/docs/test_cases/t30010_package.svg @@ -1,6 +1,6 @@ - + @@ -9,31 +9,31 @@ - + libraries - - + + lib1 - - + + lib2 - - + + lib3 - - + + lib4 - - + + app diff --git a/docs/test_cases/t30011_package.svg b/docs/test_cases/t30011_package.svg index 9a56b555..c39bda2a 100644 --- a/docs/test_cases/t30011_package.svg +++ b/docs/test_cases/t30011_package.svg @@ -1,6 +1,6 @@ - + @@ -9,31 +9,31 @@ - + libraries - - + + lib1 - - + + lib2 - - + + lib3 - - + + lib4 - - + + app diff --git a/docs/test_cases/t30012_package.svg b/docs/test_cases/t30012_package.svg index d0692405..02d17eb5 100644 --- a/docs/test_cases/t30012_package.svg +++ b/docs/test_cases/t30012_package.svg @@ -1,6 +1,6 @@ - + @@ -9,26 +9,26 @@ - + app - - + + lib1 - - + + mod1 - - + + mod2 - - + + lib2 diff --git a/docs/test_cases/t30013_package.svg b/docs/test_cases/t30013_package.svg index ee3d9f3f..6762bcb4 100644 --- a/docs/test_cases/t30013_package.svg +++ b/docs/test_cases/t30013_package.svg @@ -1,6 +1,6 @@ - + @@ -9,98 +9,98 @@ - - + + mod1 - - + + mod2 - - + + mod3 - - + + mod4 - - + + mod5 - - + + mod6 - - + + mod7 - - + + mod8 - - + + mod9 - - + + mod10 - - + + mod11 - - + + mod12 - - + + mod13 - - + + mod14 - - + + mod15 - - + + mod16 - - + + mod17 - - + + mod18 - - + + app diff --git a/docs/test_cases/t30014_package.svg b/docs/test_cases/t30014_package.svg index 372b8052..a0f74be5 100644 --- a/docs/test_cases/t30014_package.svg +++ b/docs/test_cases/t30014_package.svg @@ -1,6 +1,6 @@ - + @@ -9,21 +9,21 @@ - + app - - + + :lib1 - - + + mod1 - - + + :lib2 diff --git a/docs/test_cases/t30015_package.svg b/docs/test_cases/t30015_package.svg index e3839ff7..04c919ef 100644 --- a/docs/test_cases/t30015_package.svg +++ b/docs/test_cases/t30015_package.svg @@ -1,6 +1,6 @@ - + @@ -9,101 +9,101 @@ - + lib1 - - + + :mod1 - - + + :mod2 - - + + :mod3 - - + + :mod4 - - + + :mod5 - - + + :mod6 - - + + :mod7 - - + + :mod8 - - + + :mod9 - - + + :mod10 - - + + :mod11 - - + + :mod12 - - + + :mod13 - - + + :mod14 - - + + :mod15 - - + + :mod16 - - + + :mod17 - - + + :mod18 - - + + app diff --git a/docs/test_cases/t40001_include.svg b/docs/test_cases/t40001_include.svg index bca6c546..5dd7b52e 100644 --- a/docs/test_cases/t40001_include.svg +++ b/docs/test_cases/t40001_include.svg @@ -1,6 +1,6 @@ - + @@ -10,41 +10,41 @@ Basic include diagram example - + src - + include - + lib1 - - + + t40001.cc - - + + t40001_include1.h - + lib1.h - + string - + vector - + yaml-cpp/yaml.h - + This is a lib1 include dir - + This is a t40001_include1.h include file diff --git a/docs/test_cases/t40001_include_mermaid.svg b/docs/test_cases/t40001_include_mermaid.svg index f40dc95b..86a3bae3 100644 --- a/docs/test_cases/t40001_include_mermaid.svg +++ b/docs/test_cases/t40001_include_mermaid.svg @@ -138,7 +138,7 @@ - + @@ -151,7 +151,7 @@ - + @@ -164,7 +164,7 @@ - + diff --git a/docs/test_cases/t40002_include.svg b/docs/test_cases/t40002_include.svg index d27a6b54..58e2a3a3 100644 --- a/docs/test_cases/t40002_include.svg +++ b/docs/test_cases/t40002_include.svg @@ -1,6 +1,6 @@ - + @@ -9,46 +9,46 @@ - + src - + lib1 - + lib2 - + include - + lib1 - + lib2 - - + + t40002.cc - - + + lib1.cc - - + + lib2.cc - - + + lib1.h - - + + lib2.h diff --git a/docs/test_cases/t40002_include_mermaid.svg b/docs/test_cases/t40002_include_mermaid.svg index 628d4ecd..92fc5a8f 100644 --- a/docs/test_cases/t40002_include_mermaid.svg +++ b/docs/test_cases/t40002_include_mermaid.svg @@ -137,7 +137,7 @@ - + @@ -150,7 +150,7 @@ - + @@ -163,7 +163,7 @@ - + @@ -176,7 +176,7 @@ - + @@ -189,7 +189,7 @@ - + diff --git a/docs/test_cases/t40003_include.svg b/docs/test_cases/t40003_include.svg index ce70b344..c7da6c7b 100644 --- a/docs/test_cases/t40003_include.svg +++ b/docs/test_cases/t40003_include.svg @@ -1,6 +1,6 @@ - + @@ -9,62 +9,62 @@ - + src - + dependants - + dependencies - + include - + dependants - + dependencies - - + + t1.cc - - + + t2.cc - - + + t3.h - - + + t2.h - + t1.h - - + + t3.h - - + + t2.h - + t1.h - - + + t5.h diff --git a/docs/test_cases/t40003_include_mermaid.svg b/docs/test_cases/t40003_include_mermaid.svg index 6ae15961..7e7c556a 100644 --- a/docs/test_cases/t40003_include_mermaid.svg +++ b/docs/test_cases/t40003_include_mermaid.svg @@ -167,7 +167,7 @@ - + @@ -180,7 +180,7 @@ - + @@ -193,7 +193,7 @@ - + @@ -206,7 +206,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -232,7 +232,7 @@ - + @@ -245,7 +245,7 @@ - + @@ -258,7 +258,7 @@ - + @@ -271,7 +271,7 @@ - + diff --git a/docs/test_cases/t90000.md b/docs/test_cases/t90000.md index a91ef19f..8bdae289 100644 --- a/docs/test_cases/t90000.md +++ b/docs/test_cases/t90000.md @@ -1,6 +1,7 @@ # t90000 - Basic config test ## Config ```yaml +allow_empty_diagrams: true diagrams: t90000_class: type: class diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index d708e181..1b265f14 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -3,7 +3,7 @@ * [General issues](#general-issues) - * [clang-uml crashes when generating diagram](#clang-uml-crashes-when-generating-diagram) + * [clang-uml crashes when generating a diagram](#clang-uml-crashes-when-generating-a-diagram) * [Diagram generation is very slow](#diagram-generation-is-very-slow) * [Diagram generated with PlantUML is cropped](#diagram-generated-with-plantuml-is-cropped) * [Clang produces several warnings during diagram generation](#clang-produces-several-warnings-during-diagram-generation) @@ -22,7 +22,7 @@ ## General issues -### clang-uml crashes when generating diagram +### clang-uml crashes when generating a diagram If `clang-uml` crashes with a segmentation fault, it is possible to trace the exact stack trace of the fault using the following steps: @@ -346,7 +346,7 @@ the exact string representation of the function signature as seen by `clang-uml` To find the exact function signature run `clang-uml` as follows: ```bash -clang-uml -n my_sequence_diagram --print-start-from | grep foo +clang-uml -n my_sequence_diagram --print-from | grep foo ``` Command line flag `--print-from` will print on stdout all functions diff --git a/packaging/autocomplete/_clang-uml b/packaging/autocomplete/_clang-uml index c0a10c0a..1ea0a0f8 100644 --- a/packaging/autocomplete/_clang-uml +++ b/packaging/autocomplete/_clang-uml @@ -46,6 +46,7 @@ _arguments \ '--add-compile-flag[Add a compilation flag to each entry in the compilation database]' \ '--remove-compile-flag[Remove a compilation flag from each entry in the compilation database]' \ '--query-driver[Query the specific compiler driver to extract system paths and add to compile commands (e.g. arm-none-eabi-g++)]' \ + '--allow-empty-diagrams[Do not raise an error when generated diagram model is empty]' \ '--add-class-diagram[Add class diagram config]' \ '--add-sequence-diagram[Add sequence diagram config]' \ '--add-package-diagram[Add package diagram config]' \ diff --git a/packaging/autocomplete/clang-uml b/packaging/autocomplete/clang-uml index 4e2cb8e7..cd45aa3f 100644 --- a/packaging/autocomplete/clang-uml +++ b/packaging/autocomplete/clang-uml @@ -98,6 +98,7 @@ _clanguml() { --add-compile-flag \ --remove-compile-flag \ --query-driver \ + --allow-empty-diagrams \ --add-class-diagram \ --add-sequence-diagram \ --add-package-diagram \ diff --git a/packaging/debian/rules b/packaging/debian/rules index 1ec8c07e..8235e685 100755 --- a/packaging/debian/rules +++ b/packaging/debian/rules @@ -8,7 +8,7 @@ export CLANGUML_GIT_COMMIT={{GIT_COMMIT}} override_dh_auto_configure: dh_auto_configure --buildsystem=cmake -- -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_CXX_FLAGS="-Wno-nonnull -Wno-stringop-overflow -Wno-dangling-reference" \ + -DCMAKE_CXX_FLAGS="-Wno-nonnull -Wno-stringop-overflow -Wno-dangling-reference -Wno-unused-but-set-parameter" \ -DCMAKE_INSTALL_PREFIX=/usr \ -DGIT_VERSION={{VERSION}} \ -DBUILD_TESTS=OFF diff --git a/src/class_diagram/model/diagram.cc b/src/class_diagram/model/diagram.cc index a062cad2..270bef0b 100644 --- a/src/class_diagram/model/diagram.cc +++ b/src/class_diagram/model/diagram.cc @@ -249,6 +249,11 @@ void diagram::remove_redundant_dependencies() } } +bool diagram::is_empty() const +{ + return element_view::is_empty() && + element_view::is_empty() && element_view::is_empty(); +} } // namespace clanguml::class_diagram::model namespace clanguml::common::model { diff --git a/src/class_diagram/model/diagram.h b/src/class_diagram/model/diagram.h index 835035a4..3415e12e 100644 --- a/src/class_diagram/model/diagram.h +++ b/src/class_diagram/model/diagram.h @@ -249,6 +249,13 @@ public: */ inja::json context() const override; + /** + * @brief Check whether the diagram is empty + * + * @return True, if diagram is empty + */ + bool is_empty() const override; + private: template bool add_with_namespace_path(std::unique_ptr &&e); diff --git a/src/cli/cli_handler.cc b/src/cli/cli_handler.cc index 7bc94d21..36d343ca 100644 --- a/src/cli/cli_handler.cc +++ b/src/cli/cli_handler.cc @@ -107,6 +107,8 @@ cli_flow_t cli_handler::parse(int argc, const char **argv) "Query the specific compiler driver to extract system paths and add to " "compile commands (e.g. arm-none-eabi-g++)"); #endif + app.add_flag("--allow-empty-diagrams", allow_empty_diagrams, + "Do not raise an error when generated diagram model is empty"); app.add_option( "--add-class-diagram", add_class_diagram, "Add class diagram config"); app.add_option("--add-sequence-diagram", add_sequence_diagram, @@ -302,6 +304,10 @@ cli_flow_t cli_handler::handle_post_config_options() LOG_INFO("Loaded clang-uml config from {}", config_path); + if (allow_empty_diagrams) { + config.allow_empty_diagrams.set(true); + } + // // Override selected config options from command line // diff --git a/src/cli/cli_handler.h b/src/cli/cli_handler.h index 2aec25a7..ae222369 100644 --- a/src/cli/cli_handler.h +++ b/src/cli/cli_handler.h @@ -165,6 +165,7 @@ public: bool list_diagrams{false}; bool quiet{false}; bool initialize{false}; + bool allow_empty_diagrams{false}; std::optional> add_compile_flag; std::optional> remove_compile_flag; #if !defined(_WIN32) diff --git a/src/common/compilation_database.cc b/src/common/compilation_database.cc index dc9fe9ec..5553b36d 100644 --- a/src/common/compilation_database.cc +++ b/src/common/compilation_database.cc @@ -88,6 +88,21 @@ std::string compilation_database::guess_language_from_filename( return "c++"; } +long compilation_database::count_matching_commands( + const std::vector &files) const +{ + auto result{0L}; + + auto commands = base().getAllCompileCommands(); + + for (const auto &command : commands) { + result += std::count_if(files.begin(), files.end(), + [&command](const auto &file) { return command.Filename == file; }); + } + + return result; +} + void compilation_database::adjust_compilation_database( std::vector &commands) const { diff --git a/src/common/compilation_database.h b/src/common/compilation_database.h index e1532b87..5a4125f1 100644 --- a/src/common/compilation_database.h +++ b/src/common/compilation_database.h @@ -103,6 +103,8 @@ public: std::string guess_language_from_filename(const std::string &filename) const; + long count_matching_commands(const std::vector &files) const; + private: void adjust_compilation_database( std::vector &commands) const; diff --git a/src/common/generators/generators.cc b/src/common/generators/generators.cc index 2a3f1e5b..03494ceb 100644 --- a/src/common/generators/generators.cc +++ b/src/common/generators/generators.cc @@ -95,11 +95,17 @@ void generate_diagram_select_generator(const std::string &od, using diagram_generator = typename diagram_generator_t::type; + std::stringstream buffer; + buffer << diagram_generator( + dynamic_cast(*diagram), *model); + + // Only open the file after the diagram has been generated successfully + // in order not to overwrite previous diagram in case of failure auto path = std::filesystem::path{od} / fmt::format("{}.{}", name, GeneratorTag::extension); std::ofstream ofs; ofs.open(path, std::ofstream::out | std::ofstream::trunc); - ofs << diagram_generator(dynamic_cast(*diagram), *model); + ofs << buffer.str(); ofs.close(); @@ -240,13 +246,16 @@ void generate_diagrams(const std::vector &diagram_names, continue; } + const auto matching_commands_count = + db->count_matching_commands(valid_translation_units); + auto generator = [&name = name, &diagram = diagram, &indicator, - db = std::ref(*db), + db = std::ref(*db), matching_commands_count, translation_units = valid_translation_units, runtime_config]() mutable { try { if (indicator) - indicator->add_progress_bar(name, translation_units.size(), + indicator->add_progress_bar(name, matching_commands_count, diagram_type_to_color(diagram->type())); generate_diagram(name, diagram, db, translation_units, @@ -258,11 +267,12 @@ void generate_diagrams(const std::vector &diagram_names, if (indicator) indicator->complete(name); } - catch (std::exception &e) { + catch (const std::exception &e) { if (indicator) indicator->fail(name); - LOG_ERROR(e.what()); + LOG_ERROR( + "ERROR: Failed to generate diagram {}: {}", name, e.what()); } }; diff --git a/src/common/generators/json/generator.h b/src/common/generators/json/generator.h index d76037a0..dea6b3d4 100644 --- a/src/common/generators/json/generator.h +++ b/src/common/generators/json/generator.h @@ -107,11 +107,19 @@ std::ostream &operator<<( template void generator::generate(std::ostream &ostr) const { + const auto &config = generators::generator::config(); + const auto &model = generators::generator::model(); + + if (!config.allow_empty_diagrams() && model.is_empty()) { + throw clanguml::error::empty_diagram_error{ + "Diagram configuration resulted in empty diagram."}; + } + nlohmann::json j; - j["name"] = generators::generator::model().name(); - j["diagram_type"] = to_string(generators::generator::model().type()); - if (generators::generator::config().title) { - j["title"] = generators::generator::config().title(); + j["name"] = model.name(); + j["diagram_type"] = to_string(model.type()); + if (config.title) { + j["title"] = config.title(); } generate_diagram(j); diff --git a/src/common/generators/mermaid/generator.h b/src/common/generators/mermaid/generator.h index 92a72b4a..9333d8b4 100644 --- a/src/common/generators/mermaid/generator.h +++ b/src/common/generators/mermaid/generator.h @@ -250,6 +250,13 @@ template void generator::generate(std::ostream &ostr) const { const auto &config = generators::generator::config(); + const auto &model = generators::generator::model(); + + if (!config.allow_empty_diagrams() && model.is_empty() && + config.mermaid().before.empty() && config.mermaid().after.empty()) { + throw clanguml::error::empty_diagram_error{ + "Diagram configuration resulted in empty diagram."}; + } update_context(); diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 85406e08..dc29cbba 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -265,17 +265,26 @@ template void generator::generate(std::ostream &ostr) const { const auto &config = generators::generator::config(); + const auto &model = generators::generator::model(); update_context(); + if (!config.allow_empty_diagrams() && model.is_empty() && + config.puml().before.empty() && config.puml().after.empty()) { + throw clanguml::error::empty_diagram_error{ + "Diagram configuration resulted in empty diagram."}; + } + ostr << "@startuml" << '\n'; generate_title(ostr); + // Generate PlantUML directives before auto generated content generate_plantuml_directives(ostr, config.puml().before); generate_diagram(ostr); + // Generate PlantUML directives after auto generated content generate_plantuml_directives(ostr, config.puml().after); generate_metadata(ostr); diff --git a/src/common/model/diagram.h b/src/common/model/diagram.h index 28f40f47..89161d6d 100644 --- a/src/common/model/diagram.h +++ b/src/common/model/diagram.h @@ -164,6 +164,13 @@ public: */ virtual inja::json context() const = 0; + /** + * @brief Check whether the diagram is empty + * + * @return True, if diagram is empty + */ + virtual bool is_empty() const = 0; + private: std::string name_; std::unique_ptr filter_; diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index d29db4da..3e807d92 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -346,6 +346,35 @@ tvl::value_t element_filter::match(const diagram &d, const element &e) const }); } +tvl::value_t element_filter::match( + const diagram &d, const sequence_diagram::model::participant &p) const +{ + using sequence_diagram::model::method; + using sequence_diagram::model::participant; + + if (d.type() != diagram_t::kSequence) + return {}; + + const auto &sequence_model = + dynamic_cast(d); + return tvl::any_of(elements_.begin(), elements_.end(), + [&sequence_model, &p](const auto &el) { + if (p.type_name() == "method") { + + const auto &m = dynamic_cast(p); + const auto class_id = m.class_id(); + const auto &class_participant = + sequence_model.get_participant(class_id) + .value(); + + return el == p.full_name(false) || + el == class_participant.full_name(false); + } + + return el == p.full_name(false); + }); +} + element_type_filter::element_type_filter( filter_t type, std::vector element_types) : filter_visitor{type} diff --git a/src/common/model/diagram_filter.h b/src/common/model/diagram_filter.h index 81cd25b6..a3b868ae 100644 --- a/src/common/model/diagram_filter.h +++ b/src/common/model/diagram_filter.h @@ -180,6 +180,9 @@ struct element_filter : public filter_visitor { tvl::value_t match(const diagram &d, const element &e) const override; + tvl::value_t match(const diagram &d, + const sequence_diagram::model::participant &p) const override; + private: std::vector elements_; }; diff --git a/src/common/model/element_view.h b/src/common/model/element_view.h index b7a25c79..bd3ad090 100644 --- a/src/common/model/element_view.h +++ b/src/common/model/element_view.h @@ -69,6 +69,13 @@ public: return {}; } + /** + * @brief Check whether the element view is empty + * + * @return True, if the view does not contain any elements + */ + bool is_empty() const { return elements_.empty(); } + private: reference_vector elements_; }; diff --git a/src/config/config.cc b/src/config/config.cc index 0a59d7d8..0eb83f91 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -237,6 +237,7 @@ void inheritable_diagram_options::inherit( parent.generate_condition_statements); debug_mode.override(parent.debug_mode); generate_metadata.override(parent.generate_metadata); + allow_empty_diagrams.override(parent.allow_empty_diagrams); type_aliases.override(parent.type_aliases); } diff --git a/src/config/config.h b/src/config/config.h index f4ece81a..e76a8bef 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -577,6 +577,7 @@ struct inheritable_diagram_options { "message_comment_width", clanguml::util::kDefaultMessageCommentWidth}; option debug_mode{"debug_mode", false}; option generate_metadata{"generate_metadata", true}; + option allow_empty_diagrams{"allow_empty_diagrams", false}; protected: // This is the relative path with respect to the `base_directory`, diff --git a/src/config/schema.h b/src/config/schema.h index fa76104c..2b0eabb1 100644 --- a/src/config/schema.h +++ b/src/config/schema.h @@ -306,6 +306,7 @@ root: query_driver: !optional string add_compile_flags: !optional [string] remove_compile_flags: !optional [string] + allow_empty_diagrams: !optional bool diagram_templates: !optional diagram_templates_t diagrams: !required map_t # diff --git a/src/config/yaml_decoders.cc b/src/config/yaml_decoders.cc index bcf5f329..a63271d0 100644 --- a/src/config/yaml_decoders.cc +++ b/src/config/yaml_decoders.cc @@ -820,6 +820,7 @@ template <> struct convert { get_option(node, rhs.using_module); get_option(node, rhs.output_directory); get_option(node, rhs.query_driver); + get_option(node, rhs.allow_empty_diagrams); get_option(node, rhs.compilation_database_dir); get_option(node, rhs.add_compile_flags); get_option(node, rhs.remove_compile_flags); diff --git a/src/include_diagram/model/diagram.cc b/src/include_diagram/model/diagram.cc index 9e5b062f..0b385581 100644 --- a/src/include_diagram/model/diagram.cc +++ b/src/include_diagram/model/diagram.cc @@ -151,6 +151,9 @@ inja::json diagram::context() const return ctx; } + +bool diagram::is_empty() const { return element_view::is_empty(); } + } // namespace clanguml::include_diagram::model namespace clanguml::common::model { diff --git a/src/include_diagram/model/diagram.h b/src/include_diagram/model/diagram.h index f9b0dabc..e8a1deba 100644 --- a/src/include_diagram/model/diagram.h +++ b/src/include_diagram/model/diagram.h @@ -131,6 +131,13 @@ public: const common::model::namespace_ &ns) const override; inja::json context() const override; + + /** + * @brief Check whether the diagram is empty + * + * @return True, if diagram is empty + */ + bool is_empty() const override; }; template diff --git a/src/package_diagram/model/diagram.cc b/src/package_diagram/model/diagram.cc index 4ba5e6f0..21a903ed 100644 --- a/src/package_diagram/model/diagram.cc +++ b/src/package_diagram/model/diagram.cc @@ -73,6 +73,8 @@ inja::json diagram::context() const return ctx; } + +bool diagram::is_empty() const { return element_view::is_empty(); } } // namespace clanguml::package_diagram::model namespace clanguml::common::model { diff --git a/src/package_diagram/model/diagram.h b/src/package_diagram/model/diagram.h index 335a5456..f29c9c66 100644 --- a/src/package_diagram/model/diagram.h +++ b/src/package_diagram/model/diagram.h @@ -157,6 +157,13 @@ public: */ inja::json context() const override; + /** + * @brief Check whether the diagram is empty + * + * @return True, if diagram is empty + */ + bool is_empty() const override; + private: /** * @brief Add element using module as diagram path diff --git a/src/sequence_diagram/generators/mermaid/sequence_diagram_generator.cc b/src/sequence_diagram/generators/mermaid/sequence_diagram_generator.cc index e35dbb49..9183c894 100644 --- a/src/sequence_diagram/generators/mermaid/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/mermaid/sequence_diagram_generator.cc @@ -37,7 +37,7 @@ std::string render_participant_name(std::string name) std::string render_message_text(std::string text) { - util::replace_all(text, ";", "#59;"); + util::replace_all(text, ";", ";"); return text; } @@ -481,6 +481,12 @@ void generator::generate_diagram(std::ostream &ostr) const if (from_activity_id == 0 || to_activity_id == 0) continue; + if (model().participants().count(from_activity_id) == 0) + continue; + + if (model().participants().count(to_activity_id) == 0) + continue; + auto message_chains_unique = model().get_all_from_to_message_chains( from_activity_id, to_activity_id); @@ -522,6 +528,9 @@ void generator::generate_diagram(std::ostream &ostr) const for (const auto &mc : message_chains_unique) { const auto from_activity_id = mc.front().from(); + if (model().participants().count(from_activity_id) == 0) + continue; + const auto &from = model().get_participant(from_activity_id); @@ -547,6 +556,9 @@ void generator::generate_diagram(std::ostream &ostr) const if (sf.location_type == location_t::function) { common::id_t start_from{0}; for (const auto &[k, v] : model().sequences()) { + if (model().participants().count(v.from()) == 0) + continue; + const auto &caller = *model().participants().at(v.from()); std::string vfrom = caller.full_name(false); if (vfrom == sf.location) { @@ -566,6 +578,9 @@ void generator::generate_diagram(std::ostream &ostr) const // Use this to break out of recurrent loops std::vector visited_participants; + if (model().participants().count(start_from) == 0) + continue; + const auto &from = model().get_participant(start_from); diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 2207c95d..7d97a80e 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -483,6 +483,12 @@ void generator::generate_diagram(std::ostream &ostr) const if (from_activity_id == 0 || to_activity_id == 0) continue; + if (model().participants().count(from_activity_id) == 0) + continue; + + if (model().participants().count(to_activity_id) == 0) + continue; + auto message_chains_unique = model().get_all_from_to_message_chains( from_activity_id, to_activity_id); @@ -530,6 +536,9 @@ void generator::generate_diagram(std::ostream &ostr) const const auto from_activity_id = mc.front().from(); + if (model().participants().count(from_activity_id) == 0) + continue; + const auto &from = model().get_participant(from_activity_id); @@ -553,6 +562,9 @@ void generator::generate_diagram(std::ostream &ostr) const if (sf.location_type == location_t::function) { common::id_t start_from{0}; for (const auto &[k, v] : model().sequences()) { + if (model().participants().count(v.from()) == 0) + continue; + const auto &caller = *model().participants().at(v.from()); std::string vfrom = caller.full_name(false); if (vfrom == sf.location) { @@ -569,6 +581,9 @@ void generator::generate_diagram(std::ostream &ostr) const continue; } + if (model().participants().count(start_from) == 0) + continue; + // Use this to break out of recurrent loops std::vector visited_participants; diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index 45d2f97a..5edb4220 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -399,6 +399,11 @@ std::vector diagram::get_all_from_to_message_chains( return message_chains_unique; } +bool diagram::is_empty() const +{ + return sequences_.empty() || participants_.empty(); +} + void diagram::print() const { LOG_TRACE(" --- Participants ---"); @@ -408,6 +413,8 @@ void diagram::print() const LOG_TRACE(" --- Activities ---"); for (const auto &[from_id, act] : sequences_) { + if (participants_.count(from_id) == 0) + continue; LOG_TRACE("Sequence id={}:", from_id); diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index e075a04f..3b485b4d 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -280,6 +280,13 @@ public: */ void finalize() override; + /** + * @brief Check whether the diagram is empty + * + * @return True, if diagram is empty + */ + bool is_empty() const override; + private: /** * This method checks the last messages in sequence (current_messages), diff --git a/src/util/error.h b/src/util/error.h index 97ccf513..bd870dd8 100644 --- a/src/util/error.h +++ b/src/util/error.h @@ -36,4 +36,8 @@ class compilation_database_error : public std::runtime_error { using std::runtime_error::runtime_error; }; +class empty_diagram_error : public std::runtime_error { + using std::runtime_error::runtime_error; +}; + } // namespace clanguml::error diff --git a/tests/t20023/.clang-uml b/tests/t20023/.clang-uml index 12759641..dd92d5c7 100644 --- a/tests/t20023/.clang-uml +++ b/tests/t20023/.clang-uml @@ -7,5 +7,5 @@ diagrams: namespaces: - clanguml::t20023 using_namespace: clanguml::t20023 - start_from: + from: - function: "clanguml::t20023::tmain()" \ No newline at end of file diff --git a/tests/t20043/.clang-uml b/tests/t20043/.clang-uml new file mode 100644 index 00000000..7b22cb2e --- /dev/null +++ b/tests/t20043/.clang-uml @@ -0,0 +1,17 @@ +diagrams: + t20043_sequence: + type: sequence + glob: + - t20043.cc + include: + namespaces: + - clanguml::t20043 + exclude: + elements: + - clanguml::t20043::B + - clanguml::t20043::F + namespaces: + - clanguml::t20043::detail + using_namespace: clanguml::t20043 + from: + - function: "clanguml::t20043::tmain()" diff --git a/tests/t20043/t20043.cc b/tests/t20043/t20043.cc new file mode 100644 index 00000000..ad1baa16 --- /dev/null +++ b/tests/t20043/t20043.cc @@ -0,0 +1,47 @@ +namespace clanguml { +namespace t20043 { +struct A { + int a() { return 1; } +}; + +struct B { + A a; + int b() { return a.a(); } +}; + +struct C { + B b; + int c() { return b.b(); } +}; + +namespace detail { +struct E { + void e() { } +}; +} // namespace detail + +struct D { + C c; + detail::E e; + int d() + { + e.e(); + return c.c(); + } +}; + +struct F { + void f() { } +}; + +int tmain() +{ + D d; + F f; + + f.f(); + + return d.d(); +} +} +} \ No newline at end of file diff --git a/tests/t20043/test_case.h b/tests/t20043/test_case.h new file mode 100644 index 00000000..84c0a4e9 --- /dev/null +++ b/tests/t20043/test_case.h @@ -0,0 +1,73 @@ +/** + * tests/t20043/test_case.h + * + * Copyright (c) 2021-2024 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_CASE("t20043", "[test-case][sequence]") +{ + auto [config, db] = load_config("t20043"); + + auto diagram = config.diagrams["t20043_sequence"]; + + REQUIRE(diagram->name == "t20043_sequence"); + + auto model = generate_sequence_diagram(*db, diagram); + + REQUIRE(model->name() == "t20043_sequence"); + + { + auto src = generate_sequence_puml(diagram, *model); + AliasMatcher _A(src); + + REQUIRE_THAT(src, StartsWith("@startuml")); + REQUIRE_THAT(src, EndsWith("@enduml\n")); + + REQUIRE_THAT(src, !HasCall(_A("tmain()"), _A("F"), "f()")); + REQUIRE_THAT(src, HasCall(_A("tmain()"), _A("D"), "d()")); + + REQUIRE_THAT(src, HasCall(_A("D"), _A("C"), "c()")); + REQUIRE_THAT(src, !HasCall(_A("D"), _A("detail::E"), "e()")); + REQUIRE_THAT(src, !HasCall(_A("C"), _A("B"), "b()")); + REQUIRE_THAT(src, !HasCall(_A("B"), _A("A"), "a()")); + + save_puml(config.output_directory(), diagram->name + ".puml", src); + } + + { + auto j = generate_sequence_json(diagram, *model); + + using namespace json; + + save_json(config.output_directory(), diagram->name + ".json", j); + } + + { + auto src = generate_sequence_mermaid(diagram, *model); + + mermaid::SequenceDiagramAliasMatcher _A(src); + using mermaid::HasCall; + + REQUIRE_THAT(src, !HasCall(_A("tmain()"), _A("F"), "f()")); + REQUIRE_THAT(src, HasCall(_A("tmain()"), _A("D"), "d()")); + + REQUIRE_THAT(src, HasCall(_A("D"), _A("C"), "c()")); + REQUIRE_THAT(src, !HasCall(_A("D"), _A("detail::E"), "e()")); + REQUIRE_THAT(src, !HasCall(_A("C"), _A("B"), "b()")); + REQUIRE_THAT(src, !HasCall(_A("B"), _A("A"), "a()")); + + save_mermaid(config.output_directory(), diagram->name + ".mmd", src); + } +} \ No newline at end of file diff --git a/tests/t90000/.clang-uml b/tests/t90000/.clang-uml index 9f020697..3e8100be 100644 --- a/tests/t90000/.clang-uml +++ b/tests/t90000/.clang-uml @@ -1,3 +1,4 @@ +allow_empty_diagrams: true diagrams: t90000_class: type: class diff --git a/tests/t90001/.clang-uml b/tests/t90001/.clang-uml new file mode 100644 index 00000000..63ad4c66 --- /dev/null +++ b/tests/t90001/.clang-uml @@ -0,0 +1,24 @@ +diagrams: + t90001_class: + type: class + include: + namespaces: + - no_such_namespace + t90001_sequence: + type: sequence + include: + namespaces: + - no_such_namespace + from: + - function: "nowhere" + t90001_include: + type: include + include: + namespaces: + - no_such_namespace + t90001_package: + type: package + include: + namespaces: + - no_such_namespace + diff --git a/tests/t90001/t90001.cc b/tests/t90001/t90001.cc new file mode 100644 index 00000000..cb51bff9 --- /dev/null +++ b/tests/t90001/t90001.cc @@ -0,0 +1,88 @@ +#include + +namespace clanguml { +namespace t90001 { + +namespace ns1 { +/// \brief This is class A +class A { +public: + /// Abstract foo_a + virtual void foo_a() = 0; + /// Abstract foo_c + virtual void foo_c() = 0; +}; + +/// \brief This is class B +class B : public A { +public: + virtual void foo_a() override { } +}; + +/// @brief This is class C - class C has a long comment +/// +/// Vivamus integer non suscipit taciti mus etiam at primis tempor sagittis sit, +/// euismod libero facilisi aptent elementum felis blandit cursus gravida sociis +/// erat ante, eleifend lectus nullam dapibus netus feugiat curae curabitur est +/// ad. +class C : public A { +public: + /// Do nothing unless override is provided + virtual void foo_c() override { } +}; + +/// This is class D +/// which is a little like B +/// and a little like C +class D : public B, public C { +public: + /** + * Forward foo_a + */ + void foo_a() override + { + for (auto a : as) + a->foo_a(); + } + + /** + * Forward foo_c + */ + void foo_c() override + { + for (auto a : as) + a->foo_c(); + } + +private: + /// All the A pointers + std::vector as; +}; + +class E : virtual public B, public virtual C { +public: + /// + /// Forward foo_a + /// + void foo_a() override + { + for (auto a : as) + a->foo_a(); + } + + /// + /// Forward foo_c + /// + void foo_c() override + { + for (auto a : as) + a->foo_c(); + } + +private: + /// All the A pointers + std::vector as; +}; +} // namespace ns1 +} // namespace t90001 +} // namespace clanguml diff --git a/tests/t90001/test_case.h b/tests/t90001/test_case.h new file mode 100644 index 00000000..812f5a0d --- /dev/null +++ b/tests/t90001/test_case.h @@ -0,0 +1,92 @@ +/** + * tests/t90001/test_case.cc + * + * Copyright (c) 2021-2024 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_CASE("t90001", "[test-case][config]") +{ + using clanguml::error::empty_diagram_error; + + auto [config, db] = load_config("t90001"); + + { + auto diagram = config.diagrams["t90001_class"]; + + auto model = generate_class_diagram(*db, diagram); + + REQUIRE(model->is_empty()); + + REQUIRE(model->name() == "t90001_class"); + + REQUIRE_THROWS_AS( + generate_class_puml(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_class_json(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_class_mermaid(diagram, *model), empty_diagram_error); + } + + { + auto diagram = config.diagrams["t90001_sequence"]; + + auto model = generate_sequence_diagram(*db, diagram); + + REQUIRE(model->is_empty()); + + REQUIRE(model->name() == "t90001_sequence"); + + REQUIRE_THROWS_AS( + generate_sequence_puml(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_sequence_json(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_sequence_mermaid(diagram, *model), empty_diagram_error); + } + + { + auto diagram = config.diagrams["t90001_package"]; + + auto model = generate_package_diagram(*db, diagram); + + REQUIRE(model->is_empty()); + + REQUIRE(model->name() == "t90001_package"); + + REQUIRE_THROWS_AS( + generate_package_puml(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_package_json(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_package_mermaid(diagram, *model), empty_diagram_error); + } + + { + auto diagram = config.diagrams["t90001_include"]; + + auto model = generate_include_diagram(*db, diagram); + + REQUIRE(model->is_empty()); + + REQUIRE(model->name() == "t90001_include"); + + REQUIRE_THROWS_AS( + generate_include_puml(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_include_json(diagram, *model), empty_diagram_error); + REQUIRE_THROWS_AS( + generate_include_mermaid(diagram, *model), empty_diagram_error); + } +} diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 7f5f51b7..3f92a7fc 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -469,6 +469,7 @@ using namespace clanguml::test::matchers; #include "t20040/test_case.h" #include "t20041/test_case.h" #include "t20042/test_case.h" +#include "t20043/test_case.h" /// /// Package diagram tests @@ -501,6 +502,7 @@ using namespace clanguml::test::matchers; /// Other tests (e.g. configuration file) /// #include "t90000/test_case.h" +#include "t90001/test_case.h" /// /// Main test function diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 4a824bb8..1f611954 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -349,6 +349,9 @@ test_cases: - name: t20042 title: Test case for template overload pattern description: + - name: t20043 + title: Test case for elements diagram filter in sequence diagrams + description: Package diagrams: - name: t30001 title: Basic package diagram test case diff --git a/uml/class/architecture_visitors_class.yml b/uml/class/architecture_visitors_class.yml index a17ee7c3..8b1ac9b2 100644 --- a/uml/class/architecture_visitors_class.yml +++ b/uml/class/architecture_visitors_class.yml @@ -13,5 +13,7 @@ exclude: access: [ public, protected, private ] relationships: [ dependency ] plantuml: + style: + inheritance: up before: - - title clang-uml top level architecture - AST visitors + - left to right direction diff --git a/uml/class/class_model_class.yml b/uml/class/class_model_class.yml index b288516d..ee51c881 100644 --- a/uml/class/class_model_class.yml +++ b/uml/class/class_model_class.yml @@ -13,5 +13,9 @@ include: exclude: relationships: - dependency + access: + - public + - protected + - private using_namespace: - clanguml \ No newline at end of file diff --git a/uml/class/diagram_element_hierarchy_class.yml b/uml/class/diagram_element_hierarchy_class.yml index 97b4c691..72e0ed0a 100644 --- a/uml/class/diagram_element_hierarchy_class.yml +++ b/uml/class/diagram_element_hierarchy_class.yml @@ -23,4 +23,7 @@ exclude: - private - protected using_namespace: - - clanguml \ No newline at end of file + - clanguml +plantuml: + before: + - left to right direction diff --git a/uml/sequence/class_diagram_generator_sequence.yml b/uml/sequence/class_diagram_generator_sequence.yml index db9b8f7a..13990088 100644 --- a/uml/sequence/class_diagram_generator_sequence.yml +++ b/uml/sequence/class_diagram_generator_sequence.yml @@ -2,10 +2,18 @@ type: sequence title: PlantUML diagram generator sequence diagram glob: - src/class_diagram/generators/plantuml/*.cc +generate_condition_statements: true +generate_message_comments: true include: namespaces: - clanguml using_namespace: - clanguml::class_diagram::generators::plantuml +exclude: + elements: + - r: "clanguml::config::option.*" + - r: "clanguml::common::optional_ref.*" + namespaces: + - clanguml::util from: - function: "clanguml::common::generators::plantuml::generator::generate(std::ostream &) const" \ No newline at end of file diff --git a/uml/sequence/cli_handle_options_sequence.yml b/uml/sequence/cli_handle_options_sequence.yml index 0f326f36..48d04383 100644 --- a/uml/sequence/cli_handle_options_sequence.yml +++ b/uml/sequence/cli_handle_options_sequence.yml @@ -2,7 +2,8 @@ type: sequence title: CLI options handling sequence diagram combine_free_functions_into_file_participants: true generate_method_arguments: none -debug_mode: true +generate_condition_statements: true +generate_message_comments: true glob: - src/cli/cli_handler.cc - src/config/config.cc @@ -14,6 +15,7 @@ include: exclude: elements: - r: "clanguml::config::option.*" + - "clanguml::config::config" paths: - src/util/util.h callee_types: diff --git a/uml/sequence/diagram_generate_generic_sequence.yml b/uml/sequence/diagram_generate_generic_sequence.yml index 9463ed3d..c96c5623 100644 --- a/uml/sequence/diagram_generate_generic_sequence.yml +++ b/uml/sequence/diagram_generate_generic_sequence.yml @@ -1,7 +1,9 @@ type: sequence -title: Common sequence diagram generator sequence diagram +title: PlantUML sequence diagram generator sequence diagram combine_free_functions_into_file_participants: true generate_method_arguments: none +generate_condition_statements: true +generate_message_comments: true glob: - src/common/generators/generators.cc using_namespace: @@ -10,6 +12,12 @@ include: namespaces: - clanguml::common::generators exclude: + elements: + - r: ".*json.*" + - r: ".*mermaid.*" + - r: ".*class_diagram.*" + - r: ".*package_diagram.*" + - r: ".*include_diagram.*" paths: - src/common/model/source_location.h from: diff --git a/uml/sequence/load_config_sequence.yml b/uml/sequence/load_config_sequence.yml index 5ae1cb19..a3eac6c1 100644 --- a/uml/sequence/load_config_sequence.yml +++ b/uml/sequence/load_config_sequence.yml @@ -2,6 +2,8 @@ type: sequence title: Configuration file loading sequence diagram combine_free_functions_into_file_participants: true generate_method_arguments: none +generate_condition_statements: true +generate_message_comments: true glob: - src/config/config.cc - src/config/yaml_decoders.cc diff --git a/uml/sequence/main_sequence.yml b/uml/sequence/main_sequence.yml index c0721a0f..3d4e655f 100644 --- a/uml/sequence/main_sequence.yml +++ b/uml/sequence/main_sequence.yml @@ -4,6 +4,8 @@ title: main() function sequence diagram combine_free_functions_into_file_participants: true # Do not generate method or function arguments generate_method_arguments: none +generate_condition_statements: true +generate_message_comments: true # Parse only 1 translation unit for this diagram glob: - src/main.cc diff --git a/uml/sequence/plantuml_sequence_diagram_generator_sequence.yml b/uml/sequence/plantuml_sequence_diagram_generator_sequence.yml new file mode 100644 index 00000000..7997b7f2 --- /dev/null +++ b/uml/sequence/plantuml_sequence_diagram_generator_sequence.yml @@ -0,0 +1,28 @@ +type: sequence +title: PlantUML sequence diagram generator sequence diagram +combine_free_functions_into_file_participants: true +generate_method_arguments: none +generate_condition_statements: true +generate_message_comments: true +glob: + - src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +using_namespace: + - clanguml +include: + namespaces: + - clanguml + elements: + - r: ".*generators.*" +exclude: + elements: + - r: ".*json.*" + - r: ".*mermaid.*" + - r: ".*class_diagram.*" + - r: ".*package_diagram.*" + - r: ".*include_diagram.*" + - r: "clanguml::config::option.*" + - r: "clanguml::common::optional_ref.*" + paths: + - src/common/model/source_location.h +from: + - function: "clanguml::sequence_diagram::generators::plantuml::generator::generate_diagram(std::ostream &) const" diff --git a/uml/sequence/template_builder_sequence.yml b/uml/sequence/template_builder_sequence.yml index 305bf45e..57f3d499 100644 --- a/uml/sequence/template_builder_sequence.yml +++ b/uml/sequence/template_builder_sequence.yml @@ -2,6 +2,8 @@ type: sequence title: Diagram element template builder sequence diagram combine_free_functions_into_file_participants: true generate_method_arguments: none +generate_condition_statements: true +generate_message_comments: true glob: - src/common/visitor/template_builder.cc include: @@ -16,4 +18,4 @@ exclude: using_namespace: - clanguml from: - - function: "clanguml::common::visitor::template_builder::build(common::model::template_element &,const clang::NamedDecl *,const clang::TemplateSpecializationType &,std::optional)" + - function: "clanguml::common::visitor::template_builder::build(common::model::template_element &,const clang::NamedDecl *,const clang::TemplateDecl *,const clang::ArrayRef,std::string,std::optional)"