From 1305499207f6c21245e07aab8fa6bdad4a71a9dd Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 19 Sep 2021 13:20:31 -0700 Subject: [PATCH] chore: use Prettier to format source files --- .editorconfig | 2 +- .eslintrc.js | 2 +- .github/ISSUE_TEMPLATE.md | 4 +- .github/PULL_REQUEST_TEMPLATE.md | 18 +- .prettierignore | 5 + .prettierrc.js | 3 + .renovaterc.json | 16 +- CHANGES.md | 1170 +- CODE_OF_CONDUCT.md | 22 +- CONTRIBUTING.md | 99 +- README.md | 53 +- gulpfile.js | 53 +- lerna.json | 4 +- package-lock.json | 16671 +++++++++++++++- package.json | 6 +- packages/jsdoc-cli/lib/engine.js | 346 +- packages/jsdoc-cli/lib/flags.js | 192 +- packages/jsdoc-cli/lib/help.js | 142 +- packages/jsdoc-cli/lib/logger.js | 242 +- packages/jsdoc-cli/package-lock.json | 123 +- packages/jsdoc-cli/test/specs/index.js | 8 +- packages/jsdoc-cli/test/specs/lib/engine.js | 342 +- packages/jsdoc-cli/test/specs/lib/flags.js | 54 +- packages/jsdoc-cli/test/specs/lib/help.js | 2 +- packages/jsdoc-cli/test/specs/lib/logger.js | 389 +- packages/jsdoc-core/index.js | 4 +- packages/jsdoc-core/lib/config.js | 186 +- packages/jsdoc-core/lib/name.js | 473 +- packages/jsdoc-core/package-lock.json | 273 +- packages/jsdoc-core/test/specs/index.js | 30 +- packages/jsdoc-core/test/specs/lib/config.js | 340 +- packages/jsdoc-core/test/specs/lib/name.js | 699 +- packages/jsdoc-eslint-config/index.js | 703 +- packages/jsdoc-parse/index.js | 6 +- packages/jsdoc-parse/lib/ast-builder.js | 103 +- packages/jsdoc-parse/lib/ast-node.js | 857 +- packages/jsdoc-parse/lib/syntax.js | 186 +- packages/jsdoc-parse/test/specs/index.js | 40 +- .../jsdoc-parse/test/specs/lib/ast-builder.js | 66 +- .../jsdoc-parse/test/specs/lib/ast-node.js | 1037 +- packages/jsdoc-parse/test/specs/lib/syntax.js | 18 +- packages/jsdoc-prettier-config/.npmignore | 14 + packages/jsdoc-prettier-config/LICENSE | 202 + packages/jsdoc-prettier-config/README.md | 3 + packages/jsdoc-prettier-config/index.js | 5 + packages/jsdoc-prettier-config/package.json | 31 + packages/jsdoc-tag/index.js | 4 +- packages/jsdoc-tag/lib/inline.js | 85 +- packages/jsdoc-tag/lib/type.js | 354 +- packages/jsdoc-tag/test/specs/index.js | 30 +- packages/jsdoc-tag/test/specs/lib/inline.js | 466 +- packages/jsdoc-tag/test/specs/lib/type.js | 496 +- packages/jsdoc-task-runner/index.js | 4 +- packages/jsdoc-task-runner/lib/task-runner.js | 603 +- packages/jsdoc-task-runner/lib/task.js | 75 +- packages/jsdoc-task-runner/lib/validators.js | 76 +- packages/jsdoc-task-runner/package-lock.json | 160 +- .../jsdoc-task-runner/test/specs/index.js | 30 +- .../test/specs/lib/task-runner.js | 1514 +- .../jsdoc-task-runner/test/specs/lib/task.js | 379 +- packages/jsdoc-test-matchers/index.js | 52 +- .../jsdoc-test-matchers/package-lock.json | 29 +- packages/jsdoc-util/index.js | 8 +- packages/jsdoc-util/lib/bus.js | 44 +- packages/jsdoc-util/lib/cast.js | 107 +- packages/jsdoc-util/lib/fs.js | 18 +- packages/jsdoc-util/lib/log.js | 4 +- packages/jsdoc-util/package-lock.json | 119 +- packages/jsdoc-util/test/specs/index.js | 40 +- packages/jsdoc-util/test/specs/lib/bus.js | 112 +- packages/jsdoc-util/test/specs/lib/cast.js | 116 +- packages/jsdoc-util/test/specs/lib/fs.js | 115 +- packages/jsdoc-util/test/specs/lib/log.js | 50 +- packages/jsdoc/cli.js | 765 +- packages/jsdoc/jsdoc.js | 57 +- packages/jsdoc/lib/jsdoc/augment.js | 724 +- packages/jsdoc/lib/jsdoc/borrow.js | 63 +- packages/jsdoc/lib/jsdoc/doclet.js | 1003 +- packages/jsdoc/lib/jsdoc/env.js | 124 +- packages/jsdoc/lib/jsdoc/package.js | 381 +- packages/jsdoc/lib/jsdoc/plugins.js | 42 +- packages/jsdoc/lib/jsdoc/schema.js | 1211 +- packages/jsdoc/lib/jsdoc/src/filter.js | 87 +- packages/jsdoc/lib/jsdoc/src/handlers.js | 501 +- packages/jsdoc/lib/jsdoc/src/parser.js | 1107 +- packages/jsdoc/lib/jsdoc/src/scanner.js | 74 +- packages/jsdoc/lib/jsdoc/src/visitor.js | 1221 +- packages/jsdoc/lib/jsdoc/src/walker.js | 692 +- packages/jsdoc/lib/jsdoc/tag.js | 258 +- packages/jsdoc/lib/jsdoc/tag/dictionary.js | 231 +- .../lib/jsdoc/tag/dictionary/definitions.js | 1618 +- packages/jsdoc/lib/jsdoc/tag/validator.js | 64 +- packages/jsdoc/lib/jsdoc/template.js | 124 +- .../jsdoc/lib/jsdoc/util/templateHelper.js | 995 +- packages/jsdoc/package-lock.json | 128 +- packages/jsdoc/plugins/commentConvert.js | 24 +- packages/jsdoc/plugins/commentsOnly.js | 16 +- packages/jsdoc/plugins/escapeHtml.js | 20 +- packages/jsdoc/plugins/eventDumper.js | 106 +- packages/jsdoc/plugins/overloadHelper.js | 211 +- packages/jsdoc/plugins/partial.js | 34 +- packages/jsdoc/plugins/railsTemplate.js | 22 +- packages/jsdoc/plugins/shout.js | 14 +- packages/jsdoc/plugins/sourcetag.js | 77 +- packages/jsdoc/plugins/summarize.js | 90 +- .../plugins/test/specs/commentConvert.js | 24 +- .../jsdoc/plugins/test/specs/escapeHtml.js | 28 +- .../plugins/test/specs/overloadHelper.js | 164 +- .../jsdoc/plugins/test/specs/railsTemplate.js | 22 +- packages/jsdoc/plugins/test/specs/shout.js | 24 +- .../jsdoc/plugins/test/specs/sourcetag.js | 28 +- .../jsdoc/plugins/test/specs/summarize.js | 216 +- .../jsdoc/plugins/test/specs/underscore.js | 48 +- packages/jsdoc/plugins/underscore.js | 10 +- packages/jsdoc/templates/README.md | 12 +- packages/jsdoc/templates/default/publish.js | 989 +- .../default/static/scripts/linenumber.js | 38 +- .../default/static/styles/jsdoc-default.css | 493 +- packages/jsdoc/templates/silent/README.md | 10 +- packages/jsdoc/test/.eslintrc.js | 6 +- packages/jsdoc/test/README.md | 8 +- packages/jsdoc/test/fixtures/es6.js | 3 - packages/jsdoc/test/helpers/jsdoc.js | 136 +- packages/jsdoc/test/index.js | 68 +- .../jsdoc/test/specs/documentation/alias.js | 204 +- .../jsdoc/test/specs/documentation/also.js | 111 +- .../specs/documentation/anonymousclass.js | 34 +- .../documentation/anonymousclassparam.js | 12 +- .../test/specs/documentation/arrowfunction.js | 45 +- .../test/specs/documentation/asyncfunction.js | 26 +- .../test/specs/documentation/callback.js | 30 +- .../specs/documentation/classproperties.js | 50 +- .../specs/documentation/classwithoutname.js | 17 +- .../jsdoc/test/specs/documentation/const.js | 26 +- .../test/specs/documentation/defaultparams.js | 118 +- .../test/specs/documentation/emptycomments.js | 12 +- .../test/specs/documentation/exportclass.js | 18 +- .../test/specs/documentation/exportdefault.js | 12 +- .../specs/documentation/exportdefaultclass.js | 12 +- .../jsdoc/test/specs/documentation/exports.js | 36 +- .../specs/documentation/funcExpression.js | 42 +- .../test/specs/documentation/generators.js | 26 +- .../jsdoc/test/specs/documentation/getset.js | 96 +- .../test/specs/documentation/inlinecomment.js | 23 +- .../specs/documentation/inlineparamcomment.js | 41 +- .../jsdoc/test/specs/documentation/inner.js | 38 +- .../test/specs/documentation/innerscope.js | 66 +- .../specs/documentation/instanceproperty.js | 14 +- .../jsdoc/test/specs/documentation/jsx.js | 14 +- .../jsdoc/test/specs/documentation/lends.js | 244 +- .../test/specs/documentation/letkeyword.js | 32 +- .../specs/documentation/methoddefinition.js | 22 +- .../jsdoc/test/specs/documentation/mixins.js | 80 +- .../test/specs/documentation/moduleclasses.js | 50 +- .../test/specs/documentation/moduleinner.js | 18 +- .../documentation/moduleisconstructor.js | 168 +- .../specs/documentation/moduleisfunction.js | 26 +- .../jsdoc/test/specs/documentation/modules.js | 96 +- .../test/specs/documentation/objectkeys.js | 12 +- .../test/specs/documentation/objectlit.js | 118 +- .../specs/documentation/objectpropertykeys.js | 12 +- .../specs/documentation/paramtagsametype.js | 38 +- .../test/specs/documentation/quotename.js | 28 +- .../test/specs/documentation/restparams.js | 62 +- .../test/specs/documentation/specialchars.js | 28 +- .../test/specs/documentation/specialnames.js | 42 +- .../test/specs/documentation/starbangstar.js | 18 +- .../jsdoc/test/specs/documentation/this.js | 244 +- .../specs/documentation/trailingcomment.js | 30 +- .../test/specs/documentation/typetaginline.js | 184 +- .../specs/documentation/typetagwithnewline.js | 47 +- .../jsdoc/test/specs/documentation/var.js | 96 +- .../test/specs/documentation/variations.js | 30 +- .../jsdoc/test/specs/documentation/virtual.js | 78 +- packages/jsdoc/test/specs/jsdoc/augment.js | 138 +- packages/jsdoc/test/specs/jsdoc/borrow.js | 2 +- packages/jsdoc/test/specs/jsdoc/doclet.js | 555 +- packages/jsdoc/test/specs/jsdoc/package.js | 506 +- packages/jsdoc/test/specs/jsdoc/plugins.js | 20 +- packages/jsdoc/test/specs/jsdoc/schema.js | 145 +- packages/jsdoc/test/specs/jsdoc/src/filter.js | 304 +- .../jsdoc/test/specs/jsdoc/src/handlers.js | 78 +- packages/jsdoc/test/specs/jsdoc/src/parser.js | 764 +- .../jsdoc/test/specs/jsdoc/src/scanner.js | 79 +- .../jsdoc/test/specs/jsdoc/src/visitor.js | 414 +- packages/jsdoc/test/specs/jsdoc/src/walker.js | 52 +- packages/jsdoc/test/specs/jsdoc/tag.js | 423 +- .../jsdoc/test/specs/jsdoc/tag/dictionary.js | 492 +- .../specs/jsdoc/tag/dictionary/definitions.js | 50 +- .../jsdoc/test/specs/jsdoc/tag/validator.js | 232 +- packages/jsdoc/test/specs/jsdoc/template.js | 2 +- .../test/specs/jsdoc/util/templateHelper.js | 3201 +-- packages/jsdoc/test/specs/plugins/plugins.js | 60 +- packages/jsdoc/test/specs/tags/abstracttag.js | 22 +- packages/jsdoc/test/specs/tags/accesstag.js | 50 +- packages/jsdoc/test/specs/tags/aliastag.js | 14 +- packages/jsdoc/test/specs/tags/asynctag.js | 10 +- packages/jsdoc/test/specs/tags/augmentstag.js | 266 +- packages/jsdoc/test/specs/tags/authortag.js | 24 +- packages/jsdoc/test/specs/tags/borrowstag.js | 52 +- .../jsdoc/test/specs/tags/classdesctag.js | 26 +- packages/jsdoc/test/specs/tags/classtag.js | 139 +- packages/jsdoc/test/specs/tags/constanttag.js | 96 +- .../jsdoc/test/specs/tags/constructortag.js | 18 +- .../jsdoc/test/specs/tags/constructstag.js | 72 +- .../jsdoc/test/specs/tags/copyrighttag.js | 10 +- packages/jsdoc/test/specs/tags/defaulttag.js | 118 +- packages/jsdoc/test/specs/tags/definetag.js | 66 +- .../jsdoc/test/specs/tags/deprecatedtag.js | 18 +- .../jsdoc/test/specs/tags/descriptiontag.js | 18 +- packages/jsdoc/test/specs/tags/dicttag.js | 62 +- packages/jsdoc/test/specs/tags/enumtag.js | 118 +- .../jsdoc/test/specs/tags/eventfirestag.js | 47 +- packages/jsdoc/test/specs/tags/exampletag.js | 28 +- .../jsdoc/test/specs/tags/exceptiontag.js | 38 +- packages/jsdoc/test/specs/tags/exportstag.js | 380 +- packages/jsdoc/test/specs/tags/exporttag.js | 62 +- packages/jsdoc/test/specs/tags/externaltag.js | 51 +- packages/jsdoc/test/specs/tags/externstag.js | 62 +- .../jsdoc/test/specs/tags/fileoverviewtag.js | 42 +- packages/jsdoc/test/specs/tags/filetag.js | 2 +- packages/jsdoc/test/specs/tags/functiontag.js | 26 +- .../jsdoc/test/specs/tags/generatortag.js | 10 +- packages/jsdoc/test/specs/tags/globaltag.js | 30 +- .../test/specs/tags/hideconstructortag.js | 21 +- packages/jsdoc/test/specs/tags/ignoretag.js | 22 +- .../jsdoc/test/specs/tags/implementstag.js | 46 +- .../jsdoc/test/specs/tags/implicitcasttag.js | 62 +- .../jsdoc/test/specs/tags/inheritdoctag.js | 56 +- .../jsdoc/test/specs/tags/interfacetag.js | 197 +- packages/jsdoc/test/specs/tags/kindtag.js | 10 +- packages/jsdoc/test/specs/tags/lendstag.js | 24 +- packages/jsdoc/test/specs/tags/licensetag.js | 10 +- packages/jsdoc/test/specs/tags/listenstag.js | 22 +- packages/jsdoc/test/specs/tags/memberoftag.js | 150 +- packages/jsdoc/test/specs/tags/membertag.js | 54 +- packages/jsdoc/test/specs/tags/mixestag.js | 24 +- packages/jsdoc/test/specs/tags/mixintag.js | 18 +- packages/jsdoc/test/specs/tags/modifiestag.js | 18 +- packages/jsdoc/test/specs/tags/moduletag.js | 317 +- .../jsdoc/test/specs/tags/namespacetag.js | 47 +- packages/jsdoc/test/specs/tags/nametag.js | 36 +- packages/jsdoc/test/specs/tags/noaliastag.js | 62 +- .../jsdoc/test/specs/tags/nocollapsetag.js | 62 +- .../jsdoc/test/specs/tags/nocompiletag.js | 62 +- .../jsdoc/test/specs/tags/nosideeffectstag.js | 24 +- packages/jsdoc/test/specs/tags/overridetag.js | 159 +- packages/jsdoc/test/specs/tags/overviewtag.js | 99 +- packages/jsdoc/test/specs/tags/packagetag.js | 97 +- packages/jsdoc/test/specs/tags/paramtag.js | 162 +- .../test/specs/tags/polymerbehaviortag.js | 62 +- packages/jsdoc/test/specs/tags/polymertag.js | 62 +- packages/jsdoc/test/specs/tags/preservetag.js | 60 +- packages/jsdoc/test/specs/tags/privatetag.js | 108 +- packages/jsdoc/test/specs/tags/propertytag.js | 42 +- .../jsdoc/test/specs/tags/protectedtag.js | 102 +- packages/jsdoc/test/specs/tags/publictag.js | 60 +- packages/jsdoc/test/specs/tags/readonlytag.js | 10 +- packages/jsdoc/test/specs/tags/requirestag.js | 36 +- packages/jsdoc/test/specs/tags/returnstag.js | 44 +- packages/jsdoc/test/specs/tags/scopetags.js | 34 +- packages/jsdoc/test/specs/tags/seetag.js | 18 +- packages/jsdoc/test/specs/tags/sincetag.js | 10 +- packages/jsdoc/test/specs/tags/structtag.js | 62 +- packages/jsdoc/test/specs/tags/summarytag.js | 10 +- packages/jsdoc/test/specs/tags/suppresstag.js | 62 +- packages/jsdoc/test/specs/tags/templatetag.js | 62 +- packages/jsdoc/test/specs/tags/thistag.js | 98 +- packages/jsdoc/test/specs/tags/todotag.js | 14 +- packages/jsdoc/test/specs/tags/typedeftag.js | 162 +- packages/jsdoc/test/specs/tags/typekind.js | 22 +- packages/jsdoc/test/specs/tags/typetag.js | 102 +- .../jsdoc/test/specs/tags/undocumentedtag.js | 16 +- .../jsdoc/test/specs/tags/unrestrictedtag.js | 62 +- .../jsdoc/test/specs/tags/variationtag.js | 28 +- packages/jsdoc/test/specs/tags/versiontag.js | 10 +- packages/jsdoc/test/specs/tags/yieldstag.js | 38 +- 277 files changed, 38661 insertions(+), 21761 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc.js create mode 100644 packages/jsdoc-prettier-config/.npmignore create mode 100644 packages/jsdoc-prettier-config/LICENSE create mode 100644 packages/jsdoc-prettier-config/README.md create mode 100644 packages/jsdoc-prettier-config/index.js create mode 100644 packages/jsdoc-prettier-config/package.json diff --git a/.editorconfig b/.editorconfig index c035c9f2..4f14fdc7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,4 +9,4 @@ indent_size = 2 [{**/*.js,**/*.css,**/*.json}] indent_style = space -indent_size = 4 +indent_size = 2 diff --git a/.eslintrc.js b/.eslintrc.js index 43ee2856..b6f3ccee 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,3 @@ module.exports = { - extends: '@jsdoc' + extends: ['@jsdoc', 'plugin:prettier/recommended'], }; diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index bb1eb489..21e39fb0 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -40,8 +40,8 @@ Your debug output here ### Your environment -| Software | Version -| ---------------- | ------- +| Software | Version | +| ---------------- | ------- | | JSDoc | | Node.js | | npm | diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index de87f07c..d1566f93 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,14 +5,14 @@ https://github.com/jsdoc3/jsdoc/blob/master/CONTRIBUTING.md https://github.com/jsdoc3/jsdoc/blob/master/CODE_OF_CONDUCT.md --> -| Q | A -| ---------------- | --- -| Bug fix? | yes/no -| New feature? | yes/no -| Breaking change? | yes/no -| Deprecations? | yes/no -| Tests added? | yes/no -| Fixed issues | comma-separated list of issues fixed by the pull request, if any -| License | Apache-2.0 +| Q | A | +| ---------------- | ---------------------------------------------------------------- | +| Bug fix? | yes/no | +| New feature? | yes/no | +| Breaking change? | yes/no | +| Deprecations? | yes/no | +| Tests added? | yes/no | +| Fixed issues | comma-separated list of issues fixed by the pull request, if any | +| License | Apache-2.0 | diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..28ce0ca4 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +# Ignore test fixtures. +**/test/fixtures/** + +# Ignore code coverage reports. +.nyc_output/ diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000..e66e678d --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('./packages/jsdoc-prettier-config'), +}; diff --git a/.renovaterc.json b/.renovaterc.json index 665d3650..aa4bf715 100644 --- a/.renovaterc.json +++ b/.renovaterc.json @@ -1,12 +1,8 @@ { - "extends": [ - "config:base" - ], - "statusCheckVerify": true, - "ignoreDeps": [ - "taffydb" - ], - "automerge": true, - "automergeType": "branch", - "rangeStrategy": "bump" + "extends": ["config:base"], + "statusCheckVerify": true, + "ignoreDeps": ["taffydb"], + "automerge": true, + "automergeType": "branch", + "rangeStrategy": "bump" } diff --git a/CHANGES.md b/CHANGES.md index 8c8111e5..ab701350 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,6 @@ This file describes notable changes in each version of JSDoc 3. - ## 3.6.6 (September 2020) Fixes an issue that could cause members of an interface to be tracked incorrectly if the interface @@ -11,823 +10,794 @@ was both defined as an ES2015 class and assigned to a variable. For example: ```js /** @interface */ foo.Bar = class { - constructor() { - /** This member was missing from the generated docs. */ - this.baz = null; - } -} + constructor() { + /** This member was missing from the generated docs. */ + this.baz = null; + } +}; ``` - ## 3.6.5 (July 2020) Prevents circular references in doclets when two function parameters use the same type expression, and the `--debug` flag is present. - ## 3.6.4 (April 2020) Updates dependencies. - ## 3.6.3 (July 2019) Updates dependencies. - ## 3.6.2 (May 2019) Fixes an issue that prevented ES 2015 classes from appearing in generated docs. ([#1644][1644]) - ## 3.6.1 (May 2019) Prevents a crash when using type applications in Node.js 12. ([#1643][1643]) - ## 3.6.0 (May 2019) ### Major changes -+ JSDoc is now compatible with Node.js 12, and it requires Node.js 8.15.0 or later. -+ JSDoc now recognizes all documented Closure Compiler tags. ([#605][605]) +- JSDoc is now compatible with Node.js 12, and it requires Node.js 8.15.0 or later. +- JSDoc now recognizes all documented Closure Compiler tags. ([#605][605]) ### Enhancements -+ You can now use the `templates.useShortNamesInLinks` configuration setting to show the short name -of each symbol in link text (for example, `baz`), rather than the full longname (for example, -`foo.bar.baz`). ([#738][738]) -+ When you enable the Markdown plugin, you can now specify a function that performs syntax -highlighting in code blocks. ([#1412][1412]) -+ The default template now places namespaces near the top of the TOC. ([#1410][1410]) +- You can now use the `templates.useShortNamesInLinks` configuration setting to show the short name + of each symbol in link text (for example, `baz`), rather than the full longname (for example, + `foo.bar.baz`). ([#738][738]) +- When you enable the Markdown plugin, you can now specify a function that performs syntax + highlighting in code blocks. ([#1412][1412]) +- The default template now places namespaces near the top of the TOC. ([#1410][1410]) ### Bug fixes -+ When you add a JSDoc comment to an ES2015 constructor, JSDoc now preserves all of the JSDoc tags, -not only the description and parameters. ([#1129][1129]) -+ The `@exports` tag now works correctly when it is combined with the `@enum` tag. ([#970][970]) -+ When you enable the Markdown plugin, and you use a code fence with the language set to `plain`, -JSDoc no longer pretty-prints the code block in the generated documentation. ([#1361][1361]) - +- When you add a JSDoc comment to an ES2015 constructor, JSDoc now preserves all of the JSDoc tags, + not only the description and parameters. ([#1129][1129]) +- The `@exports` tag now works correctly when it is combined with the `@enum` tag. ([#970][970]) +- When you enable the Markdown plugin, and you use a code fence with the language set to `plain`, + JSDoc no longer pretty-prints the code block in the generated documentation. ([#1361][1361]) ## 3.5.5 (September 2017) Fixes a compatibility issue with Node.js 8.5.0. (#1438) - ## 3.5.4 (August 2017) -+ When a class uses the `@hideconstructor` tag, the default template no longer displays the names of -parameters that the constructor accepts. (#1397) -+ When an arrow function expression returns a class, the class's methods and properties are now -named correctly. (#1409) -+ JSDoc no longer crashes when an anonymous class is passed as a function parameter. (#1416) -+ JSDoc now allows `import` and `export` declarations anywhere where a statement is allowed. (#1411) -+ JSDoc now allows `return` statements outside of functions. (#1411) -+ JSDoc now allows `super()` calls outside of a method definition. (#1411) -+ JSDoc no longer exits before the `STDOUT` pipe has been flushed. (#1408) - +- When a class uses the `@hideconstructor` tag, the default template no longer displays the names of + parameters that the constructor accepts. (#1397) +- When an arrow function expression returns a class, the class's methods and properties are now + named correctly. (#1409) +- JSDoc no longer crashes when an anonymous class is passed as a function parameter. (#1416) +- JSDoc now allows `import` and `export` declarations anywhere where a statement is allowed. (#1411) +- JSDoc now allows `return` statements outside of functions. (#1411) +- JSDoc now allows `super()` calls outside of a method definition. (#1411) +- JSDoc no longer exits before the `STDOUT` pipe has been flushed. (#1408) ## 3.5.3 (July 2017) -+ Non-JSDoc comments (comments that do not begin with `/**`) are now ignored. (#1398) -+ JSDoc no longer crashes when it parses a class property with no value assigned to it. (#1400) -+ When there are JSDoc comments at the end of a source file that has a `'use strict';` directive, -the comments are no longer ignored. (#1396) -+ Namepaths that contain an `@` sign (for example, `module:@prefix/my-module~myCallback`) are now -parsed correctly. (#1302) -+ The default template now displays interfaces that belong to a namespace. (#1406) -+ When an ES2015 class inside a module uses an `@alias` tag, the class's constructor now gets the -correct longname. (#1395) -+ When there are no input files to process, JSDoc no longer prints help text to the console. (#1404) - +- Non-JSDoc comments (comments that do not begin with `/**`) are now ignored. (#1398) +- JSDoc no longer crashes when it parses a class property with no value assigned to it. (#1400) +- When there are JSDoc comments at the end of a source file that has a `'use strict';` directive, + the comments are no longer ignored. (#1396) +- Namepaths that contain an `@` sign (for example, `module:@prefix/my-module~myCallback`) are now + parsed correctly. (#1302) +- The default template now displays interfaces that belong to a namespace. (#1406) +- When an ES2015 class inside a module uses an `@alias` tag, the class's constructor now gets the + correct longname. (#1395) +- When there are no input files to process, JSDoc no longer prints help text to the console. (#1404) ## 3.5.2 (July 2017) -+ The default template now hides parameters and properties for class constructors that are hidden -with the `@hideconstructor` tag. (#1397) -+ JSDoc now uses an improved algorithm for locating plugins and template resources. (#1394) -+ When the `@alias` tag identifies an instance member (for example, `@alias Foo#bar`), the alias is -now applied correctly. (#1385) -+ When the `@alias` tag is applied to a class that is within a module and is aliased to the module -name, the class's instance members are now documented correctly. (#1134) -+ Fixed a crash when a `@param` tag uses the wrong delimiter to close the type expression (for -example, `@param {Object)`). (#1221) -+ The Markdown plugin now converts Markdown-formatted text in the `@summary` tag. (#1149) - +- The default template now hides parameters and properties for class constructors that are hidden + with the `@hideconstructor` tag. (#1397) +- JSDoc now uses an improved algorithm for locating plugins and template resources. (#1394) +- When the `@alias` tag identifies an instance member (for example, `@alias Foo#bar`), the alias is + now applied correctly. (#1385) +- When the `@alias` tag is applied to a class that is within a module and is aliased to the module + name, the class's instance members are now documented correctly. (#1134) +- Fixed a crash when a `@param` tag uses the wrong delimiter to close the type expression (for + example, `@param {Object)`). (#1221) +- The Markdown plugin now converts Markdown-formatted text in the `@summary` tag. (#1149) ## 3.5.1 (July 2017) -+ Fixed an issue that prevented JSDoc from working on versions of Node.js prior to 5.10.0. (#1393) -+ If the JSDoc configuration file does not have a file extension, JSDoc now assumes that the file -is in JSON format. (#1391) - +- Fixed an issue that prevented JSDoc from working on versions of Node.js prior to 5.10.0. (#1393) +- If the JSDoc configuration file does not have a file extension, JSDoc now assumes that the file + is in JSON format. (#1391) ## 3.5.0 (July 2017) ### Major changes -+ JSDoc now uses the [Babylon](https://github.com/babel/babylon) JavaScript parser, which means that -JSDoc can parse any JavaScript or JSX file that is supported by the [Babel](https://babeljs.io/) -compiler. For example, JSDoc can now parse JavaScript files that include all of the following -language features: +- JSDoc now uses the [Babylon](https://github.com/babel/babylon) JavaScript parser, which means that + JSDoc can parse any JavaScript or JSX file that is supported by the [Babel](https://babeljs.io/) + compiler. For example, JSDoc can now parse JavaScript files that include all of the following + language features: - + [Decorators](https://github.com/tc39/proposal-decorators) - + [Public and private class fields](https://github.com/tc39/proposal-class-fields) - + [Asynchronous iterators](https://github.com/tc39/proposal-async-iteration) - + [Dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) - + [Optional chaining](https://github.com/tc39/proposal-optional-chaining) + + [Decorators](https://github.com/tc39/proposal-decorators) + + [Public and private class fields](https://github.com/tc39/proposal-class-fields) + + [Asynchronous iterators](https://github.com/tc39/proposal-async-iteration) + + [Dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) + + [Optional chaining](https://github.com/tc39/proposal-optional-chaining) -+ You can now use a JavaScript file to configure JSDoc. The JavaScript file must be a CommonJS -module that exports a single configuration object. See the -[documentation](https://jsdoc.app/about-configuring-jsdoc.html) for details and examples. -+ Fixed multiple issues with documenting ES2015 classes and modules. See "Bug fixes" for details. -+ JSDoc now requires Node.js 4.2.0 or later. +- You can now use a JavaScript file to configure JSDoc. The JavaScript file must be a CommonJS + module that exports a single configuration object. See the + [documentation](https://jsdoc.app/about-configuring-jsdoc.html) for details and examples. +- Fixed multiple issues with documenting ES2015 classes and modules. See "Bug fixes" for details. +- JSDoc now requires Node.js 4.2.0 or later. ### New tags **Note**: Third-party templates may not support these new tags. -+ You can now use the new [`@async` tag](https://jsdoc.app/tags-async.html) to indicate that a -function is asynchronous (that is, that it was declared with the syntax `async function foo() {}`). -In general, you do not need to use this tag, because JSDoc autodetects asynchronous functions. -(#1188) -+ You can now use the new [`@generator` tag](https://jsdoc.app/tags-generator.html) to indicate -that a function is a generator function. In general, you do not need to use this tag, because JSDoc -autodetects generator functions. (#1158) -+ You can now use the new [`@hideconstructor` tag](https://jsdoc.app/tags-hideconstructor.html) to -tell JSDoc to hide a class's constructor from the documentation. (#952) -+ You can now use the new [`@package` tag](https://jsdoc.app/tags-package.html) to indicate that a -symbol is package-private. (#962) -+ You can now use the new [`@yields` tag](https://jsdoc.app/tags-yields.html) to document the -value that is yielded by a generator function. (#1388) +- You can now use the new [`@async` tag](https://jsdoc.app/tags-async.html) to indicate that a + function is asynchronous (that is, that it was declared with the syntax `async function foo() {}`). + In general, you do not need to use this tag, because JSDoc autodetects asynchronous functions. + (#1188) +- You can now use the new [`@generator` tag](https://jsdoc.app/tags-generator.html) to indicate + that a function is a generator function. In general, you do not need to use this tag, because JSDoc + autodetects generator functions. (#1158) +- You can now use the new [`@hideconstructor` tag](https://jsdoc.app/tags-hideconstructor.html) to + tell JSDoc to hide a class's constructor from the documentation. (#952) +- You can now use the new [`@package` tag](https://jsdoc.app/tags-package.html) to indicate that a + symbol is package-private. (#962) +- You can now use the new [`@yields` tag](https://jsdoc.app/tags-yields.html) to document the + value that is yielded by a generator function. (#1388) ### Enhancements -+ JSDoc can now parse files that contain asynchronous functions (that is, functions declared as -`async function foo() {}`), and JSDoc autodetects when a function is asynchronous. (#1188) -+ JSDoc now autodetects generator functions. (#1158) -+ When JSDoc cannot parse a type expression, it now logs the line number on which the type -expression was found. (#1057) -+ When JSDoc fires `jsdocCommentFound` and `symbolFound` events, the event now includes a `columnno` -property indicating the column number on which the comment or symbol was found. (#1362) -+ You can now use the new `sourceType` configuration option to control how JavaScript files are -parsed. The default value is `module`. Set the value to `script` to suppress implied strict mode; -this setting will also prevent you from using ES2015 modules. (#1210) -+ You can now use the new `recurseDepth` configuration option to control how many levels deep JSDoc -will recursively search for files. The default value is 10. (#1340) +- JSDoc can now parse files that contain asynchronous functions (that is, functions declared as + `async function foo() {}`), and JSDoc autodetects when a function is asynchronous. (#1188) +- JSDoc now autodetects generator functions. (#1158) +- When JSDoc cannot parse a type expression, it now logs the line number on which the type + expression was found. (#1057) +- When JSDoc fires `jsdocCommentFound` and `symbolFound` events, the event now includes a `columnno` + property indicating the column number on which the comment or symbol was found. (#1362) +- You can now use the new `sourceType` configuration option to control how JavaScript files are + parsed. The default value is `module`. Set the value to `script` to suppress implied strict mode; + this setting will also prevent you from using ES2015 modules. (#1210) +- You can now use the new `recurseDepth` configuration option to control how many levels deep JSDoc + will recursively search for files. The default value is 10. (#1340) ### Bug fixes -+ JSDoc now correctly documents the constructors and instance properties of ES2015 classes. (#1182) -+ JSDoc now correctly documents the constructor of an ES2015 class exported from an ES2015 module. -(#1272) -+ JSDoc now uses the correct scope for exported symbols, and their children, in ES2015 modules. -(#1293) -+ When JSDoc is run in a directory that has a `plugins/` or `templates/` directory, JSDoc can now -discover plugins and templates in other directories. (#1081, #1308) -+ JSDoc no longer crashes when it reads a UTF-8 JSON file with a leading BOM. (#1256, #1297) -+ When a function is assigned to a variable, JSDoc now autodetects the function's default and -repeatable parameters. (#1054) -+ JSDoc no longer crashes when the `@author` tag does not have a value. (#1289) -+ JSDoc now always calls `process.exit()` when exiting. (#1287) +- JSDoc now correctly documents the constructors and instance properties of ES2015 classes. (#1182) +- JSDoc now correctly documents the constructor of an ES2015 class exported from an ES2015 module. + (#1272) +- JSDoc now uses the correct scope for exported symbols, and their children, in ES2015 modules. + (#1293) +- When JSDoc is run in a directory that has a `plugins/` or `templates/` directory, JSDoc can now + discover plugins and templates in other directories. (#1081, #1308) +- JSDoc no longer crashes when it reads a UTF-8 JSON file with a leading BOM. (#1256, #1297) +- When a function is assigned to a variable, JSDoc now autodetects the function's default and + repeatable parameters. (#1054) +- JSDoc no longer crashes when the `@author` tag does not have a value. (#1289) +- JSDoc now always calls `process.exit()` when exiting. (#1287) ### Default template -+ The default template now identifies asynchronous and generator functions. (#1158, #1188) -+ The default template now displays appropriate documentation for namespaces that are also -functions. (#955) -+ Images that are wider than the text area are now displayed correctly. (#1359) - - +- The default template now identifies asynchronous and generator functions. (#1158, #1188) +- The default template now displays appropriate documentation for namespaces that are also + functions. (#955) +- Images that are wider than the text area are now displayed correctly. (#1359) ## 3.4.3 (November 2016) Updated JSDoc's `LICENSE.md` file. - ## 3.4.2 (October 2016) -+ Classes exported from an ES2015 module are now documented correctly. (#1137) -+ Fixed an issue that prevented plugins and templates from being loaded correctly. (#1259) -+ Fixed a crash when using the experimental object spread operator in assignments. (#1258) - +- Classes exported from an ES2015 module are now documented correctly. (#1137) +- Fixed an issue that prevented plugins and templates from being loaded correctly. (#1259) +- Fixed a crash when using the experimental object spread operator in assignments. (#1258) ## 3.4.1 (September 2016) ### Enhancements -+ When installing JSDoc from NPM, all dependencies are now pulled from NPM. (#961) -+ The configuration setting `tags.allowUnknownTags` may now contain an array of tag names that -should be allowed. (#1159) +- When installing JSDoc from NPM, all dependencies are now pulled from NPM. (#961) +- The configuration setting `tags.allowUnknownTags` may now contain an array of tag names that + should be allowed. (#1159) ### Bug fixes -+ When an ES2015 module's default export is a class, JSDoc now documents the class correctly. -(#1113, #1120) -+ JSDoc no longer crashes when an ES2015 module exports an anonymous class. (#1113) -+ JSDoc no longer crashes when the experimental object spread operator is used. (#1141) -+ In ES2015 methods, JSDoc now autodetects whether a parameter is a default or repeatable parameter. -(#1144) -+ The Markdown plugin now works correctly with inline tags that contain special characters, such as -`{@link chat."#channel"}`. (#1035) -+ When JSDoc is run in a directory that has a `plugins/` or `templates/` directory, JSDoc can now -discover plugins and templates in other directories. (#1081) +- When an ES2015 module's default export is a class, JSDoc now documents the class correctly. + (#1113, #1120) +- JSDoc no longer crashes when an ES2015 module exports an anonymous class. (#1113) +- JSDoc no longer crashes when the experimental object spread operator is used. (#1141) +- In ES2015 methods, JSDoc now autodetects whether a parameter is a default or repeatable parameter. + (#1144) +- The Markdown plugin now works correctly with inline tags that contain special characters, such as + `{@link chat."#channel"}`. (#1035) +- When JSDoc is run in a directory that has a `plugins/` or `templates/` directory, JSDoc can now + discover plugins and templates in other directories. (#1081) ### Templates -+ The default template now uses appropriate styles for displaying tables. (#1064) -+ The default template's CSS file no longer uses the same style for both `

` and `

` elements. -(#1108) -+ JSDoc now includes a `silent` template that generates no output. This template makes it easier to -use JSDoc as a linter to check for syntax errors and unrecognized tags in documentation comments. -(#1160) - +- The default template now uses appropriate styles for displaying tables. (#1064) +- The default template's CSS file no longer uses the same style for both `

` and `

` elements. + (#1108) +- JSDoc now includes a `silent` template that generates no output. This template makes it easier to + use JSDoc as a linter to check for syntax errors and unrecognized tags in documentation comments. + (#1160) ## 3.4.0 (November 2015) ### Major changes -+ JSDoc is now compatible with Node.js 4.0.0 and later. -+ JSDoc no longer runs on Mozilla Rhino. Use Node.js to run JSDoc. -+ JSDoc can now parse ECMAScript 2015 code, including code that uses native classes and modules. -(#555) -+ JSDoc can now parse [JSX](https://facebook.github.io/jsx/) files. (#1001) -+ JSDoc's `app` and `env` global variables are now deprecated. Avoid using the `app` global. Use the -`jsdoc/env` module instead of the `env` global. (#812) +- JSDoc is now compatible with Node.js 4.0.0 and later. +- JSDoc no longer runs on Mozilla Rhino. Use Node.js to run JSDoc. +- JSDoc can now parse ECMAScript 2015 code, including code that uses native classes and modules. + (#555) +- JSDoc can now parse [JSX](https://facebook.github.io/jsx/) files. (#1001) +- JSDoc's `app` and `env` global variables are now deprecated. Avoid using the `app` global. Use the + `jsdoc/env` module instead of the `env` global. (#812) ### Enhancements -+ `const` declarations are now automatically treated as constants. (#555) -+ Templates may now run asynchronously. To create an asynchronous template, simply return a promise -from your template's `publish` method. (#953) +- `const` declarations are now automatically treated as constants. (#555) +- Templates may now run asynchronously. To create an asynchronous template, simply return a promise + from your template's `publish` method. (#953) ### Bug fixes -+ Symbols now get the correct longname when they are defined as properties of a prototype and -include special characters, such as `#` and `.` (for example, `Foo.prototype['this#is#bar']`). -(#888) -+ Instance members that are defined as computed properties of `this` (for example, `this['bar']`) -now get the correct longname. (#890) -+ When an instance member (for example, `this.bar`) is documented within a member of a prototype -(for example, `Foo.prototype.setBar`), the instance member's longname is now set correctly. (#1011) -+ The `@borrows` tag now works with symbol names that contain whitespace. (#818) +- Symbols now get the correct longname when they are defined as properties of a prototype and + include special characters, such as `#` and `.` (for example, `Foo.prototype['this#is#bar']`). + (#888) +- Instance members that are defined as computed properties of `this` (for example, `this['bar']`) + now get the correct longname. (#890) +- When an instance member (for example, `this.bar`) is documented within a member of a prototype + (for example, `Foo.prototype.setBar`), the instance member's longname is now set correctly. (#1011) +- The `@borrows` tag now works with symbol names that contain whitespace. (#818) ### Plugins -+ For the Markdown plugin, you can now autogenerate a heading ID for each heading by setting the -configuration property `markdown.idInHeadings` to `true`. (#1032) +- For the Markdown plugin, you can now autogenerate a heading ID for each heading by setting the + configuration property `markdown.idInHeadings` to `true`. (#1032) ### Template improvements -+ In the default template, you can now show the full namepath of each object in the navigation -column by setting the configuration property `templates.default.useLongnameInNav` to `true`. (#986) -+ In the Haruki template, falsy default values now appear in the output. (#1063) - +- In the default template, you can now show the full namepath of each object in the navigation + column by setting the configuration property `templates.default.useLongnameInNav` to `true`. (#986) +- In the Haruki template, falsy default values now appear in the output. (#1063) ## 3.3.3 (September 2015) -+ Symbols named `prototype` are now handled correctly. (#891) -+ Fixed an issue that could cause JSDoc to go into an infinite loop when a module is documented -twice. (#975) -+ Fixed an issue that could cause parsing errors on valid regular expressions. (#1053) - +- Symbols named `prototype` are now handled correctly. (#891) +- Fixed an issue that could cause JSDoc to go into an infinite loop when a module is documented + twice. (#975) +- Fixed an issue that could cause parsing errors on valid regular expressions. (#1053) ## 3.3.2 (June 2015) JSDoc no longer crashes when parsing a large number of files, or a single object that has a large number of properties. (#976) - ## 3.3.1 (June 2015) -+ Fixed a crash in the Haruki template. (#1005) -+ When a type expression includes a record type with numeric keys (for example, `{0: string}`), the -type expression is now parsed correctly. (#1016) - +- Fixed a crash in the Haruki template. (#1005) +- When a type expression includes a record type with numeric keys (for example, `{0: string}`), the + type expression is now parsed correctly. (#1016) ## 3.3.0 (May 2015) ### Major changes -+ You can now run JSDoc on Node.js. (#93) -+ You can now use the `@interface` and `@implements` tags to document interfaces and their -implementations. (#720, #828) -+ Closure Compiler's `@inheritDoc` and `@override` tags are now supported. (#53) -+ If the JSDoc comment for a symbol includes the `@mixes` tag, all of the mixins now appear in the -symbol's documentation. (#378) -+ JSDoc can now log information to the console as it runs (for example, the name of each file that -JSDoc parses). To log this information, run JSDoc with the `--verbose` flag. (#416) -+ You can now use any file as the package or README file for your documentation. Use the -`-P/--package/` and `-R/--readme` flags to specify the package and README file. (#708) -+ The default template's typography and color scheme have been significantly improved. (#550, #780, -#843) +- You can now run JSDoc on Node.js. (#93) +- You can now use the `@interface` and `@implements` tags to document interfaces and their + implementations. (#720, #828) +- Closure Compiler's `@inheritDoc` and `@override` tags are now supported. (#53) +- If the JSDoc comment for a symbol includes the `@mixes` tag, all of the mixins now appear in the + symbol's documentation. (#378) +- JSDoc can now log information to the console as it runs (for example, the name of each file that + JSDoc parses). To log this information, run JSDoc with the `--verbose` flag. (#416) +- You can now use any file as the package or README file for your documentation. Use the + `-P/--package/` and `-R/--readme` flags to specify the package and README file. (#708) +- The default template's typography and color scheme have been significantly improved. (#550, #780, + #843) ### Enhancements -+ You can now use the `--pedantic` flag to treat all errors as fatal errors, and to treat warnings -as errors. This flag replaces the `--lenient` flag, which had roughly the opposite meaning and is no -longer available. (#416) -+ You can now use the `-a/--access` flag to control whether private, protected, and public symbols -appear in the documentation. (#860, #861) -+ You can now use the `--debug` flag to log detailed debugging information to the console. This -information can help you diagnose bugs in JSDoc itself. (#416) -+ JSDoc's configuration file can now contain JavaScript comments. (#660) -+ You can now include source files from a directory, but exclude one of its subdirectories, by -adding the subdirectory to the `source.exclude` option in the configuration file. (#484) -+ The `source.exclude` option now works correctly when JSDoc is run with the `-r/--recurse` flag. -(#616) -+ When JSDoc is run with the `-r/--recurse` flag, it now scans for tutorials recursively. (#712) -+ JSDoc's `-X/--explain` option now runs much more quickly. (#633) -+ If all of the text for an `@example` tag is indented, JSDoc now removes the extra indentation. -(#540) -+ The default value for a parameter or property can now include brackets (for example, -`@param {Array.} [foo=['bar']]`). (#640) -+ You can now provide a default value for parameters and properties that are not optional (for -example, `@property {string} foo='bar'`). (#791) -+ If the `@type` tag includes a description (for example, `@type {string} some text`), JSDoc now -parses the type expression correctly and discards the description. (#615) -+ You can now add JSDoc comments to function parameters. (#473) -+ For Closure Compiler projects, you can now enable a Closure Compiler-specific tag dictionary that -more closely matches Closure Compiler's semantics. To enable Closure Compiler semantics, set the -configuration file's `tags.dictionaries` option to `['closure']`. This option can contain the values -`jsdoc`, `closure`, or both. If multiple dictionaries are enabled, and a tag is defined in more than -one dictionary, JSDoc uses the definition from the first dictionary that contains the tag. (#729, -#730, #731, #732) -+ If one symbol overrides another, JSDoc now adds an `overrides` property to the doclet that is -overriding another. The `overrides` property contains the longname of the overridden symbol. (#792) -+ When a JSDoc tag contains a type expression, the doclet's `type` object now includes a hidden -`parsedType` property. The `parsedType` property contains a syntax tree that represents the type -expression. The syntax tree is generated by [Catharsis](https://github.com/hegemonic/catharsis), and -its format may change in the future. (#576) -+ JSDoc now allows output filenames to contain non-ASCII characters. In addition, links to output -files are now URL-encoded when necessary. (#677) -+ JSDoc now ensures that output filenames do not have a leading underscore. (#758) -+ JSDoc now tries to ensure that `id` attributes in output files are unique within that file. (#539) -+ JSDoc now has an up-to-date JSON Schema file for parse results. The schema file is available in -`lib/jsdoc/schema.js`. (#327) -+ JSDoc now extracts more information from package files. (#710) -+ JSDoc now displays usage information if you run JSDoc without any input files, or with an -unrecognized command-line option. (#609, #840) +- You can now use the `--pedantic` flag to treat all errors as fatal errors, and to treat warnings + as errors. This flag replaces the `--lenient` flag, which had roughly the opposite meaning and is no + longer available. (#416) +- You can now use the `-a/--access` flag to control whether private, protected, and public symbols + appear in the documentation. (#860, #861) +- You can now use the `--debug` flag to log detailed debugging information to the console. This + information can help you diagnose bugs in JSDoc itself. (#416) +- JSDoc's configuration file can now contain JavaScript comments. (#660) +- You can now include source files from a directory, but exclude one of its subdirectories, by + adding the subdirectory to the `source.exclude` option in the configuration file. (#484) +- The `source.exclude` option now works correctly when JSDoc is run with the `-r/--recurse` flag. + (#616) +- When JSDoc is run with the `-r/--recurse` flag, it now scans for tutorials recursively. (#712) +- JSDoc's `-X/--explain` option now runs much more quickly. (#633) +- If all of the text for an `@example` tag is indented, JSDoc now removes the extra indentation. + (#540) +- The default value for a parameter or property can now include brackets (for example, + `@param {Array.} [foo=['bar']]`). (#640) +- You can now provide a default value for parameters and properties that are not optional (for + example, `@property {string} foo='bar'`). (#791) +- If the `@type` tag includes a description (for example, `@type {string} some text`), JSDoc now + parses the type expression correctly and discards the description. (#615) +- You can now add JSDoc comments to function parameters. (#473) +- For Closure Compiler projects, you can now enable a Closure Compiler-specific tag dictionary that + more closely matches Closure Compiler's semantics. To enable Closure Compiler semantics, set the + configuration file's `tags.dictionaries` option to `['closure']`. This option can contain the values + `jsdoc`, `closure`, or both. If multiple dictionaries are enabled, and a tag is defined in more than + one dictionary, JSDoc uses the definition from the first dictionary that contains the tag. (#729, + #730, #731, #732) +- If one symbol overrides another, JSDoc now adds an `overrides` property to the doclet that is + overriding another. The `overrides` property contains the longname of the overridden symbol. (#792) +- When a JSDoc tag contains a type expression, the doclet's `type` object now includes a hidden + `parsedType` property. The `parsedType` property contains a syntax tree that represents the type + expression. The syntax tree is generated by [Catharsis](https://github.com/hegemonic/catharsis), and + its format may change in the future. (#576) +- JSDoc now allows output filenames to contain non-ASCII characters. In addition, links to output + files are now URL-encoded when necessary. (#677) +- JSDoc now ensures that output filenames do not have a leading underscore. (#758) +- JSDoc now tries to ensure that `id` attributes in output files are unique within that file. (#539) +- JSDoc now has an up-to-date JSON Schema file for parse results. The schema file is available in + `lib/jsdoc/schema.js`. (#327) +- JSDoc now extracts more information from package files. (#710) +- JSDoc now displays usage information if you run JSDoc without any input files, or with an + unrecognized command-line option. (#609, #840) ### Bug fixes -+ When the `allowUnknownTags` option is set to `false`, JSDoc no longer logs warnings about the -presence of `@also` and `@scope` tags. (#574) -+ Fixed several errors when parsing type expressions. (#619, #644, #652, #705, #767) -+ Properties added to the `module.exports` object can now be documented. (#500) -+ When a symbol's name starts with the same characters as its parent namespace (such as `Vector` in -`V.Vector`), JSDoc now assigns the correct longname to the symbol. (#608) -+ If a child class inherits from multiple parent classes, and the parent classes have instance -members with the same name, the child class no longer displays the documentation from both parent -classes. (#613) -+ If a source file contains an object literal, and one of the property names is a whitespace -character or a character that must be escaped in a regular expression, JSDoc now parses the file -successfully. (#549, #775) -+ Virtual comments now work correctly for overloaded functions. (#727) -+ When a virtual comment appears within a module, JSDoc now assigns the correct values to the -virtual comment doclet's `memberof`, `longname`, and `scope` properties. (#631) -+ JSDoc now sets the `scope` property to `global` for all global doclets. (#684) -+ Module doclets no longer have a `scope` property. (#782) -+ In Markdown tutorials, JSDoc no longer unescapes HTML entities. (#743) -+ If a longname includes a variation (for example, `Foo#bar(variation)`), the link text is now -preserved when generating HTML links. (#857) -+ When a single JSDoc comment includes `@class`, `@classdesc`, and `@constructor` tags, JSDoc no -longer ignores the value of the `@classdesc` tag. (#806) -+ For tags where the name and type are both optional (`@constant`, `@external`, `@member`, -`@module`, `@namespace`, and `@param`), JSDoc now parses the tag correctly when it includes a type -but not a name. (#351, #535) -+ The `@default` tag now works correctly when used with an array literal. (#604) -+ The `@enum` tag now works correctly when the enumeration is part of a chain of assignments (for -example, `var FOO = exports.FOO = {/* enumerated values */}`). (#702) -+ The `@exports` and `@module` tags now work correctly when their value includes a `module:` -namespace (for example, `@exports module:foo`). (#786) -+ The `@memberof` tag now works correctly when it refers to a module that is defined in a separate -file. (#880) -+ The `@variation` tag now works correctly when its value is enclosed in parentheses (for example, -`@variation (foo)`). (#850) +- When the `allowUnknownTags` option is set to `false`, JSDoc no longer logs warnings about the + presence of `@also` and `@scope` tags. (#574) +- Fixed several errors when parsing type expressions. (#619, #644, #652, #705, #767) +- Properties added to the `module.exports` object can now be documented. (#500) +- When a symbol's name starts with the same characters as its parent namespace (such as `Vector` in + `V.Vector`), JSDoc now assigns the correct longname to the symbol. (#608) +- If a child class inherits from multiple parent classes, and the parent classes have instance + members with the same name, the child class no longer displays the documentation from both parent + classes. (#613) +- If a source file contains an object literal, and one of the property names is a whitespace + character or a character that must be escaped in a regular expression, JSDoc now parses the file + successfully. (#549, #775) +- Virtual comments now work correctly for overloaded functions. (#727) +- When a virtual comment appears within a module, JSDoc now assigns the correct values to the + virtual comment doclet's `memberof`, `longname`, and `scope` properties. (#631) +- JSDoc now sets the `scope` property to `global` for all global doclets. (#684) +- Module doclets no longer have a `scope` property. (#782) +- In Markdown tutorials, JSDoc no longer unescapes HTML entities. (#743) +- If a longname includes a variation (for example, `Foo#bar(variation)`), the link text is now + preserved when generating HTML links. (#857) +- When a single JSDoc comment includes `@class`, `@classdesc`, and `@constructor` tags, JSDoc no + longer ignores the value of the `@classdesc` tag. (#806) +- For tags where the name and type are both optional (`@constant`, `@external`, `@member`, + `@module`, `@namespace`, and `@param`), JSDoc now parses the tag correctly when it includes a type + but not a name. (#351, #535) +- The `@default` tag now works correctly when used with an array literal. (#604) +- The `@enum` tag now works correctly when the enumeration is part of a chain of assignments (for + example, `var FOO = exports.FOO = {/* enumerated values */}`). (#702) +- The `@exports` and `@module` tags now work correctly when their value includes a `module:` + namespace (for example, `@exports module:foo`). (#786) +- The `@memberof` tag now works correctly when it refers to a module that is defined in a separate + file. (#880) +- The `@variation` tag now works correctly when its value is enclosed in parentheses (for example, + `@variation (foo)`). (#850) ### Plugins -+ Tag definitions can now have a `mustNotHaveDescription` property. When this property is set to -`true`, JSDoc will warn the user if the tag text includes a description (such as `The description` -in `@param {string} foo - The description`). (#615) -+ Tag definitions can now call the method `dictionary.normalize`, which is a synonym for -`dictionary.normalise`. (#884) -+ The Markdown plugin no longer prevents inline `{@link}` tags from working. (#518) -+ The Markdown plugin now converts `@author` and `@throws` tag values to HTML by default. (#736, -#878) -+ JSDoc now includes a `summarize` plugin that automatically generates summaries based on the -description. (#485) -+ JSDoc now includes an `underscore` plugin that finds symbols whose names begin with an underscore -and automatically tags them as `@private`. (#471) -+ Plugins can now replace the `doclet` property of `newDoclet` events. (#584) +- Tag definitions can now have a `mustNotHaveDescription` property. When this property is set to + `true`, JSDoc will warn the user if the tag text includes a description (such as `The description` + in `@param {string} foo - The description`). (#615) +- Tag definitions can now call the method `dictionary.normalize`, which is a synonym for + `dictionary.normalise`. (#884) +- The Markdown plugin no longer prevents inline `{@link}` tags from working. (#518) +- The Markdown plugin now converts `@author` and `@throws` tag values to HTML by default. (#736, + #878) +- JSDoc now includes a `summarize` plugin that automatically generates summaries based on the + description. (#485) +- JSDoc now includes an `underscore` plugin that finds symbols whose names begin with an underscore + and automatically tags them as `@private`. (#471) +- Plugins can now replace the `doclet` property of `newDoclet` events. (#584) ### Template improvements -+ You can now override the default template's main layout file, `layout.tmpl`, by setting the -`templates.default.layoutFile` option in JSDoc's configuration file. The property can contain a -relative or absolute path to the replacement for `layout.tmpl`. Relative paths are resolved against -the path to the configuration file; the current working directory; and the JSDoc directory, in that -order. (#480) -+ When the `templates.default.outputSourceFiles` option is set to `false`, the documentation no -longer shows the path to each source file. (#571) -+ You can now use the property `templates.default.staticFiles.include` to list files that will be -copied to the output directory. For backwards compatibility, the property -`templates.default.staticFiles.paths` is also supported but is deprecated. (#785) -+ The property `templates.default.staticFiles.include` now works correctly when an absolute path is -specified. (#939) -+ The `templates.default.staticFiles` options now work correctly on Windows. (#785) -+ In output files, you can now prevent the date from appearing in the footer by setting the property -`templates.default.includeDate` to `false`. (#910) -+ Output files no longer show the default value for members of an enumeration. (#689) -+ In certain types of AMD modules, the module-overview section is no longer duplicated. (#853) -+ If a constructor is assigned to `module.exports`, the value of the `@classdesc` tag now appears in -the documentation. (#740) -+ If a constructor is assigned to `module.exports`, and the constructor inherits from another class, -the parent class is now listed in the documentation. (#594) -+ Text within an `@example` tag, including HTML tags, is now properly escaped. (#511) -+ If a member has a `@fires` tag, the tag information now appears in the documentation. (#568) -+ If a symbol has members that use the `@mixin` tag, the mixins are now listed in the documentation. -(#379, #602) -+ When multiple `@param` tags are used to document properties of array values (for example, -`@param {Object[]} foo` and `@param {string} foo[].bar`), the properties are now grouped into the -appropriate row of the parameters table. (#870) -+ If a member has a `@requires` tag, the tag information now appears in the documentation. (#563) -+ Type expressions are now presented more clearly. (#618) -+ Pretty-printed source files now include line numbers. (#532) -+ When you run JSDoc with a single input file, the full path to the file no longer appears in the -documentation. (#553) -+ When an overloaded function is assigned to `module.exports`, the documentation now displays all of -the signatures for the overloaded function. (#727) -+ Resolved several issues that caused the default template to generate invalid HTML. (#843) - +- You can now override the default template's main layout file, `layout.tmpl`, by setting the + `templates.default.layoutFile` option in JSDoc's configuration file. The property can contain a + relative or absolute path to the replacement for `layout.tmpl`. Relative paths are resolved against + the path to the configuration file; the current working directory; and the JSDoc directory, in that + order. (#480) +- When the `templates.default.outputSourceFiles` option is set to `false`, the documentation no + longer shows the path to each source file. (#571) +- You can now use the property `templates.default.staticFiles.include` to list files that will be + copied to the output directory. For backwards compatibility, the property + `templates.default.staticFiles.paths` is also supported but is deprecated. (#785) +- The property `templates.default.staticFiles.include` now works correctly when an absolute path is + specified. (#939) +- The `templates.default.staticFiles` options now work correctly on Windows. (#785) +- In output files, you can now prevent the date from appearing in the footer by setting the property + `templates.default.includeDate` to `false`. (#910) +- Output files no longer show the default value for members of an enumeration. (#689) +- In certain types of AMD modules, the module-overview section is no longer duplicated. (#853) +- If a constructor is assigned to `module.exports`, the value of the `@classdesc` tag now appears in + the documentation. (#740) +- If a constructor is assigned to `module.exports`, and the constructor inherits from another class, + the parent class is now listed in the documentation. (#594) +- Text within an `@example` tag, including HTML tags, is now properly escaped. (#511) +- If a member has a `@fires` tag, the tag information now appears in the documentation. (#568) +- If a symbol has members that use the `@mixin` tag, the mixins are now listed in the documentation. + (#379, #602) +- When multiple `@param` tags are used to document properties of array values (for example, + `@param {Object[]} foo` and `@param {string} foo[].bar`), the properties are now grouped into the + appropriate row of the parameters table. (#870) +- If a member has a `@requires` tag, the tag information now appears in the documentation. (#563) +- Type expressions are now presented more clearly. (#618) +- Pretty-printed source files now include line numbers. (#532) +- When you run JSDoc with a single input file, the full path to the file no longer appears in the + documentation. (#553) +- When an overloaded function is assigned to `module.exports`, the documentation now displays all of + the signatures for the overloaded function. (#727) +- Resolved several issues that caused the default template to generate invalid HTML. (#843) ## 3.2.2 (November 2013) ### Bug fixes -+ Addressed a regression in JSDoc 3.2.1 that could prevent a function declaration from shadowing a -declaration with the same name in an outer scope. (#513) -+ If a child class overrides a method in a parent class without documenting the overridden method, -the method's documentation is now copied from the parent class. (#503) -+ You can now use inline HTML tags in Markdown-formatted text. In addition, JSDoc now uses only the -[marked Markdown parser](https://github.com/chjj/marked); the markdown-js parser has been removed. -(#510) -+ Type expressions can now include a much broader range of repeatable types. In addition, you can -now use Closure Compiler's nullable and non-nullable modifiers with repeatable types. For example, -the type expression `...!string` (a repeatable, non-nullable string) is now parsed correctly. (#502) -+ If a function accepts a parameter named `prototype`, the parameter is no longer renamed during -parsing. (#505) -+ If the list of input files includes relative paths, the paths are now resolved relative to the -user's working directory. (a3d33842) - +- Addressed a regression in JSDoc 3.2.1 that could prevent a function declaration from shadowing a + declaration with the same name in an outer scope. (#513) +- If a child class overrides a method in a parent class without documenting the overridden method, + the method's documentation is now copied from the parent class. (#503) +- You can now use inline HTML tags in Markdown-formatted text. In addition, JSDoc now uses only the + [marked Markdown parser](https://github.com/chjj/marked); the markdown-js parser has been removed. + (#510) +- Type expressions can now include a much broader range of repeatable types. In addition, you can + now use Closure Compiler's nullable and non-nullable modifiers with repeatable types. For example, + the type expression `...!string` (a repeatable, non-nullable string) is now parsed correctly. (#502) +- If a function accepts a parameter named `prototype`, the parameter is no longer renamed during + parsing. (#505) +- If the list of input files includes relative paths, the paths are now resolved relative to the + user's working directory. (a3d33842) ## 3.2.1 (October 2013) ### Enhancements -+ JSDoc's parser now fires a `processingComplete` event after JSDoc has completed all -post-processing of the parse results. This event has a `doclets` property containing an array of -doclets. (#421) -+ When JSDoc's parser fires a `parseComplete` event, the event now includes a `doclets` property -containing an array of doclets. (#431) -+ You can now use relative paths in the JSDoc configuration file's `source.exclude` option. Relative -paths will be resolved relative to the current working directory. (#405) -+ If a symbol uses the `@default` tag, and its default value is an object literal, this value is now -stored as a string, and the doclet will have a `defaultvaluetype` property containing the string -`object`. This change enables templates to show the default value with appropriate syntax -highlighting. (#419) -+ Inline `{@link}` tags can now contain newlines. (#441) +- JSDoc's parser now fires a `processingComplete` event after JSDoc has completed all + post-processing of the parse results. This event has a `doclets` property containing an array of + doclets. (#421) +- When JSDoc's parser fires a `parseComplete` event, the event now includes a `doclets` property + containing an array of doclets. (#431) +- You can now use relative paths in the JSDoc configuration file's `source.exclude` option. Relative + paths will be resolved relative to the current working directory. (#405) +- If a symbol uses the `@default` tag, and its default value is an object literal, this value is now + stored as a string, and the doclet will have a `defaultvaluetype` property containing the string + `object`. This change enables templates to show the default value with appropriate syntax + highlighting. (#419) +- Inline `{@link}` tags can now contain newlines. (#441) ### Bug fixes -+ Inherited symbols now indicate that they were inherited from the ancestor that defined the symbol, -rather than the direct parent. (#422) -+ If the first line of a JavaScript file contains a hashbang (for example, `#!/usr/bin/env node`), -the hashbang is now ignored when the file is parsed. (#499) -+ Resolved a crash when a JavaScript file contains a [JavaScript -1.8](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.8) keyword, such as -`let`. (#477) -+ The type expression `function[]` is now parsed correctly. (#493) -+ If a module is tagged incorrectly, the module's output file now has a valid filename. (#440, #458) -+ For tags that accept names, such as `@module` and `@param`, if a hyphen is used to separate the -name and description, the hyphen must appear on the same line as the name. This change prevents a -Markdown bullet on the followng line from being interpreted as a separator. (#459) -+ When lenient mode is enabled, a `@param` tag with an invalid type expression no longer causes a -crash. (#448) -+ The `@requires` tag can now contain an inline tag in its tag text. (#486) -+ The `@returns` tag can now contain inline tags even if a type is not specified. (#444) -+ When lenient mode is enabled, a `@returns` tag with no value no longer causes a crash. (#451) -+ The `@type` tag now works correctly with type expressions that span multiple lines. (#427) -+ If a string contains inline `{@link}` tags preceded by bracketed link text (for example, -`[test]{@link Test#test}`), HTML links are now generated correctly even if the string contains other -bracketed text. (#470) -+ On POSIX systems, if you run JSDoc using a symlink to the startup script, JSDoc now works -correctly. (#492) +- Inherited symbols now indicate that they were inherited from the ancestor that defined the symbol, + rather than the direct parent. (#422) +- If the first line of a JavaScript file contains a hashbang (for example, `#!/usr/bin/env node`), + the hashbang is now ignored when the file is parsed. (#499) +- Resolved a crash when a JavaScript file contains a [JavaScript + 1.8](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.8) keyword, such as + `let`. (#477) +- The type expression `function[]` is now parsed correctly. (#493) +- If a module is tagged incorrectly, the module's output file now has a valid filename. (#440, #458) +- For tags that accept names, such as `@module` and `@param`, if a hyphen is used to separate the + name and description, the hyphen must appear on the same line as the name. This change prevents a + Markdown bullet on the followng line from being interpreted as a separator. (#459) +- When lenient mode is enabled, a `@param` tag with an invalid type expression no longer causes a + crash. (#448) +- The `@requires` tag can now contain an inline tag in its tag text. (#486) +- The `@returns` tag can now contain inline tags even if a type is not specified. (#444) +- When lenient mode is enabled, a `@returns` tag with no value no longer causes a crash. (#451) +- The `@type` tag now works correctly with type expressions that span multiple lines. (#427) +- If a string contains inline `{@link}` tags preceded by bracketed link text (for example, + `[test]{@link Test#test}`), HTML links are now generated correctly even if the string contains other + bracketed text. (#470) +- On POSIX systems, if you run JSDoc using a symlink to the startup script, JSDoc now works + correctly. (#492) ### Default template -+ Pretty-printed source files are now generated by default. To disable this feature, add the -property `templates.default.outputSourceFiles: false` to your `conf.json` file. (#454) -+ Links to a specific line in a source file now work correctly. (#475) -+ Pretty-printed source files are now generated using the encoding specified in the `-e/--encoding` -option. (#496) -+ If a `@default` tag is added to a symbol whose default value is an object, the value is now -displayed in the output file. (#419) -+ Output files now identify symbols as "abstract" rather than "virtual." (#432) - +- Pretty-printed source files are now generated by default. To disable this feature, add the + property `templates.default.outputSourceFiles: false` to your `conf.json` file. (#454) +- Links to a specific line in a source file now work correctly. (#475) +- Pretty-printed source files are now generated using the encoding specified in the `-e/--encoding` + option. (#496) +- If a `@default` tag is added to a symbol whose default value is an object, the value is now + displayed in the output file. (#419) +- Output files now identify symbols as "abstract" rather than "virtual." (#432) ## 3.2.0 (May 2013) ### Major changes -+ JSDoc can now parse any valid [Google Closure Compiler type -expression](https://developers.google.com/closure/compiler/docs/js-for-compiler#types). **Note**: As -a result of this change, JSDoc quits if a file contains an invalid type expression. To prevent JSDoc -from quitting, run JSDoc with the `--lenient` (`-l`) command-line option. (Multiple issues) -+ You can now use the new `@listens` tag to indicate that a symbol listens for an event. (#273) +- JSDoc can now parse any valid [Google Closure Compiler type + expression](https://developers.google.com/closure/compiler/docs/js-for-compiler#types). **Note**: As + a result of this change, JSDoc quits if a file contains an invalid type expression. To prevent JSDoc + from quitting, run JSDoc with the `--lenient` (`-l`) command-line option. (Multiple issues) +- You can now use the new `@listens` tag to indicate that a symbol listens for an event. (#273) ### Enhancements -+ The parser now fires a `parseBegin` event before it starts parsing files, as well as a -`parseComplete` event after all files have been parsed. Plugins can define event handlers for these -events, and `parseBegin` handlers can modify the list of files to parse. (#299) -+ Event handlers for `jsdocCommentFound` events can now modify the JSDoc comment. (#228) -+ You can now exclude tags from Markdown processing using the new option `markdown.excludeTags` in -the configuration file. (#337) -+ You can now use the [marked](https://github.com/chjj/marked) Markdown parser by setting the -configuration property `markdown.parser` to `marked`. In addition, if `markdown.parser` is set to -`gfm`, JSDoc will now use the "marked" parser instead. (#385) -+ The `@typedef` tag no longer requires a name when used with a Closure Compiler-style type -definition. For example, the following type definition will automatically get the name `Foo.Bar`: +- The parser now fires a `parseBegin` event before it starts parsing files, as well as a + `parseComplete` event after all files have been parsed. Plugins can define event handlers for these + events, and `parseBegin` handlers can modify the list of files to parse. (#299) +- Event handlers for `jsdocCommentFound` events can now modify the JSDoc comment. (#228) +- You can now exclude tags from Markdown processing using the new option `markdown.excludeTags` in + the configuration file. (#337) +- You can now use the [marked](https://github.com/chjj/marked) Markdown parser by setting the + configuration property `markdown.parser` to `marked`. In addition, if `markdown.parser` is set to + `gfm`, JSDoc will now use the "marked" parser instead. (#385) +- The `@typedef` tag no longer requires a name when used with a Closure Compiler-style type + definition. For example, the following type definition will automatically get the name `Foo.Bar`: - ```javascript - /** @typedef {string} */ - Foo.Bar; - ``` + ```javascript + /** @typedef {string} */ + Foo.Bar; + ``` - (#391) -+ You can now use an inline `{@type}` tag in a parameter's description. If this tag is present, -JSDoc will assume that the parameter uses the type specified in the inline `{@type}` tag. For -example, the following `@param` tag would cause `myParam`'s type to be documented as `Foo`: + (#391) - ``` - @param {(boolean|string)} myParam - My special parameter. {@type Foo} - ``` +- You can now use an inline `{@type}` tag in a parameter's description. If this tag is present, + JSDoc will assume that the parameter uses the type specified in the inline `{@type}` tag. For + example, the following `@param` tag would cause `myParam`'s type to be documented as `Foo`: - (#152) -+ The `console.log` function now behaves the same way as on Node.js. In addition, the functions -`console.info`, `console.error`, `console.warn`, and `console.trace` have been implemented. (#298) -+ You can now use npm to install JSDoc globally by running `npm install -g`. **Note**: JSDoc will -still run under Mozilla Rhino, not Node.js. (#374) -+ The `jsVersion` configuration property has been removed. (#390) + ``` + @param {(boolean|string)} myParam - My special parameter. {@type Foo} + ``` + + (#152) + +- The `console.log` function now behaves the same way as on Node.js. In addition, the functions + `console.info`, `console.error`, `console.warn`, and `console.trace` have been implemented. (#298) +- You can now use npm to install JSDoc globally by running `npm install -g`. **Note**: JSDoc will + still run under Mozilla Rhino, not Node.js. (#374) +- The `jsVersion` configuration property has been removed. (#390) ### Bug fixes -+ JSDoc now quits if the configuration file cannot be loaded. (#407) -+ JSDoc's `--explain` (`-X`) option now runs much more quickly, and it outputs valid JSON to the -console. (#298) -+ JSDoc's `--lenient` (`-l`) option now prints warnings on STDERR rather than STDOUT. (#298) -+ The parser now assigns the correct scope to object properties whose names include single quotes. -(#386) -+ The parser now recognizes CommonJS modules that export a single function rather than an object. -(#384) -+ The inline `{@link}` tag now works correctly when `@link` is followed by a tab. (#359) -+ On POSIX systems, quoted command-line arguments are no longer split on spaces. (#397) +- JSDoc now quits if the configuration file cannot be loaded. (#407) +- JSDoc's `--explain` (`-X`) option now runs much more quickly, and it outputs valid JSON to the + console. (#298) +- JSDoc's `--lenient` (`-l`) option now prints warnings on STDERR rather than STDOUT. (#298) +- The parser now assigns the correct scope to object properties whose names include single quotes. + (#386) +- The parser now recognizes CommonJS modules that export a single function rather than an object. + (#384) +- The inline `{@link}` tag now works correctly when `@link` is followed by a tab. (#359) +- On POSIX systems, quoted command-line arguments are no longer split on spaces. (#397) ### Plugins -+ The new `overloadHelper` plugin makes it easier to link to overloaded methods. (#179) -+ The `markdown` plugin now converts Markdown links in the `@see` tag. (#297) +- The new `overloadHelper` plugin makes it easier to link to overloaded methods. (#179) +- The `markdown` plugin now converts Markdown links in the `@see` tag. (#297) ### Default template enhancements -+ You can now use the configuration property `templates.default.staticFiles` to copy additional -static files to the output directory. (#393) -+ All output files now use human-readable filenames. (#339) -+ The documentation for events now lists the symbols that listen to that event. (#273) -+ Links to source files now allow you to jump to the line where a symbol is defined. (#316) -+ The output files now link to individual types within a Closure Compiler type expression. (Multiple -issues) -+ CommonJS modules that export a single function, rather than an object, are now documented more -clearly. (#384) -+ Functions that can throw multiple types of errors are now documented more clearly. (#389) -+ If a `@property` tag does not identify the property's name, the template no longer throws an -error. (#373) -+ The type of each `@typedef` is now displayed. (#391) -+ If a `@see` tag contains a URL (for example, `@see http://example.com` or -`@see `), the tag text is now converted to a link. (#371) -+ Repeatable parameters are now identified. (#381) -+ The "Classes" header is no longer repeated in the navigation bar. (#361) -+ When the only documented symbols in global scope are type definitions, you can now click the -"Global" header to view their documentation. (#261) - +- You can now use the configuration property `templates.default.staticFiles` to copy additional + static files to the output directory. (#393) +- All output files now use human-readable filenames. (#339) +- The documentation for events now lists the symbols that listen to that event. (#273) +- Links to source files now allow you to jump to the line where a symbol is defined. (#316) +- The output files now link to individual types within a Closure Compiler type expression. (Multiple + issues) +- CommonJS modules that export a single function, rather than an object, are now documented more + clearly. (#384) +- Functions that can throw multiple types of errors are now documented more clearly. (#389) +- If a `@property` tag does not identify the property's name, the template no longer throws an + error. (#373) +- The type of each `@typedef` is now displayed. (#391) +- If a `@see` tag contains a URL (for example, `@see http://example.com` or + `@see `), the tag text is now converted to a link. (#371) +- Repeatable parameters are now identified. (#381) +- The "Classes" header is no longer repeated in the navigation bar. (#361) +- When the only documented symbols in global scope are type definitions, you can now click the + "Global" header to view their documentation. (#261) ## 3.1.1 (February 2013) -+ Resolved a crash when no input files contain JSDoc comments. (#329) -+ Resolved a crash when JSDoc cannot identify the common prefix of several paths. (#330) -+ Resolved a crash when the full path to JSDoc contained at least one space. (#347) -+ Files named `README.md` or `package.json` will now be processed when they are specified on the -command line. (#350) -+ You can now use `@emits` as a synonym for `@fires`. (#324) -+ The module `jsdoc/util/templateHelper` now allows you to specify the CSS class for links that are -generated by the following methods: (#331) - + `getAncestorLinks` - + `getSignatureReturns` - + `getSignatureTypes` - + `linkto` - +- Resolved a crash when no input files contain JSDoc comments. (#329) +- Resolved a crash when JSDoc cannot identify the common prefix of several paths. (#330) +- Resolved a crash when the full path to JSDoc contained at least one space. (#347) +- Files named `README.md` or `package.json` will now be processed when they are specified on the + command line. (#350) +- You can now use `@emits` as a synonym for `@fires`. (#324) +- The module `jsdoc/util/templateHelper` now allows you to specify the CSS class for links that are + generated by the following methods: (#331) + `getAncestorLinks` + `getSignatureReturns` + `getSignatureTypes` + `linkto` ## 3.1.0 (January 2013) ### Major changes -+ You can now use the new `@callback` tag to provide information about a callback function's -signature. To document a callback function, create a standalone JSDoc comment, as shown in the -following example: +- You can now use the new `@callback` tag to provide information about a callback function's + signature. To document a callback function, create a standalone JSDoc comment, as shown in the + following example: - ```javascript - /** - * @class - */ - function MyClass() {} + ```javascript + /** + * @class + */ + function MyClass() {} - /** - * Send a request. - * - * @param {MyClass~responseCb} cb - Called after a response is received. - */ - MyClass.prototype.sendRequest = function(cb) { - // code - }; + /** + * Send a request. + * + * @param {MyClass~responseCb} cb - Called after a response is received. + */ + MyClass.prototype.sendRequest = function(cb) { + // code + }; - /** - * Callback for sending a request. - * - * @callback MyClass~responseCb - * @param {?string} error - Information about the error. - * @param {?string} response - Body of the response. - */ - ``` -+ The inline link tag, `{@link}`, has been improved: - + You can now use a space as the delimiter between the link target and link text. - + In your `conf.json` file, you can now enable the option `templates.cleverLinks` to display + /** + * Callback for sending a request. + * + * @callback MyClass~responseCb + * @param {?string} error - Information about the error. + * @param {?string} response - Body of the response. + */ + ``` + +- The inline link tag, `{@link}`, has been improved: + - You can now use a space as the delimiter between the link target and link text. + - In your `conf.json` file, you can now enable the option `templates.cleverLinks` to display code links in a monospace font and URL links in plain text. You can also enable the option `templates.monospaceLinks` to display all links in a monospace font. **Note**: JSDoc templates must be updated to respect these options. - + You can now use the new inline tags `{@linkplain}`, which forces a plain-text link, and + - You can now use the new inline tags `{@linkplain}`, which forces a plain-text link, and `{@linkcode}`, which forces a monospace link. These tags always override the settings in your `conf.json` file. (#250) -+ JSDoc now provides a `-l/--lenient` option that tells JSDoc to continue running if it encounters a -non-fatal error. (Multiple issues) -+ A template's `publish.js` file should now assign its `publish` function to `exports.publish`, -rather than defining a global `publish` function. The global `publish` function is deprecated and -may not be supported in future versions. JSDoc's built-in templates reflect this change. (#166) -+ The template helper (`templateHelper.js`) exports a variety of new functions for finding -information within a parse tree. These functions were previously contained within the default -template. (#186) -+ Updated the `fs` and `path` modules to make their behavior more consistent with Node.js. In -addition, created extended versions of these modules with additional functionality. (Multiple -commits) -+ Updated or replaced numerous third-party modules. (Multiple commits) -+ Reorganized the JSDoc codebase in preparation for future enhancements. (Multiple commits) -+ JSDoc now embeds a version of Mozilla Rhino that recognizes Node.js packages, including -`package.json` files. (Multiple commits) -+ Node.js' `npm` utility can now install JSDoc from its GitHub repository. **Note**: JSDoc is not -currently compatible with Node.js. However, this change allows JSDoc to be installed as a dependency -of a Node.js project. In this version, global installation with `npm` is not supported. (Multiple -commits) +- JSDoc now provides a `-l/--lenient` option that tells JSDoc to continue running if it encounters a + non-fatal error. (Multiple issues) +- A template's `publish.js` file should now assign its `publish` function to `exports.publish`, + rather than defining a global `publish` function. The global `publish` function is deprecated and + may not be supported in future versions. JSDoc's built-in templates reflect this change. (#166) +- The template helper (`templateHelper.js`) exports a variety of new functions for finding + information within a parse tree. These functions were previously contained within the default + template. (#186) +- Updated the `fs` and `path` modules to make their behavior more consistent with Node.js. In + addition, created extended versions of these modules with additional functionality. (Multiple + commits) +- Updated or replaced numerous third-party modules. (Multiple commits) +- Reorganized the JSDoc codebase in preparation for future enhancements. (Multiple commits) +- JSDoc now embeds a version of Mozilla Rhino that recognizes Node.js packages, including + `package.json` files. (Multiple commits) +- Node.js' `npm` utility can now install JSDoc from its GitHub repository. **Note**: JSDoc is not + currently compatible with Node.js. However, this change allows JSDoc to be installed as a dependency + of a Node.js project. In this version, global installation with `npm` is not supported. (Multiple + commits) ### Enhancements -+ If a `README.md` file is passed to JSDoc, its contents will be included on the `index.html` page -of the generated documentation. (#128) -+ The `@augments` tag can now refer to an undocumented member, such as `window.XMLHTTPRequest`. -(#160) -+ The `@extends` tag can now refer to an undocumented member, such as `window.XMLHttpRequest`. In -addition, you can now use `@host` as a synonym for `@extends`. (#145) -+ The `@lends` tag is now supported in multiline JSDoc comments. (#163) -+ On Windows, `jsdoc.cmd` now provides the same options as the `jsdoc` shell script. (#127) -+ JSDoc now provides `setTimeout()`, `clearTimeout()`, `setInterval()`, and `clearInterval()` -functions. (Multiple commits) -+ JSDoc no longer provides a global `exit()` function. Use `process.exit()` instead. (1228a8f7) -+ JSDoc now includes additional shims for Node.js' built-in modules. **Note**: Many of these shims -implement only the functions that JSDoc uses, and they may not be consistent with Node.js' behavior -in edge cases. (Multiple commits) -+ JSDoc now provides a `-v/--version` option to display information about the current version. -(#303) -+ When running tests, you can now use the `--nocolor` option to disable colored output. On Windows, -colored output is always disabled. (e17601fe, 8bc33541) +- If a `README.md` file is passed to JSDoc, its contents will be included on the `index.html` page + of the generated documentation. (#128) +- The `@augments` tag can now refer to an undocumented member, such as `window.XMLHTTPRequest`. + (#160) +- The `@extends` tag can now refer to an undocumented member, such as `window.XMLHttpRequest`. In + addition, you can now use `@host` as a synonym for `@extends`. (#145) +- The `@lends` tag is now supported in multiline JSDoc comments. (#163) +- On Windows, `jsdoc.cmd` now provides the same options as the `jsdoc` shell script. (#127) +- JSDoc now provides `setTimeout()`, `clearTimeout()`, `setInterval()`, and `clearInterval()` + functions. (Multiple commits) +- JSDoc no longer provides a global `exit()` function. Use `process.exit()` instead. (1228a8f7) +- JSDoc now includes additional shims for Node.js' built-in modules. **Note**: Many of these shims + implement only the functions that JSDoc uses, and they may not be consistent with Node.js' behavior + in edge cases. (Multiple commits) +- JSDoc now provides a `-v/--version` option to display information about the current version. + (#303) +- When running tests, you can now use the `--nocolor` option to disable colored output. On Windows, + colored output is always disabled. (e17601fe, 8bc33541) ### Bug fixes -+ When using the `@event` tag to define an event within a class or namespace, the event's longname -is now set correctly regardless of tag order. (#280) -+ The `@property` tag no longer results in malformed parse trees. (20f87094) -+ The `jsdoc` and `jsdoc.cmd` scripts now work correctly with paths that include spaces. (#127, -#130) -+ The `jsdoc` script now works correctly on Cygwin and MinGW, and with the `dash` shell. (#182, -#184, #187) -+ The `-d/--destination` option is no longer treated as a path relative to the JSDoc directory. -Instead, it can contain an absolute path, or a path relative to the current working directory. -(f5e3f0f3) -+ JSDoc now provides default options for the values in `conf.json`. (#129) -+ If the `conf.json` file does not exist, JSDoc no longer tries to create it, which prevents errors -if the current user does not have write access to the JSDoc directory. (d2d05fcb) -+ Doclets for getters and setters are now parsed appropriately. (#150) -+ Only the first asterisk is removed from each line of a JSDoc comment. (#172) -+ If a child member overrides an ancestor member, the ancestor member is no longer documented. -(#158) -+ If a member of a namespace has the same name as a namespace, the member is now documented -correctly. (#214) -+ The parse tree now uses a single set of properties to track both JSDoc-style type information and -Closure Compiler-style type information. (#118) -+ If a type has a leading `!`, indicating that it is non-nullable, the leading `!` is now removed -from the type name. (#226) -+ When Markdown formatting is enabled, underscores in inline `{@link}` tags are no longer treated as -Markdown formatting characters. (#259) -+ Markdown links now work correctly when a JavaScript reserved word, such as `constructor`, is used -as the link text. (#249) -+ Markdown files for tutorials are now parsed based on the settings in `conf.json`, rather than -using the "evilstreak" Markdown parser in all cases. (#220) -+ If a folder contains both tutorial source files and `.js` files, JSDoc no longer attempts to parse -the `.js` files as JSON files. (#222) -+ The "evilstreak" Markdown parser now works correctly with files that use Windows-style line -endings. (#223) -+ JSDoc no longer fails unit tests when the `conf.json` file is not present. (#206) -+ On Windows, JSDoc now passes all unit tests. (Multiple commits) +- When using the `@event` tag to define an event within a class or namespace, the event's longname + is now set correctly regardless of tag order. (#280) +- The `@property` tag no longer results in malformed parse trees. (20f87094) +- The `jsdoc` and `jsdoc.cmd` scripts now work correctly with paths that include spaces. (#127, + #130) +- The `jsdoc` script now works correctly on Cygwin and MinGW, and with the `dash` shell. (#182, + #184, #187) +- The `-d/--destination` option is no longer treated as a path relative to the JSDoc directory. + Instead, it can contain an absolute path, or a path relative to the current working directory. + (f5e3f0f3) +- JSDoc now provides default options for the values in `conf.json`. (#129) +- If the `conf.json` file does not exist, JSDoc no longer tries to create it, which prevents errors + if the current user does not have write access to the JSDoc directory. (d2d05fcb) +- Doclets for getters and setters are now parsed appropriately. (#150) +- Only the first asterisk is removed from each line of a JSDoc comment. (#172) +- If a child member overrides an ancestor member, the ancestor member is no longer documented. + (#158) +- If a member of a namespace has the same name as a namespace, the member is now documented + correctly. (#214) +- The parse tree now uses a single set of properties to track both JSDoc-style type information and + Closure Compiler-style type information. (#118) +- If a type has a leading `!`, indicating that it is non-nullable, the leading `!` is now removed + from the type name. (#226) +- When Markdown formatting is enabled, underscores in inline `{@link}` tags are no longer treated as + Markdown formatting characters. (#259) +- Markdown links now work correctly when a JavaScript reserved word, such as `constructor`, is used + as the link text. (#249) +- Markdown files for tutorials are now parsed based on the settings in `conf.json`, rather than + using the "evilstreak" Markdown parser in all cases. (#220) +- If a folder contains both tutorial source files and `.js` files, JSDoc no longer attempts to parse + the `.js` files as JSON files. (#222) +- The "evilstreak" Markdown parser now works correctly with files that use Windows-style line + endings. (#223) +- JSDoc no longer fails unit tests when the `conf.json` file is not present. (#206) +- On Windows, JSDoc now passes all unit tests. (Multiple commits) ### Plugins -+ The new `partial` plugin adds support for a `@partial` tag, which links to an external file that -contains JSDoc comments. (#156) -+ The new `commentsOnly` plugin removes everything in a file except JSDoc-style comments. You can -use this plugin to document source files that are not valid JavaScript, including source files for -other languages. (#304) -+ The new `eventDumper` plugin logs information about parser events to the console. (#242) -+ The new `verbose` plugin logs the name of each input file to the console. (#157) +- The new `partial` plugin adds support for a `@partial` tag, which links to an external file that + contains JSDoc comments. (#156) +- The new `commentsOnly` plugin removes everything in a file except JSDoc-style comments. You can + use this plugin to document source files that are not valid JavaScript, including source files for + other languages. (#304) +- The new `eventDumper` plugin logs information about parser events to the console. (#242) +- The new `verbose` plugin logs the name of each input file to the console. (#157) ### Template enhancements #### Default template -+ The template output now includes pretty-printed versions of source files. This feature is enabled -by default. To disable this feature, add the property `templates.default.outputSourceFiles: false` -to your `conf.json` file. (#208) -+ You can now use the template if it is placed outside of the JSDoc directory. (#198) -+ The template no longer throws an error when a parameter does not have a name. (#175) -+ The navigation bar now includes an "Events" section if any events are documented. (#280) -+ Pages no longer include a "Classes" header when no classes are documented. (eb0186b9) -+ Member details now include "Inherited From" section when a member is inherited from another -member. (#154) -+ If an `@author` tag contains text in the format "Jane Doe ", the value is now -converted to an HTML `mailto:` link. (#326) -+ Headings for functions now include the function's signature. (#253) -+ Type information is now displayed for events. (#192) -+ Functions now link to their return type when appropriate. (#192) -+ Type definitions that contain functions are now displayed correctly. (#292) -+ Tutorial output is now generated correctly. (#188) -+ Output files now use Google Code Prettify with the Tomorrow theme as a syntax highlighter. (#193) -+ The `index.html` output file is no longer overwritten if a namespace called `index` has been -documented. (#244) -+ The current JSDoc version number is now displayed in the footer. (#321) +- The template output now includes pretty-printed versions of source files. This feature is enabled + by default. To disable this feature, add the property `templates.default.outputSourceFiles: false` + to your `conf.json` file. (#208) +- You can now use the template if it is placed outside of the JSDoc directory. (#198) +- The template no longer throws an error when a parameter does not have a name. (#175) +- The navigation bar now includes an "Events" section if any events are documented. (#280) +- Pages no longer include a "Classes" header when no classes are documented. (eb0186b9) +- Member details now include "Inherited From" section when a member is inherited from another + member. (#154) +- If an `@author` tag contains text in the format "Jane Doe ", the value is now + converted to an HTML `mailto:` link. (#326) +- Headings for functions now include the function's signature. (#253) +- Type information is now displayed for events. (#192) +- Functions now link to their return type when appropriate. (#192) +- Type definitions that contain functions are now displayed correctly. (#292) +- Tutorial output is now generated correctly. (#188) +- Output files now use Google Code Prettify with the Tomorrow theme as a syntax highlighter. (#193) +- The `index.html` output file is no longer overwritten if a namespace called `index` has been + documented. (#244) +- The current JSDoc version number is now displayed in the footer. (#321) #### Haruki template -+ Members are now contained in arrays rather than objects, allowing overloaded members to be -documented. (#153) -+ A clearer error message is now provided when the output destination is not specified correctly. -(#174) - +- Members are now contained in arrays rather than objects, allowing overloaded members to be + documented. (#153) +- A clearer error message is now provided when the output destination is not specified correctly. + (#174) ## 3.0.1 (June 2012) ### Enhancements -+ The `conf.json` file may now contain `source.include` and `source.exclude` properties. (#56) - + `source.include` specifies files or directories that JSDoc should _always_ check for +- The `conf.json` file may now contain `source.include` and `source.exclude` properties. (#56) + - `source.include` specifies files or directories that JSDoc should _always_ check for documentation. - + `source.exclude` specifies files or directories that JSDoc should _never_ check for + - `source.exclude` specifies files or directories that JSDoc should _never_ check for documentation. These settings take precedence over the `source.includePattern` and `source.excludePattern` properties, which contain regular expressions that JSDoc uses to search for source files. -+ The `-t/--template` option may now specify the absolute path to a template. (#122) +- The `-t/--template` option may now specify the absolute path to a template. (#122) ### Bug fixes -+ JSDoc no longer throws exceptions when a symbol has a special name, such as `hasOwnProperty`. -(1ef37251) -+ The `@alias` tag now works correctly when documenting inner classes as globals. (810dd7f7) +- JSDoc no longer throws exceptions when a symbol has a special name, such as `hasOwnProperty`. + (1ef37251) +- The `@alias` tag now works correctly when documenting inner classes as globals. (810dd7f7) ### Template improvements -+ The default template now sorts classes by name correctly when the classes come from several -modules. (4ce17195) -+ The Haruki template now correctly supports `@example`, `@members`, and `@returns` tags. (6580e176, -59655252, 31c8554d) - +- The default template now sorts classes by name correctly when the classes come from several + modules. (4ce17195) +- The Haruki template now correctly supports `@example`, `@members`, and `@returns` tags. (6580e176, + 59655252, 31c8554d) ## 3.0.0 (May 2012) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index d7da7628..753f516e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -11,20 +11,20 @@ of experience, nationality, personal appearance, race, religion, or sexual ident Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit -permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit + permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 998c7ade..8783984c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,69 +1,68 @@ -Pull Requests -------------- +## Pull Requests If you're thinking about making some changes, maybe fixing a bug, or adding a -snazzy new feature, first, thank you. Contributions are very welcome. Things -need to be manageable for the maintainers, however. So below you'll find **The -fastest way to get your pull request merged in.** Some things, particularly how +snazzy new feature, first, thank you. Contributions are very welcome. Things +need to be manageable for the maintainers, however. So below you'll find **The +fastest way to get your pull request merged in.** Some things, particularly how you set up your branches and work with git, are just suggestions, but pretty good ones. -1. **Create a remote to track the base jsdoc/jsdoc repository** - This is just a convenience to make it easier to update your `````` - (more on that shortly). You would execute something like: +1. **Create a remote to track the base jsdoc/jsdoc repository** + This is just a convenience to make it easier to update your `` + (more on that shortly). You would execute something like: - git remote add base git://github.com/jsdoc/jsdoc.git + git remote add base git://github.com/jsdoc/jsdoc.git - Here 'base' is the name of the remote. Feel free to use whatever you want. + Here 'base' is the name of the remote. Feel free to use whatever you want. -2. **Set up a tracking branch for the base repository** - We're gonna call this your ``````. You will only ever update - this branch by pulling from the 'base' remote. (as opposed to 'origin') +2. **Set up a tracking branch for the base repository** + We're gonna call this your ``. You will only ever update + this branch by pulling from the 'base' remote. (as opposed to 'origin') - git branch --track pullpost base/master - git checkout pullpost + git branch --track pullpost base/master + git checkout pullpost - Here 'pullpost' is the name of the branch. Fell free to use whatever you want. + Here 'pullpost' is the name of the branch. Fell free to use whatever you want. -3. **Create your change branch** - Once you are in ``````, make sure it's up to date, then create - a branch for your changes off of that one. +3. **Create your change branch** + Once you are in ``, make sure it's up to date, then create + a branch for your changes off of that one. - git branch fix-for-issue-395 - git checkout fix-for-issue-395 + git branch fix-for-issue-395 + git checkout fix-for-issue-395 - Here 'fix-for-issue-395' is the name of the branch. Feel free to use whatever - you want. We'll call this the ``````. This is the branch that - you will eventually issue your pull request from. + Here 'fix-for-issue-395' is the name of the branch. Feel free to use whatever + you want. We'll call this the ``. This is the branch that + you will eventually issue your pull request from. - The purpose of these first three steps is to make sure that your merge request - has a nice clean diff that only involves the changes related to your fix/feature. + The purpose of these first three steps is to make sure that your merge request + has a nice clean diff that only involves the changes related to your fix/feature. -4. **Make your changes** - On your `````` make any changes relevant to your fix/feature. Don't - group fixes for multiple unrelated issues or multiple unrelated features together. - Create a separate branch for each unrelated changeset. For instance, if you're - fixing a bug in the parser and adding some new UI to the default template, those - should be separate branches and merge requests. +4. **Make your changes** + On your `` make any changes relevant to your fix/feature. Don't + group fixes for multiple unrelated issues or multiple unrelated features together. + Create a separate branch for each unrelated changeset. For instance, if you're + fixing a bug in the parser and adding some new UI to the default template, those + should be separate branches and merge requests. -5. **Add tests** - Add tests for your change. If you are submitting a bugfix, include a test that - verifies the existence of the bug along with your fix. If you are submitting - a new feature, include tests that verify proper feature function, if applicable. - See the readme in the 'test' directory for more information +5. **Add tests** + Add tests for your change. If you are submitting a bugfix, include a test that + verifies the existence of the bug along with your fix. If you are submitting + a new feature, include tests that verify proper feature function, if applicable. + See the readme in the 'test' directory for more information -6. **Commit and publish** - Commit your changes and publish your branch (or push it if it's already published) +6. **Commit and publish** + Commit your changes and publish your branch (or push it if it's already published) -7. **Issue your pull request** - On github.com, switch to your `````` and click the 'Pull Request' - button. Enter some meaningful information about the pull request. If it's a bugfix, - that doesn't already have an issue associated with it, provide some info on what - situations that bug occurs in and a sense of it's severity. If it does already have - an issue, make sure the include the hash and issue number (e.g. '#100') so github - links it. +7. **Issue your pull request** + On github.com, switch to your `` and click the 'Pull Request' + button. Enter some meaningful information about the pull request. If it's a bugfix, + that doesn't already have an issue associated with it, provide some info on what + situations that bug occurs in and a sense of it's severity. If it does already have + an issue, make sure the include the hash and issue number (e.g. '#100') so github + links it. - If it's a feature, provide some context about the motivations behind the feature, - why it's important/useful/cool/necessary and what it does/how it works. Don't - worry about being too verbose. Folks will be much more amenable to reading through - your code if they know what its supposed to be about. + If it's a feature, provide some context about the motivations behind the feature, + why it's important/useful/cool/necessary and what it does/how it works. Don't + worry about being too verbose. Folks will be much more amenable to reading through + your code if they know what its supposed to be about. diff --git a/README.md b/README.md index 0a591587..67aa38b3 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,7 @@ An API documentation generator for JavaScript. Want to contribute to JSDoc? Please read [`CONTRIBUTING.md`](CONTRIBUTING.md). -Installation and Usage ----------------------- +## Installation and Usage JSDoc supports stable versions of Node.js 8.15.0 and later. You can install JSDoc globally or in your project's `node_modules` folder. @@ -51,41 +50,41 @@ and customize your documentation. Here are a few of them: ### Templates -+ [jaguarjs-jsdoc](https://github.com/davidshimjs/jaguarjs-jsdoc) -+ [DocStrap](https://github.com/docstrap/docstrap) -([example](https://docstrap.github.io/docstrap)) -+ [jsdoc3Template](https://github.com/DBCDK/jsdoc3Template) +- [jaguarjs-jsdoc](https://github.com/davidshimjs/jaguarjs-jsdoc) +- [DocStrap](https://github.com/docstrap/docstrap) + ([example](https://docstrap.github.io/docstrap)) +- [jsdoc3Template](https://github.com/DBCDK/jsdoc3Template) ([example](https://github.com/danyg/jsdoc3Template/wiki#wiki-screenshots)) -+ [minami](https://github.com/Nijikokun/minami) -+ [docdash](https://github.com/clenemt/docdash) -([example](http://clenemt.github.io/docdash/)) -+ [tui-jsdoc-template](https://github.com/nhnent/tui.jsdoc-template) -([example](https://nhnent.github.io/tui.jsdoc-template/latest/)) -+ [better-docs](https://github.com/SoftwareBrothers/better-docs) -([example](https://softwarebrothers.github.io/admin-bro-dev/index.html)) +- [minami](https://github.com/Nijikokun/minami) +- [docdash](https://github.com/clenemt/docdash) + ([example](http://clenemt.github.io/docdash/)) +- [tui-jsdoc-template](https://github.com/nhnent/tui.jsdoc-template) + ([example](https://nhnent.github.io/tui.jsdoc-template/latest/)) +- [better-docs](https://github.com/SoftwareBrothers/better-docs) + ([example](https://softwarebrothers.github.io/admin-bro-dev/index.html)) ### Build tools -+ [JSDoc Grunt plugin](https://github.com/krampstudio/grunt-jsdoc) -+ [JSDoc Gulp plugin](https://github.com/mlucool/gulp-jsdoc3) -+ [JSDoc GitHub Action](https://github.com/andstor/jsdoc-action) +- [JSDoc Grunt plugin](https://github.com/krampstudio/grunt-jsdoc) +- [JSDoc Gulp plugin](https://github.com/mlucool/gulp-jsdoc3) +- [JSDoc GitHub Action](https://github.com/andstor/jsdoc-action) ### Other tools -+ [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown) -+ [Integrating GitBook with -JSDoc](https://medium.com/@kevinast/integrate-gitbook-jsdoc-974be8df6fb3) +- [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown) +- [Integrating GitBook with + JSDoc](https://medium.com/@kevinast/integrate-gitbook-jsdoc-974be8df6fb3) ## For more information -+ Documentation is available at [jsdoc.app](https://jsdoc.app/). -+ Contribute to the docs at -[jsdoc/jsdoc.github.io](https://github.com/jsdoc/jsdoc.github.io). -+ [Join JSDoc's Slack channel](https://jsdoc-slack.appspot.com/). -+ Ask for help on the -[JSDoc Users mailing list](http://groups.google.com/group/jsdoc-users). -+ Post questions tagged `jsdoc` to -[Stack Overflow](http://stackoverflow.com/questions/tagged/jsdoc). +- Documentation is available at [jsdoc.app](https://jsdoc.app/). +- Contribute to the docs at + [jsdoc/jsdoc.github.io](https://github.com/jsdoc/jsdoc.github.io). +- [Join JSDoc's Slack channel](https://jsdoc-slack.appspot.com/). +- Ask for help on the + [JSDoc Users mailing list](http://groups.google.com/group/jsdoc-users). +- Post questions tagged `jsdoc` to + [Stack Overflow](http://stackoverflow.com/questions/tagged/jsdoc). ## License diff --git a/gulpfile.js b/gulpfile.js index 36b589c8..d616d6da 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,50 +2,53 @@ const eslint = require('gulp-eslint'); const { exec } = require('child_process'); const gulp = require('gulp'); const path = require('path'); +const prettier = require('gulp-prettier'); function execCb(cb, err, stdout, stderr) { - console.log(stdout); - console.error(stderr); - cb(err); + console.log(stdout); + console.error(stderr); + cb(err); } const options = { - coveragePaths: [ - '*.js', - 'packages/**/*.js', - '!packages/**/test/*.js', - '!packages/**/test/**/*.js', - '!packages/**/static/*.js' - ], - lintPaths: [ - '*.js', - 'packages/**/*.js', - '!packages/**/static/*.js' - ], - nodeBin: path.resolve(__dirname, './packages/jsdoc/jsdoc.js'), - nodePath: process.execPath + coveragePaths: [ + '*.js', + 'packages/**/*.js', + '!packages/**/test/*.js', + '!packages/**/test/**/*.js', + '!packages/**/static/*.js', + ], + lintPaths: ['*.js', 'packages/**/*.js', '!packages/**/static/*.js'], + nodeBin: path.resolve(__dirname, './packages/jsdoc/jsdoc.js'), + nodePath: process.execPath, }; function coverage(cb) { - const cmd = `./node_modules/.bin/nyc --reporter=html ${options.nodeBin} -T`; + const cmd = `./node_modules/.bin/nyc --reporter=html ${options.nodeBin} -T`; - return exec(cmd, execCb.bind(null, cb)); + return exec(cmd, execCb.bind(null, cb)); +} + +function format() { + return gulp.src(options.lintPaths).pipe(prettier()); } function lint() { - return gulp.src(options.lintPaths) - .pipe(eslint()) - .pipe(eslint.formatEach()) - .pipe(eslint.failAfterError()); + return gulp + .src(options.lintPaths) + .pipe(eslint()) + .pipe(eslint.formatEach()) + .pipe(eslint.failAfterError()); } function test(cb) { - const cmd = `${options.nodePath} "${options.nodeBin}" -T`; + const cmd = `${options.nodePath} "${options.nodeBin}" -T`; - return exec(cmd, execCb.bind(null, cb)); + return exec(cmd, execCb.bind(null, cb)); } exports.coverage = coverage; exports.default = gulp.series(lint, test); +exports.format = format; exports.lint = lint; exports.test = test; diff --git a/lerna.json b/lerna.json index a2bb50ba..7926728a 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,4 @@ { - "packages": [ - "packages/*" - ], + "packages": ["packages/*"], "version": "independent" } diff --git a/package-lock.json b/package-lock.json index 13bc5d57..5400171c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,16082 @@ { "name": "jsdoc", + "lockfileVersion": 2, "requires": true, - "lockfileVersion": 1, + "packages": { + "": { + "name": "jsdoc", + "license": "Apache-2.0", + "devDependencies": { + "@jsdoc/eslint-config": "^1.0.8", + "@jsdoc/test-matchers": "^0.1.6", + "ajv": "^8.6.3", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^4.0.0", + "gulp": "^4.0.2", + "gulp-eslint": "^6.0.0", + "gulp-prettier": "^4.0.0", + "jasmine": "^3.9.0", + "jasmine-console-reporter": "^3.1.0", + "klaw-sync": "^6.0.0", + "lerna": "^4.0.0", + "mock-fs": "^5.1.0", + "nyc": "^15.1.0", + "prettier": "^2.4.1" + }, + "engines": { + "node": ">=v14.17.6" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.8.3" + } + }, + "node_modules/@babel/core": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.2.tgz", + "integrity": "sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.2", + "@babel/helper-module-transforms": "^7.10.1", + "@babel/helpers": "^7.10.1", + "@babel/parser": "^7.10.2", + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.2", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.1" + } + }, + "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "node_modules/@babel/core/node_modules/@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.2.tgz", + "integrity": "sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.2", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz", + "integrity": "sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz", + "integrity": "sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz", + "integrity": "sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz", + "integrity": "sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz", + "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.1", + "@babel/helper-replace-supers": "^7.10.1", + "@babel/helper-simple-access": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz", + "integrity": "sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz", + "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.10.1", + "@babel/helper-optimise-call-expression": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz", + "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz", + "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", + "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", + "dev": true + }, + "node_modules/@babel/helpers": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz", + "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.1", + "@babel/traverse": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.2.tgz", + "integrity": "sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", + "integrity": "sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.1" + } + }, + "node_modules/@babel/template/node_modules/@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "node_modules/@babel/template/node_modules/@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.1.tgz", + "integrity": "sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.1", + "@babel/generator": "^7.10.1", + "@babel/helper-function-name": "^7.10.1", + "@babel/helper-split-export-declaration": "^7.10.1", + "@babel/parser": "^7.10.1", + "@babel/types": "^7.10.1", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.1" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "node_modules/@babel/traverse/node_modules/@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.10.2.tgz", + "integrity": "sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.1", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/types/node_modules/@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", + "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jsdoc/eslint-config": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@jsdoc/eslint-config/-/eslint-config-1.0.8.tgz", + "integrity": "sha512-QKqfU25dltYG7Euz14ND2jPWiFXCYARqotwFdXDDopyRSduUkvKVFLMZvvPk4tBj5gpTlufKMmZ+QHUMDtYAkg==", + "dev": true, + "peerDependencies": { + "eslint": ">= 6.4.0" + } + }, + "node_modules/@jsdoc/test-matchers": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@jsdoc/test-matchers/-/test-matchers-0.1.6.tgz", + "integrity": "sha512-+WWW/iHLa8zAs7vs6vNY5Wy5xoKWCvPrRZtgs5nQhMg767YMtXdsOcHZdXBAqzBiFhhp72Ia7Jhs3Yg66lPq6g==", + "dev": true, + "dependencies": { + "add-matchers": "^0.6.2", + "jasmine-expect": "^5.0.0" + }, + "engines": { + "node": ">=10.18.0" + } + }, + "node_modules/@lerna/add": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/add/-/add-4.0.0.tgz", + "integrity": "sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng==", + "dev": true, + "dependencies": { + "@lerna/bootstrap": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "npm-package-arg": "^8.1.0", + "p-map": "^4.0.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/add/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/bootstrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-4.0.0.tgz", + "integrity": "sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/has-npm-version": "4.0.0", + "@lerna/npm-install": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/rimraf-dir": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/symlink-binary": "4.0.0", + "@lerna/symlink-dependencies": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "get-port": "^5.1.1", + "multimatch": "^5.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1", + "read-package-tree": "^5.3.1", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/bootstrap/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/changed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-4.0.0.tgz", + "integrity": "sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ==", + "dev": true, + "dependencies": { + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/listable": "4.0.0", + "@lerna/output": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/check-working-tree": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz", + "integrity": "sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q==", + "dev": true, + "dependencies": { + "@lerna/collect-uncommitted": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "@lerna/validation-error": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/child-process": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-4.0.0.tgz", + "integrity": "sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "execa": "^5.0.0", + "strong-log-transformer": "^2.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/child-process/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@lerna/child-process/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@lerna/child-process/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@lerna/child-process/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@lerna/child-process/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/child-process/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/clean": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-4.0.0.tgz", + "integrity": "sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/rimraf-dir": "4.0.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/cli": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/cli/-/cli-4.0.0.tgz", + "integrity": "sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA==", + "dev": true, + "dependencies": { + "@lerna/global-options": "4.0.0", + "dedent": "^0.7.0", + "npmlog": "^4.1.2", + "yargs": "^16.2.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/cli/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@lerna/cli/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@lerna/cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@lerna/cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@lerna/cli/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/@lerna/cli/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/@lerna/cli/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/cli/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/cli/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@lerna/cli/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/cli/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/cli/node_modules/yargs-parser": { + "version": "20.2.6", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.6.tgz", + "integrity": "sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/collect-uncommitted": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz", + "integrity": "sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "chalk": "^4.1.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/collect-uncommitted/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@lerna/collect-uncommitted/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@lerna/collect-uncommitted/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@lerna/collect-uncommitted/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@lerna/collect-uncommitted/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/collect-uncommitted/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/collect-updates": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-4.0.0.tgz", + "integrity": "sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/command": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/command/-/command-4.0.0.tgz", + "integrity": "sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/project": "4.0.0", + "@lerna/validation-error": "4.0.0", + "@lerna/write-log-file": "4.0.0", + "clone-deep": "^4.0.1", + "dedent": "^0.7.0", + "execa": "^5.0.0", + "is-ci": "^2.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/conventional-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz", + "integrity": "sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw==", + "dev": true, + "dependencies": { + "@lerna/validation-error": "4.0.0", + "conventional-changelog-angular": "^5.0.12", + "conventional-changelog-core": "^4.2.2", + "conventional-recommended-bump": "^6.1.0", + "fs-extra": "^9.1.0", + "get-stream": "^6.0.0", + "lodash.template": "^4.5.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "pify": "^5.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/conventional-commits/node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/conventional-commits/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/create": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-4.0.0.tgz", + "integrity": "sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "init-package-json": "^2.0.2", + "npm-package-arg": "^8.1.0", + "p-reduce": "^2.1.0", + "pacote": "^11.2.6", + "pify": "^5.0.0", + "semver": "^7.3.4", + "slash": "^3.0.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0", + "whatwg-url": "^8.4.0", + "yargs-parser": "20.2.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/create-symlink": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-4.0.0.tgz", + "integrity": "sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig==", + "dev": true, + "dependencies": { + "cmd-shim": "^4.1.0", + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/create/node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/create/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/create/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/describe-ref": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-4.0.0.tgz", + "integrity": "sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-4.0.0.tgz", + "integrity": "sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/validation-error": "4.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/exec": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-4.0.0.tgz", + "integrity": "sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/profiler": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "p-map": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/filter-options": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-4.0.0.tgz", + "integrity": "sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw==", + "dev": true, + "dependencies": { + "@lerna/collect-updates": "4.0.0", + "@lerna/filter-packages": "4.0.0", + "dedent": "^0.7.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/filter-packages": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-4.0.0.tgz", + "integrity": "sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA==", + "dev": true, + "dependencies": { + "@lerna/validation-error": "4.0.0", + "multimatch": "^5.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/get-npm-exec-opts": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz", + "integrity": "sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/get-packed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-4.0.0.tgz", + "integrity": "sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w==", + "dev": true, + "dependencies": { + "fs-extra": "^9.1.0", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/get-packed/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/get-packed/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@lerna/get-packed/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/get-packed/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@lerna/get-packed/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/get-packed/node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/github-client": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/github-client/-/github-client-4.0.0.tgz", + "integrity": "sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@octokit/plugin-enterprise-rest": "^6.0.1", + "@octokit/rest": "^18.1.0", + "git-url-parse": "^11.4.4", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/gitlab-client": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz", + "integrity": "sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.1", + "npmlog": "^4.1.2", + "whatwg-url": "^8.4.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/global-options": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-4.0.0.tgz", + "integrity": "sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ==", + "dev": true, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/has-npm-version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz", + "integrity": "sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/has-npm-version/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/import/-/import-4.0.0.tgz", + "integrity": "sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/validation-error": "4.0.0", + "dedent": "^0.7.0", + "fs-extra": "^9.1.0", + "p-map-series": "^2.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/info": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/info/-/info-4.0.0.tgz", + "integrity": "sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/output": "4.0.0", + "envinfo": "^7.7.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/init": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/init/-/init-4.0.0.tgz", + "integrity": "sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/command": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/link/-/link-4.0.0.tgz", + "integrity": "sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/package-graph": "4.0.0", + "@lerna/symlink-dependencies": "4.0.0", + "p-map": "^4.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/list": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/list/-/list-4.0.0.tgz", + "integrity": "sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/listable": "4.0.0", + "@lerna/output": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/listable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-4.0.0.tgz", + "integrity": "sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ==", + "dev": true, + "dependencies": { + "@lerna/query-graph": "4.0.0", + "chalk": "^4.1.0", + "columnify": "^1.5.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/listable/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@lerna/listable/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@lerna/listable/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@lerna/listable/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@lerna/listable/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/listable/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/log-packed": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-4.0.0.tgz", + "integrity": "sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ==", + "dev": true, + "dependencies": { + "byte-size": "^7.0.0", + "columnify": "^1.5.4", + "has-unicode": "^2.0.1", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-conf": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-4.0.0.tgz", + "integrity": "sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.12", + "pify": "^5.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-conf/node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/npm-dist-tag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz", + "integrity": "sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw==", + "dev": true, + "dependencies": { + "@lerna/otplease": "4.0.0", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-install": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-4.0.0.tgz", + "integrity": "sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/get-npm-exec-opts": "4.0.0", + "fs-extra": "^9.1.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "signal-exit": "^3.0.3", + "write-pkg": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-install/node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/@lerna/npm-publish": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-4.0.0.tgz", + "integrity": "sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w==", + "dev": true, + "dependencies": { + "@lerna/otplease": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "fs-extra": "^9.1.0", + "libnpmpublish": "^4.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "pify": "^5.0.0", + "read-package-json": "^3.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/npm-publish/node_modules/hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/npm-publish/node_modules/normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/npm-publish/node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/npm-publish/node_modules/read-package-json": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-3.0.1.tgz", + "integrity": "sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/npm-publish/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/npm-run-script": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz", + "integrity": "sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "@lerna/get-npm-exec-opts": "4.0.0", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/otplease": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/otplease/-/otplease-4.0.0.tgz", + "integrity": "sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw==", + "dev": true, + "dependencies": { + "@lerna/prompt": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/output": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/output/-/output-4.0.0.tgz", + "integrity": "sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/pack-directory": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-4.0.0.tgz", + "integrity": "sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ==", + "dev": true, + "dependencies": { + "@lerna/get-packed": "4.0.0", + "@lerna/package": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "npm-packlist": "^2.1.4", + "npmlog": "^4.1.2", + "tar": "^6.1.0", + "temp-write": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/pack-directory/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/pack-directory/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@lerna/pack-directory/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/pack-directory/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@lerna/pack-directory/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/pack-directory/node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/package": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/package/-/package-4.0.0.tgz", + "integrity": "sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q==", + "dev": true, + "dependencies": { + "load-json-file": "^6.2.0", + "npm-package-arg": "^8.1.0", + "write-pkg": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/package-graph": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-4.0.0.tgz", + "integrity": "sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw==", + "dev": true, + "dependencies": { + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/validation-error": "4.0.0", + "npm-package-arg": "^8.1.0", + "npmlog": "^4.1.2", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/package-graph/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/package/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/@lerna/package/node_modules/load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/package/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/prerelease-id-from-version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz", + "integrity": "sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg==", + "dev": true, + "dependencies": { + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/prerelease-id-from-version/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/profiler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/profiler/-/profiler-4.0.0.tgz", + "integrity": "sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q==", + "dev": true, + "dependencies": { + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2", + "upath": "^2.0.1" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/profiler/node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/@lerna/project": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/project/-/project-4.0.0.tgz", + "integrity": "sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg==", + "dev": true, + "dependencies": { + "@lerna/package": "4.0.0", + "@lerna/validation-error": "4.0.0", + "cosmiconfig": "^7.0.0", + "dedent": "^0.7.0", + "dot-prop": "^6.0.1", + "glob-parent": "^5.1.1", + "globby": "^11.0.2", + "load-json-file": "^6.2.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "resolve-from": "^5.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/project/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@lerna/project/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/@lerna/project/node_modules/load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/project/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/project/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/prompt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/prompt/-/prompt-4.0.0.tgz", + "integrity": "sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ==", + "dev": true, + "dependencies": { + "inquirer": "^7.3.3", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/publish": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-4.0.0.tgz", + "integrity": "sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg==", + "dev": true, + "dependencies": { + "@lerna/check-working-tree": "4.0.0", + "@lerna/child-process": "4.0.0", + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/describe-ref": "4.0.0", + "@lerna/log-packed": "4.0.0", + "@lerna/npm-conf": "4.0.0", + "@lerna/npm-dist-tag": "4.0.0", + "@lerna/npm-publish": "4.0.0", + "@lerna/otplease": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/pack-directory": "4.0.0", + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/pulse-till-done": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "@lerna/version": "4.0.0", + "fs-extra": "^9.1.0", + "libnpmaccess": "^4.0.1", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/publish/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/pulse-till-done": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz", + "integrity": "sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/query-graph": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-4.0.0.tgz", + "integrity": "sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg==", + "dev": true, + "dependencies": { + "@lerna/package-graph": "4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/resolve-symlink": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz", + "integrity": "sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA==", + "dev": true, + "dependencies": { + "fs-extra": "^9.1.0", + "npmlog": "^4.1.2", + "read-cmd-shim": "^2.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/rimraf-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz", + "integrity": "sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg==", + "dev": true, + "dependencies": { + "@lerna/child-process": "4.0.0", + "npmlog": "^4.1.2", + "path-exists": "^4.0.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/rimraf-dir/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/rimraf-dir/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@lerna/run": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run/-/run-4.0.0.tgz", + "integrity": "sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ==", + "dev": true, + "dependencies": { + "@lerna/command": "4.0.0", + "@lerna/filter-options": "4.0.0", + "@lerna/npm-run-script": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/profiler": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/timer": "4.0.0", + "@lerna/validation-error": "4.0.0", + "p-map": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/run-lifecycle": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz", + "integrity": "sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ==", + "dev": true, + "dependencies": { + "@lerna/npm-conf": "4.0.0", + "npm-lifecycle": "^3.1.5", + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/run-topologically": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-4.0.0.tgz", + "integrity": "sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA==", + "dev": true, + "dependencies": { + "@lerna/query-graph": "4.0.0", + "p-queue": "^6.6.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/symlink-binary": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz", + "integrity": "sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA==", + "dev": true, + "dependencies": { + "@lerna/create-symlink": "4.0.0", + "@lerna/package": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/symlink-dependencies": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz", + "integrity": "sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw==", + "dev": true, + "dependencies": { + "@lerna/create-symlink": "4.0.0", + "@lerna/resolve-symlink": "4.0.0", + "@lerna/symlink-binary": "4.0.0", + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "p-map-series": "^2.1.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/timer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/timer/-/timer-4.0.0.tgz", + "integrity": "sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg==", + "dev": true, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/validation-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-4.0.0.tgz", + "integrity": "sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/version": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/version/-/version-4.0.0.tgz", + "integrity": "sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA==", + "dev": true, + "dependencies": { + "@lerna/check-working-tree": "4.0.0", + "@lerna/child-process": "4.0.0", + "@lerna/collect-updates": "4.0.0", + "@lerna/command": "4.0.0", + "@lerna/conventional-commits": "4.0.0", + "@lerna/github-client": "4.0.0", + "@lerna/gitlab-client": "4.0.0", + "@lerna/output": "4.0.0", + "@lerna/prerelease-id-from-version": "4.0.0", + "@lerna/prompt": "4.0.0", + "@lerna/run-lifecycle": "4.0.0", + "@lerna/run-topologically": "4.0.0", + "@lerna/validation-error": "4.0.0", + "chalk": "^4.1.0", + "dedent": "^0.7.0", + "load-json-file": "^6.2.0", + "minimatch": "^3.0.4", + "npmlog": "^4.1.2", + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "p-reduce": "^2.1.0", + "p-waterfall": "^2.1.1", + "semver": "^7.3.4", + "slash": "^3.0.0", + "temp-write": "^4.0.0", + "write-json-file": "^4.3.0" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/version/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@lerna/version/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@lerna/version/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@lerna/version/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@lerna/version/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/@lerna/version/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/version/node_modules/load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/version/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/version/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/version/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/write-log-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-4.0.0.tgz", + "integrity": "sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg==", + "dev": true, + "dependencies": { + "npmlog": "^4.1.2", + "write-file-atomic": "^3.0.3" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/@lerna/write-log-file/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/ci-detect": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz", + "integrity": "sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q==", + "dev": true + }, + "node_modules/@npmcli/git": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.0.8.tgz", + "integrity": "sha512-LPnzyBZ+1p7+JzHVwwKycMF8M3lr1ze3wxGRnxn/QxJtk++Y3prSJQrdBDGCxJyRpFsup6J3lrRBVYBhJVrM8Q==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "node_modules/@npmcli/git/node_modules/hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git/node_modules/npm-package-arg": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", + "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git/node_modules/npm-pick-manifest": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "dev": true, + "dependencies": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + } + }, + "node_modules/@npmcli/git/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz", + "integrity": "sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg==", + "dev": true + }, + "node_modules/@npmcli/promise-spawn": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", + "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + } + }, + "node_modules/@npmcli/run-script": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.3.tgz", + "integrity": "sha512-ELPGWAVU/xyU+A+H3pEPj0QOvYwLTX71RArXcClFzeiyJ/b/McsZ+d0QxpznvfFtZzxGN/gz/1cvlqICR4/suQ==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "infer-owner": "^1.0.4", + "node-gyp": "^7.1.0", + "puka": "^1.0.1", + "read-package-json-fast": "^2.0.1" + } + }, + "node_modules/@npmcli/run-script/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/run-script/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/run-script/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/@npmcli/run-script/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@npmcli/run-script/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/run-script/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/run-script/node_modules/node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@npmcli/run-script/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/run-script/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/run-script/node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-token": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz", + "integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/core": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.5.tgz", + "integrity": "sha512-+DCtPykGnvXKWWQI0E1XD+CCeWSBhB6kwItXqfFmNBlIlhczuDPbg+P6BtLnVBaRJDAjv+1mrUJuRsFSjktopg==", + "dev": true, + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.4.12", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.1.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz", + "integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.0.tgz", + "integrity": "sha512-CJ6n7izLFXLvPZaWzCQDjU/RP+vHiZmWdOunaCS87v+2jxMsW9FB5ktfIxybRBxZjxuJGRnxk7xJecWTVxFUYQ==", + "dev": true, + "dependencies": { + "@octokit/request": "^5.3.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-5.2.1.tgz", + "integrity": "sha512-Bf7MBvQ1nMpv15ANaQtRBsC7YnwQFPM0eUztp3luQs9L6sBEiQ6ArM1Wx5CG+N7tXETtd0oE0DMcU4wbLlCZIw==", + "dev": true + }, + "node_modules/@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.11.0.tgz", + "integrity": "sha512-7L9xQank2G3r1dGqrVPo1z62V5utbykOUzlmNHPz87Pww/JpZQ9KyG5CHtUzgmB4n5iDRKYNK/86A8D98HP0yA==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.11.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz", + "integrity": "sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==", + "dev": true, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.1.tgz", + "integrity": "sha512-T9YhQqpbO9Onmg+FYk09uci9pfChg8CZR9GBaPJWj+bDSzictW1xnU0NtCSSKKyrwvpW/opu7CtuDSs/HF1Syg==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.11.1", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.14.tgz", + "integrity": "sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==", + "dev": true, + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^6.7.1", + "deprecation": "^2.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.1", + "once": "^1.4.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz", + "integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==", + "dev": true, + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/request-error/node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/@octokit/request/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@octokit/request/node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/@octokit/rest": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.3.1.tgz", + "integrity": "sha512-g57ebsk7dtbLjiPBgEYDAiDTsyQM9kvlIt0J5UN6OSjG82K6fQQck6HXPpwcyNIDqbN7lIaWr3nsz56jBfI6qg==", + "dev": true, + "dependencies": { + "@octokit/core": "^3.2.3", + "@octokit/plugin-paginate-rest": "^2.6.2", + "@octokit/plugin-request-log": "^1.0.2", + "@octokit/plugin-rest-endpoint-methods": "4.13.1" + } + }, + "node_modules/@octokit/types": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.11.1.tgz", + "integrity": "sha512-UiSRTG2lrFbMUMwhKNR0uSV33Fzv4bNu1n5iFuuNOg80XCh0VYNhR4TQWgrkLhVxdDuej6s61aP3eQvVm6K6uA==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^5.2.1" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", + "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", + "dev": true + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/add-matchers": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/add-matchers/-/add-matchers-0.6.2.tgz", + "integrity": "sha512-hVO2wodMei9RF00qe+506MoeJ/NEOdCMEkSJ12+fC3hx/5Z4zmhNiP92nJEF6XhmXokeB0hOtuQrjHCx2vmXrQ==", + "dev": true + }, + "node_modules/add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/agentkeepalive": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", + "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agentkeepalive/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "dependencies": { + "type-fest": "^0.11.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "dev": true, + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "dev": true, + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "dev": true, + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "dev": true, + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/before-after-hook": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.1.tgz", + "integrity": "sha512-5ekuQOvO04MDj7kYZJaMab2S8SPjGJbotVNyv7QYFCOAwrGZs/YnoDNlh1U+m5hl7H2D/+n0taaAV/tfyd3KMA==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "node_modules/byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/byte-size": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-7.0.0.tgz", + "integrity": "sha512-NNiBxKgxybMBtWdmvx7ZITJi4ZG+CYUgwOSZTfqB1qogkRHrhbQE/R2r5Fh94X+InN5MCYz6SvB/ejHMj/HbsQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz", + "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==", + "dev": true, + "dependencies": { + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.0", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/caching-transform/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caching-transform/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/caching-transform/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/chokidar/node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-spinners": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.1.0.tgz", + "integrity": "sha512-8B00fJOEh1HPrx4fo5eW16XmE1PcL1tGpGrxy63CXGP9nHdPBN63X75hA1zhvQuhVztJWLqV58Roj2qlNM7cAA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/cmd-shim": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-4.1.0.tgz", + "integrity": "sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw==", + "dev": true, + "dependencies": { + "mkdirp-infer-owner": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "dev": true, + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/columnify": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", + "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "dev": true, + "dependencies": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/compare-func/node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "node_modules/conventional-changelog-angular": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz", + "integrity": "sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.2.tgz", + "integrity": "sha512-7pDpRUiobQDNkwHyJG7k9f6maPo9tfPzkSWbRq97GGiZqisElhnvUZSvyQH20ogfOjntB5aadvv6NNcKL1sReg==", + "dev": true, + "dependencies": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^4.0.18", + "conventional-commits-parser": "^3.2.0", + "dateformat": "^3.0.0", + "get-pkg-repo": "^1.0.0", + "git-raw-commits": "^2.0.8", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^4.1.1", + "lodash": "^4.17.15", + "normalize-package-data": "^3.0.0", + "q": "^1.5.1", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0", + "shelljs": "^0.8.3", + "through2": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/conventional-changelog-core/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/conventional-changelog-core/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-core/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/conventional-changelog-core/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz", + "integrity": "sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.6", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/conventional-changelog-writer/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/conventional-changelog-writer/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/conventional-commits-filter": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", + "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "dev": true, + "dependencies": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-commits-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz", + "integrity": "sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0", + "trim-off-newlines": "^1.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-commits-parser/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/conventional-commits-parser/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz", + "integrity": "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw==", + "dev": true, + "dependencies": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^2.3.4", + "conventional-commits-filter": "^2.0.7", + "conventional-commits-parser": "^3.2.0", + "git-raw-commits": "^2.0.8", + "git-semver-tags": "^4.1.1", + "meow": "^8.0.0", + "q": "^1.5.1" + }, + "bin": { + "conventional-recommended-bump": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-recommended-bump/node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/conventional-recommended-bump/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "dev": true, + "dependencies": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cosmiconfig/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-compare/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/end-of-stream/node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/enquirer/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/env-paths": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", + "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.4.tgz", + "integrity": "sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.18.0-next.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.3.tgz", + "integrity": "sha512-VMzHx/Bczjg59E6jZOQjHeN3DEoptdhejpARgflAViidlqSpjdq9zA6lKwlhRRs/lOw1gHJv2xkkSFRgvEwbQg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.50", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", + "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", + "dev": true, + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", + "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/@babel/helper-validator-identifier": { + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz", + "integrity": "sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint/node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint/node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/eslint/node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/eslint/node_modules/flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "dev": true + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", + "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/eslint/node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/eslint/node_modules/table/node_modules/ajv": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/execa/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-glob/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/fast-glob/node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", + "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/foreground-child/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/foreground-child/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fromentries": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.0.tgz", + "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-extra/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", + "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", + "bundleDependencies": [ + "node-pre-gyp" + ], + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/fsevents/node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/aproba": { + "version": "1.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/are-we-there-yet": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/fsevents/node_modules/balanced-match": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fsevents/node_modules/chownr": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/code-point-at": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/debug": { + "version": "3.2.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/fsevents/node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/fsevents/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/detect-libc": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/fsevents/node_modules/fs-minipass": { + "version": "1.2.7", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fsevents/node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/gauge": { + "version": "2.7.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/fsevents/node_modules/glob": { + "version": "7.1.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/ignore-walk": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/fsevents/node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/fsevents/node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/ini": { + "version": "1.3.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/minimatch": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fsevents/node_modules/minimist": { + "version": "1.2.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/minipass": { + "version": "2.9.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/fsevents/node_modules/minizlib": { + "version": "1.3.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/fsevents/node_modules/mkdirp": { + "version": "0.5.3", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/fsevents/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/needle": { + "version": "2.3.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/fsevents/node_modules/node-pre-gyp": { + "version": "0.14.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/fsevents/node_modules/nopt": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/fsevents/node_modules/npm-bundled": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/fsevents/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/npm-packlist": { + "version": "1.4.8", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/fsevents/node_modules/npmlog": { + "version": "4.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/fsevents/node_modules/number-is-nan": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/once": { + "version": "1.4.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/fsevents/node_modules/os-homedir": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/os-tmpdir": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/osenv": { + "version": "0.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/fsevents/node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/rc": { + "version": "1.2.8", + "dev": true, + "inBundle": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/fsevents/node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/fsevents/node_modules/rimraf": { + "version": "2.7.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/fsevents/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/sax": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/semver": { + "version": "5.7.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/fsevents/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/signal-exit": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/fsevents/node_modules/string-width": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fsevents/node_modules/tar": { + "version": "4.4.13", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/fsevents/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/fsevents/node_modules/wide-align": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/fsevents/node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/fsevents/node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic/node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-pkg-repo": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz", + "integrity": "sha1-xztInAbYDMVTbCyFP54FIyBWly0=", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "meow": "^3.3.0", + "normalize-package-data": "^2.3.0", + "parse-github-repo-url": "^1.3.0", + "through2": "^2.0.0" + }, + "bin": { + "get-pkg-repo": "cli.js" + } + }, + "node_modules/get-pkg-repo/node_modules/camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-pkg-repo/node_modules/camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "dependencies": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-pkg-repo/node_modules/indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-pkg-repo/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-pkg-repo/node_modules/meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "dependencies": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-pkg-repo/node_modules/redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "dependencies": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-pkg-repo/node_modules/strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "dependencies": { + "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-pkg-repo/node_modules/trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/git-raw-commits": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", + "integrity": "sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==", + "dev": true, + "dependencies": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-raw-commits/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/git-raw-commits/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "dev": true, + "dependencies": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/git-semver-tags": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", + "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", + "dev": true, + "dependencies": { + "meow": "^8.0.0", + "semver": "^6.0.0" + }, + "bin": { + "git-semver-tags": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-semver-tags/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/git-up": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.2.tgz", + "integrity": "sha512-kbuvus1dWQB2sSW4cbfTeGpCMd8ge9jx9RKnhXhuJ7tnvT+NIrTVfYZxjtflZddQYcmdOTlkAcjmx7bor+15AQ==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "parse-url": "^5.0.0" + } + }, + "node_modules/git-url-parse": { + "version": "11.4.4", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.4.4.tgz", + "integrity": "sha512-Y4o9o7vQngQDIU9IjyCmRJBin5iYjI5u9ZITnddRZpD7dcCFQj2sL2XuMNbLRE4b4B/4ENPsp2Q8P44fjAZ0Pw==", + "dev": true, + "dependencies": { + "git-up": "^4.0.0" + } + }, + "node_modules/gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "dev": true, + "dependencies": { + "ini": "^1.3.2" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-watcher/node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", + "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-eslint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", + "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", + "dev": true, + "dependencies": { + "eslint": "^6.0.0", + "fancy-log": "^1.3.2", + "plugin-error": "^1.0.1" + } + }, + "node_modules/gulp-eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/gulp-eslint/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/gulp-eslint/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/gulp-eslint/node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-eslint/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/gulp-eslint/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gulp-eslint/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gulp-eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/gulp-eslint/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/gulp-eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/gulp-eslint/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/gulp-eslint/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/gulp-eslint/node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/gulp-eslint/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/gulp-eslint/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-eslint/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/gulp-eslint/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/gulp-eslint/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gulp-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gulp-prettier/-/gulp-prettier-4.0.0.tgz", + "integrity": "sha512-REx99tBRRKJD7qLPaKpplReM9cq2vFvqhMbcUZtJEVjxGjb5Ji+gN9vi8bsM8UhnDV+l0Zrf5x6L4uZiDmvGFQ==", + "dev": true, + "dependencies": { + "plugin-error": "^1.0.1", + "prettier": "^2.0.0", + "through2": "^4.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gulp-prettier/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gulp-prettier/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", + "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/init-package-json": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.2.tgz", + "integrity": "sha512-PO64kVeArePvhX7Ff0jVWkpnE1DfGRvaWcStYrPugcJz9twQGYibagKJuIMHCX7ENcp0M6LJlcjLBuLD5KeJMg==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "npm-package-arg": "^8.1.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "^3.0.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/init-package-json/node_modules/hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/init-package-json/node_modules/normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/init-package-json/node_modules/read-package-json": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-3.0.1.tgz", + "integrity": "sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/init-package-json/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/inquirer/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/inquirer/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inquirer/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "6.6.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz", + "integrity": "sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex/node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-ssh": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.2.tgz", + "integrity": "sha512-elEw0/0c2UscLrNG+OAorbP539E3rhliKPg+hDMWN9VwrDXfYK+4PBEykDPfxlYYtQvl84TascnQyobfQLHEhQ==", + "dev": true, + "dependencies": { + "protocols": "^1.1.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol/node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "dev": true, + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jasmine": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.9.0.tgz", + "integrity": "sha512-JgtzteG7xnqZZ51fg7N2/wiQmXon09szkALcRMTgCMX4u/m17gVJFjObnvw5FXkZOWuweHPaPRVB6DI2uN0wVA==", + "dev": true, + "dependencies": { + "glob": "^7.1.6", + "jasmine-core": "~3.9.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-console-reporter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine-console-reporter/-/jasmine-console-reporter-3.1.0.tgz", + "integrity": "sha512-fNP6XlgkIyNvfr6JVMJudZL9qWNY2K7l934Ojj4k8J09/QXf4xYf2Mc7MUgcsDhqIb2zTkLd2LsBJWFvJz41/w==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "ci-info": "^1.4.0", + "node-emoji": "^1.8.1", + "ora": "^3.0.0", + "perfy": "^1.1.5" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jasmine": ">=3.0.0" + } + }, + "node_modules/jasmine-core": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.9.0.tgz", + "integrity": "sha512-Tv3kVbPCGVrjsnHBZ38NsPU3sDOtNa0XmbG2baiyJqdb5/SPpDO6GVwJYtUryl6KB4q1Ssckwg612ES9Z0dreQ==", + "dev": true + }, + "node_modules/jasmine-expect": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/jasmine-expect/-/jasmine-expect-5.0.0.tgz", + "integrity": "sha512-byn1zq0EQBA9UKs5A+H6gk5TRcanV+TqQMRxrjurGuqKkclaqgjw/vV6aT/jtf5tabXGonTH6VDZJ33Z1pxSxw==", + "dev": true, + "dependencies": { + "add-matchers": "0.6.2" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lerna": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz", + "integrity": "sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg==", + "dev": true, + "dependencies": { + "@lerna/add": "4.0.0", + "@lerna/bootstrap": "4.0.0", + "@lerna/changed": "4.0.0", + "@lerna/clean": "4.0.0", + "@lerna/cli": "4.0.0", + "@lerna/create": "4.0.0", + "@lerna/diff": "4.0.0", + "@lerna/exec": "4.0.0", + "@lerna/import": "4.0.0", + "@lerna/info": "4.0.0", + "@lerna/init": "4.0.0", + "@lerna/link": "4.0.0", + "@lerna/list": "4.0.0", + "@lerna/publish": "4.0.0", + "@lerna/run": "4.0.0", + "@lerna/version": "4.0.0", + "import-local": "^3.0.2", + "npmlog": "^4.1.2" + }, + "bin": { + "lerna": "cli.js" + }, + "engines": { + "node": ">= 10.18.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libnpmaccess": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-4.0.1.tgz", + "integrity": "sha512-ZiAgvfUbvmkHoMTzdwmNWCrQRsDkOC+aM5BDfO0C9aOSwF3R1LdFDBD+Rer1KWtsoQYO35nXgmMR7OUHpDRxyA==", + "dev": true, + "dependencies": { + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^8.0.0", + "npm-registry-fetch": "^9.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmaccess/node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/libnpmaccess/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/libnpmpublish": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-4.0.0.tgz", + "integrity": "sha512-2RwYXRfZAB1x/9udKpZmqEzSqNd7ouBRU52jyG14/xG8EF+O9A62d7/XVR3iABEQHf1iYhkm0Oq9iXjrL3tsXA==", + "dev": true, + "dependencies": { + "normalize-package-data": "^3.0.0", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmpublish/node_modules/hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmpublish/node_modules/normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/libnpmpublish/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "dependencies": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "node_modules/lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "dependencies": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-fetch-happen": { + "version": "8.0.14", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz", + "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.0.5", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^5.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/meow/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.6", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.6.tgz", + "integrity": "sha512-AP1+fQIWSM/sMiET8fyayjx/J+JmTPt2Mr0FkrgqB4todtfa53sOsrSAcIrJRD5XS20bKUwaDIuMkWKCEiQLKA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "dev": true, + "dependencies": { + "mime-db": "1.46.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.3.3.tgz", + "integrity": "sha512-akCrLDWfbdAWkMLBxJEeWTdNsjML+dt5YgOI4gJ53vuO0vrmYQkUPxa6j6V65s9CcePIr2SSWqjT2EcrNseryQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-infer-owner": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", + "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-infer-owner/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-infer-owner/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mock-fs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.1.0.tgz", + "integrity": "sha512-wXdQ2nIk81TYIGLphUnbXl8akQpjb9ItfZefMcTxZcoe+djMkd5POU8fQdSEErxVAeT4CgDHWveYquys4H6Cmw==", + "dev": true + }, + "node_modules/modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "dev": true, + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "dev": true, + "dependencies": { + "lodash.toarray": "^4.4.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-gyp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz", + "integrity": "sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-gyp/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-install-checks/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-lifecycle": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz", + "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", + "dev": true, + "dependencies": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "node_modules/npm-lifecycle/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.1.tgz", + "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.6", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-arg/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-packlist": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.1.4.tgz", + "integrity": "sha512-Qzg2pvXC9U4I4fLnUrBmcIT4x0woLtUgxUi9eC+Zrcv1Xx5eamytGAfbDWQ67j7xOcQ2VW1I3su9smVTIdu7Hw==", + "dev": true, + "dependencies": { + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-pick-manifest": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.0.tgz", + "integrity": "sha512-ygs4k6f54ZxJXrzT0x34NybRlLeZ4+6nECAIbr2i0foTnijtS1TJiyzpqtuUAJOps/hO0tNDr8fRV5g+BtRlTw==", + "dev": true, + "dependencies": { + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^8.0.0", + "semver": "^7.0.0" + } + }, + "node_modules/npm-pick-manifest/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-registry-fetch": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz", + "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==", + "dev": true, + "dependencies": { + "@npmcli/ci-detect": "^1.0.0", + "lru-cache": "^6.0.0", + "make-fetch-happen": "^8.0.9", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-registry-fetch/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nyc/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/nyc/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/nyc/node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/nyc/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/nyc/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/nyc/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map-series": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-2.1.0.tgz", + "integrity": "sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-pipe": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz", + "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-waterfall": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-2.1.1.tgz", + "integrity": "sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw==", + "dev": true, + "dependencies": { + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-hash/node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/pacote": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.7.tgz", + "integrity": "sha512-ogxPor11v/rnU9ukwLlI2dPx22q9iob1+yZyqSwerKsOvBMhU9e+SJHtxY4y2N0MRH4/5jGsGiRLsZeJWyM4dQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^2.0.1", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^9.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pacote/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/pacote/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pacote/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pacote/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pacote/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pacote/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pacote/node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-github-repo-url": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", + "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=", + "dev": true + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.0.tgz", + "integrity": "sha512-02GTVHD1u0nWc20n2G7WX/PgdhNFG04j5fi1OkaJzPWLTcf6vh6229Lta1wTmXG/7Dg42tCssgkccVt7qvd8Kg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-path": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz", + "integrity": "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0", + "qs": "^6.9.4", + "query-string": "^6.13.8" + } + }, + "node_modules/parse-path/node_modules/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", + "dev": true, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/parse-url": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-5.0.3.tgz", + "integrity": "sha512-nrLCVMJpqo12X8uUJT4GJPd5AFaTOrGx/QpJy3HNcVtq0AZSstVIsnxS5fqNPuoqMUs3MyfBoOP6Zvu2Arok5A==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "normalize-url": "^6.0.1", + "parse-path": "^4.0.0", + "protocols": "^1.4.0" + } + }, + "node_modules/parse-url/node_modules/normalize-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.0.1.tgz", + "integrity": "sha512-VU4pzAuh7Kip71XEmO9aNREYAdMHFGTVj/i+CaTImS8x0i1d3jUZkXhqluy/PRgjPLMgsLQulYY3PJ/aSbSjpQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "node_modules/perfy": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/perfy/-/perfy-1.1.5.tgz", + "integrity": "sha512-/ieVBpMaPTJf83YTUl2TImsSwMEJ23qGP2w27pE6aX+NrB/ZRGqOnQZpl7J719yFwd+ebDiHguPNFeMSamyK7w==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promzard": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", + "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "dev": true, + "dependencies": { + "read": "1" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "node_modules/protocols": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz", + "integrity": "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/puka": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/puka/-/puka-1.0.1.tgz", + "integrity": "sha512-ssjRZxBd7BT3dte1RR3VoeT2cT/ODH8x+h0rUF1rMqB0srHYf48stSDWfiYakTp5UBZMxroZhB2+ExLDHm7W3g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", + "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", + "dev": true, + "dependencies": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz", + "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/read-cmd-shim": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz", + "integrity": "sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw==", + "dev": true + }, + "node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.2.tgz", + "integrity": "sha512-5fyFUyO9B799foVk4n6ylcoAktG/FbE3jwRKxvwaeSrIunaoMc0u81dzXxjeAFKOce7O5KncdfwpGvvs6r5PsQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "dependencies": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "dev": true, + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "dependencies": { + "is-finite": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/socks": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.5.1.tgz", + "integrity": "sha512-oZCsJJxapULAYJaEYBSzMcz8m3jqgGrHaGhkmU/o/PQfFWYWxkAaA0UMGImb6s6tEXfKi959X6VJjMMQ3P6TTQ==", + "dev": true, + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz", + "integrity": "sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "dependencies": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/spawn-wrap/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/spawn-wrap/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/split2/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "node_modules/stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + }, + "bin": { + "sl-log-transformer": "bin/sl-log-transformer.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "4.4.18", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.18.tgz", + "integrity": "sha512-ZuOtqqmkV9RE1+4odd+MhBpibmCxNP6PJhH/h2OqNuotTX7/XHPZQJv2pKvWMplFH9SIZZhitehh6vBH6LO8Pg==", + "dev": true, + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/tar/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/tar/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/temp-write": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/temp-write/-/temp-write-4.0.0.tgz", + "integrity": "sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "is-stream": "^2.0.0", + "make-dir": "^3.0.0", + "temp-dir": "^1.0.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-write/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/temp-write/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/temp-write/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-off-newlines": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", + "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "node_modules/type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/type/-/type-1.0.1.tgz", + "integrity": "sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-TWYSWa9T2pPN4DIJYbU9oAjQx+5qdV5RUDxwARg8fmJZrD/V27Zj0JngW5xg1DFz42G0uDYl2XhzF6alSzD62w==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/umask": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", + "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", + "integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.0", + "has-symbols": "^1.0.0", + "which-boxed-primitive": "^1.0.1" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undertaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "dev": true, + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-url": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", + "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^2.0.2", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/write-json-file": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz", + "integrity": "sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ==", + "dev": true, + "dependencies": { + "detect-indent": "^6.0.0", + "graceful-fs": "^4.1.15", + "is-plain-obj": "^2.0.0", + "make-dir": "^3.0.0", + "sort-keys": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/write-json-file/node_modules/detect-indent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", + "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/write-json-file/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/write-json-file/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/write-json-file/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/write-json-file/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/write-json-file/node_modules/sort-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", + "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", + "dev": true, + "dependencies": { + "is-plain-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/write-json-file/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-pkg": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-4.0.0.tgz", + "integrity": "sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==", + "dev": true, + "dependencies": { + "sort-keys": "^2.0.0", + "type-fest": "^0.4.1", + "write-json-file": "^3.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/write-pkg/node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "node_modules/write-pkg/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-pkg/node_modules/type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/write-pkg/node_modules/write-json-file": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", + "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", + "dev": true, + "dependencies": { + "detect-indent": "^5.0.0", + "graceful-fs": "^4.1.15", + "make-dir": "^2.1.0", + "pify": "^4.0.1", + "sort-keys": "^2.0.0", + "write-file-atomic": "^2.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", + "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", + "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "5.0.0-security.0" + } + }, + "node_modules/yargs-parser": { + "version": "5.0.0-security.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", + "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.8.3", @@ -475,24 +16550,6 @@ "path-exists": "^4.0.0" } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -517,7 +16574,8 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@jsdoc/eslint-config/-/eslint-config-1.0.8.tgz", "integrity": "sha512-QKqfU25dltYG7Euz14ND2jPWiFXCYARqotwFdXDDopyRSduUkvKVFLMZvvPk4tBj5gpTlufKMmZ+QHUMDtYAkg==", - "dev": true + "dev": true, + "requires": {} }, "@jsdoc/test-matchers": { "version": "0.1.6", @@ -1141,9 +17199,9 @@ "dev": true }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -1550,9 +17608,9 @@ "dev": true }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -1692,9 +17750,9 @@ }, "dependencies": { "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -2344,9 +18402,9 @@ } }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -2446,7 +18504,8 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz", "integrity": "sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==", - "dev": true + "dev": true, + "requires": {} }, "@octokit/plugin-rest-endpoint-methods": { "version": "4.13.1", @@ -2570,16 +18629,6 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -2596,7 +18645,8 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true + "dev": true, + "requires": {} }, "add-matchers": { "version": "0.6.2", @@ -3282,9 +19332,9 @@ } }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -3411,14 +19461,6 @@ "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } } }, "chardet": { @@ -3511,12 +19553,6 @@ "integrity": "sha512-8B00fJOEh1HPrx4fo5eW16XmE1PcL1tGpGrxy63CXGP9nHdPBN63X75hA1zhvQuhVztJWLqV58Roj2qlNM7cAA==", "dev": true }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -3526,28 +19562,6 @@ "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } } }, "clone": { @@ -4025,8 +20039,8 @@ "integrity": "sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA==", "dev": true, "requires": { - "JSONStream": "^1.0.4", "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", "lodash": "^4.17.15", "meow": "^8.0.0", "split2": "^3.0.0", @@ -4295,14 +20309,6 @@ "dev": true, "requires": { "strip-bom": "^4.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - } } }, "default-resolution": { @@ -5120,6 +21126,22 @@ } } }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "requires": {} + }, + "eslint-plugin-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", + "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -5466,6 +21488,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-glob": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", @@ -5499,9 +21527,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -5620,25 +21648,6 @@ "pkg-dir": "^4.1.0" }, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -5648,30 +21657,6 @@ "semver": "^6.0.0" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -6365,6 +22350,15 @@ "dev": true, "optional": true }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-width": { "version": "1.0.2", "bundled": true, @@ -6376,15 +22370,6 @@ "strip-ansi": "^3.0.0" } }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "strip-ansi": { "version": "3.0.1", "bundled": true, @@ -6401,7 +22386,7 @@ "optional": true }, "tar": { - "version": "4.4.18", + "version": "4.4.13", "bundled": true, "dev": true, "optional": true, @@ -6776,9 +22761,9 @@ } }, "glob-watcher": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -6786,7 +22771,16 @@ "chokidar": "^2.0.0", "is-negated-glob": "^1.0.0", "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", "object.defaults": "^1.1.0" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } } }, "global-modules": { @@ -6917,63 +22911,6 @@ "uri-js": "^4.2.2" } }, - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -6983,12 +22920,6 @@ "ms": "^2.1.1" } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "eslint": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", @@ -7054,19 +22985,10 @@ "eslint-visitor-keys": "^1.1.0" } }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -7081,60 +23003,6 @@ "type-fest": "^0.8.1" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "inquirer": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", - "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7151,33 +23019,12 @@ "type-check": "~0.3.2" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -7204,50 +23051,12 @@ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -7265,15 +23074,6 @@ } } }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -7291,6 +23091,39 @@ } } }, + "gulp-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gulp-prettier/-/gulp-prettier-4.0.0.tgz", + "integrity": "sha512-REx99tBRRKJD7qLPaKpplReM9cq2vFvqhMbcUZtJEVjxGjb5Ji+gN9vi8bsM8UhnDV+l0Zrf5x6L4uZiDmvGFQ==", + "dev": true, + "requires": { + "plugin-error": "^1.0.1", + "prettier": "^2.0.0", + "through2": "^4.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + } + } + } + }, "gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", @@ -7438,12 +23271,6 @@ "type-fest": "^0.8.0" }, "dependencies": { - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -8594,6 +24421,16 @@ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -9484,14 +25321,6 @@ "dev": true, "requires": { "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - } } }, "mkdirp-infer-owner": { @@ -10025,15 +25854,6 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -10043,15 +25863,6 @@ "semver": "^6.0.0" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, "p-map": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", @@ -10581,9 +26392,9 @@ } }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -10838,6 +26649,21 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", @@ -11059,14 +26885,6 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - } } }, "readdir-scoped-modules": { @@ -11357,15 +27175,6 @@ "queue-microtask": "^1.2.2" } }, - "rxjs": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", - "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -11901,6 +27710,15 @@ "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=", "dev": true }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -11943,15 +27761,6 @@ "define-properties": "^1.1.3" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -12754,28 +28563,6 @@ "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } } }, "wrappy": { @@ -12962,28 +28749,6 @@ "which-module": "^1.0.0", "y18n": "^3.2.1", "yargs-parser": "5.0.0-security.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } } }, "yargs-parser": { diff --git a/package.json b/package.json index 2d706246..e3ce7f46 100644 --- a/package.json +++ b/package.json @@ -7,14 +7,18 @@ "@jsdoc/test-matchers": "^0.1.6", "ajv": "^8.6.3", "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^4.0.0", "gulp": "^4.0.2", "gulp-eslint": "^6.0.0", + "gulp-prettier": "^4.0.0", "jasmine": "^3.9.0", "jasmine-console-reporter": "^3.1.0", "klaw-sync": "^6.0.0", "lerna": "^4.0.0", "mock-fs": "^5.1.0", - "nyc": "^15.1.0" + "nyc": "^15.1.0", + "prettier": "^2.4.1" }, "engines": { "node": ">=v14.17.6" diff --git a/packages/jsdoc-cli/lib/engine.js b/packages/jsdoc-cli/lib/engine.js index 27f9d530..10b6cd1a 100644 --- a/packages/jsdoc-cli/lib/engine.js +++ b/packages/jsdoc-cli/lib/engine.js @@ -3,21 +3,19 @@ const { EventBus } = require('@jsdoc/util'); const flags = require('./flags'); const help = require('./help'); const { LEVELS, Logger } = require('./logger'); -const {default: ow} = require('ow'); +const { default: ow } = require('ow'); const yargs = require('yargs-parser'); function validateChoice(flagInfo, choices, values) { - let flagNames = flagInfo.alias ? `-${flagInfo.alias}/` : ''; + let flagNames = flagInfo.alias ? `-${flagInfo.alias}/` : ''; - flagNames += `--${flagInfo.name}`; + flagNames += `--${flagInfo.name}`; - for (let value of values) { - if (!choices.includes(value)) { - throw new TypeError( - `The flag ${flagNames} accepts only these values: ${choices.join(', ')}` - ); - } + for (let value of values) { + if (!choices.includes(value)) { + throw new TypeError(`The flag ${flagNames} accepts only these values: ${choices.join(', ')}`); } + } } /** @@ -30,54 +28,54 @@ function validateChoice(flagInfo, choices, values) { * @private */ const { KNOWN_FLAGS, YARGS_FLAGS } = (() => { - const names = new Set(); - const opts = { - alias: {}, - array: [], - boolean: [], - coerce: {}, - narg: {}, - normalize: [] - }; + const names = new Set(); + const opts = { + alias: {}, + array: [], + boolean: [], + coerce: {}, + narg: {}, + normalize: [], + }; - // `_` contains unparsed arguments. - names.add('_'); + // `_` contains unparsed arguments. + names.add('_'); - Object.keys(flags).forEach(flag => { - const value = flags[flag]; + Object.keys(flags).forEach((flag) => { + const value = flags[flag]; - names.add(flag); + names.add(flag); - if (value.alias) { - names.add(value.alias); - opts.alias[flag] = [value.alias]; - } + if (value.alias) { + names.add(value.alias); + opts.alias[flag] = [value.alias]; + } - if (value.array) { - opts.array.push(flag); - } + if (value.array) { + opts.array.push(flag); + } - if (value.boolean) { - opts.boolean.push(flag); - } + if (value.boolean) { + opts.boolean.push(flag); + } - if (value.coerce) { - opts.coerce[flag] = value.coerce; - } + if (value.coerce) { + opts.coerce[flag] = value.coerce; + } - if (value.normalize) { - opts.normalize.push(flag); - } + if (value.normalize) { + opts.normalize.push(flag); + } - if (value.requiresArg) { - opts.narg[flag] = 1; - } - }); + if (value.requiresArg) { + opts.narg[flag] = 1; + } + }); - return { - KNOWN_FLAGS: names, - YARGS_FLAGS: opts - }; + return { + KNOWN_FLAGS: names, + YARGS_FLAGS: opts, + }; })(); /** @@ -86,148 +84,146 @@ const { KNOWN_FLAGS, YARGS_FLAGS } = (() => { * @alias module:@jsdoc/cli */ class Engine { - /** - * Create an instance of the CLI engine. - * - * @param {Object} opts - Options for the CLI engine. - * @param {number} [opts.logLevel] - The maximum logging level to print to the console. Must be - * an enumerated value of `module:@jsdoc/cli.LOG_LEVELS`. The default value is - * `module:@jsdoc/cli.LOG_LEVELS.WARN`. - * @param {string} [opts.version] - The version of JSDoc that is running. - * @param {Date} [opts.revision] - A timestamp for the version of JSDoc that is running. - */ - constructor(opts = {}) { - ow(opts, ow.object); - // The `Logger` class validates `opts.level`, so no need to validate it here. - ow(opts.revision, ow.optional.date); - ow(opts.version, ow.optional.string); + /** + * Create an instance of the CLI engine. + * + * @param {Object} opts - Options for the CLI engine. + * @param {number} [opts.logLevel] - The maximum logging level to print to the console. Must be + * an enumerated value of `module:@jsdoc/cli.LOG_LEVELS`. The default value is + * `module:@jsdoc/cli.LOG_LEVELS.WARN`. + * @param {string} [opts.version] - The version of JSDoc that is running. + * @param {Date} [opts.revision] - A timestamp for the version of JSDoc that is running. + */ + constructor(opts = {}) { + ow(opts, ow.object); + // The `Logger` class validates `opts.level`, so no need to validate it here. + ow(opts.revision, ow.optional.date); + ow(opts.version, ow.optional.string); - this._bus = new EventBus('jsdoc', { - cache: _.isBoolean(opts._cacheEventBus) ? opts._cacheEventBus : true - }); - this._logger = new Logger({ - emitter: this._bus, - level: opts.logLevel - }); - this.flags = []; - this.revision = opts.revision; - this.version = opts.version; + this._bus = new EventBus('jsdoc', { + cache: _.isBoolean(opts._cacheEventBus) ? opts._cacheEventBus : true, + }); + this._logger = new Logger({ + emitter: this._bus, + level: opts.logLevel, + }); + this.flags = []; + this.revision = opts.revision; + this.version = opts.version; + } + + /** + * The log level to use. Messages are logged only if they are at or above this level. + * Must be an enumerated value of {@link module:@jsdoc/cli.LOG_LEVELS}. + * + * The default value is `module:@jsdoc/cli.LOG_LEVELS.WARN`. + */ + get logLevel() { + return this._logger.level; + } + + set logLevel(level) { + this._logger.level = level; + } + + /** + * Get help text for JSDoc. + * + * You can specify the maximum line length for the help text. This method attempts to fit each + * line within the maximum length, but it only splits on word boundaries. If you specify a small + * length, such as `10`, some lines will exceed that length. + * + * @param {Object} [opts] - Options for formatting the help text. + * @param {number} [opts.maxLength=Infinity] - The desired maximum length of each line in the + * formatted text. + * @return {string} The formatted help text. + */ + help(opts = {}) { + ow(opts, ow.object); + ow(opts.maxLength, ow.optional.number); + + const maxLength = opts.maxLength || Infinity; + + return ( + `Options:\n${help({ maxLength })}\n\n` + 'Visit https://jsdoc.app/ for more information.' + ); + } + + /** + * Details about the command-line flags that JSDoc recognizes. + */ + get knownFlags() { + return flags; + } + + /** + * Parse an array of command-line flags (also known as "options"). + * + * Use the instance's `flags` property to retrieve the parsed flags later. + * + * @param {Array} cliFlags - The command-line flags to parse. + * @returns {Object} The name and value for each flag. The `_` property contains all arguments + * other than flags and their values. + */ + parseFlags(cliFlags) { + ow(cliFlags, ow.array); + + let normalizedFlags; + let parsed; + let parsedFlags; + let parsedFlagNames; + + normalizedFlags = Object.keys(flags); + parsed = yargs.detailed(cliFlags, YARGS_FLAGS); + if (parsed.error) { + throw parsed.error; } + parsedFlags = parsed.argv; + parsedFlagNames = new Set(Object.keys(parsedFlags)); - /** - * The log level to use. Messages are logged only if they are at or above this level. - * Must be an enumerated value of {@link module:@jsdoc/cli.LOG_LEVELS}. - * - * The default value is `module:@jsdoc/cli.LOG_LEVELS.WARN`. - */ - get logLevel() { - return this._logger.level; - } - - set logLevel(level) { - this._logger.level = level; - } - - /** - * Get help text for JSDoc. - * - * You can specify the maximum line length for the help text. This method attempts to fit each - * line within the maximum length, but it only splits on word boundaries. If you specify a small - * length, such as `10`, some lines will exceed that length. - * - * @param {Object} [opts] - Options for formatting the help text. - * @param {number} [opts.maxLength=Infinity] - The desired maximum length of each line in the - * formatted text. - * @return {string} The formatted help text. - */ - help(opts = {}) { - ow(opts, ow.object); - ow(opts.maxLength, ow.optional.number); - - const maxLength = opts.maxLength || Infinity; - - return ( - `Options:\n${help({ maxLength })}\n\n` + - 'Visit https://jsdoc.app/ for more information.' + // Check all parsed flags for unknown flag names. + for (let flag of parsedFlagNames) { + if (!KNOWN_FLAGS.has(flag)) { + throw new TypeError( + 'Unknown command-line option: ' + (flag.length === 1 ? `-${flag}` : `--${flag}`) ); + } } - /** - * Details about the command-line flags that JSDoc recognizes. - */ - get knownFlags() { - return flags; + // Validate the values of known flags. + for (let flag of normalizedFlags) { + if (parsedFlags[flag] && flags[flag].choices) { + let flagInfo = { + name: flag, + alias: flags[flag].alias, + }; + + validateChoice(flagInfo, flags[flag].choices, parsedFlags[flag]); + } } - /** - * Parse an array of command-line flags (also known as "options"). - * - * Use the instance's `flags` property to retrieve the parsed flags later. - * - * @param {Array} cliFlags - The command-line flags to parse. - * @returns {Object} The name and value for each flag. The `_` property contains all arguments - * other than flags and their values. - */ - parseFlags(cliFlags) { - ow(cliFlags, ow.array); + // Only keep the long name of each flag. + this.flags = _.pick(parsedFlags, normalizedFlags.concat(['_'])); - let normalizedFlags; - let parsed; - let parsedFlags; - let parsedFlagNames; + return this.flags; + } - normalizedFlags = Object.keys(flags); - parsed = yargs.detailed(cliFlags, YARGS_FLAGS); - if (parsed.error) { - throw parsed.error; - } - parsedFlags = parsed.argv; - parsedFlagNames = new Set(Object.keys(parsedFlags)); + /** + * A string that describes the current JSDoc version. + */ + get versionDetails() { + let revision = ''; - // Check all parsed flags for unknown flag names. - for (let flag of parsedFlagNames) { - if (!KNOWN_FLAGS.has(flag)) { - throw new TypeError( - 'Unknown command-line option: ' + - (flag.length === 1 ? `-${flag}` : `--${flag}`) - ); - } - } - - // Validate the values of known flags. - for (let flag of normalizedFlags) { - if (parsedFlags[flag] && flags[flag].choices) { - let flagInfo = { - name: flag, - alias: flags[flag].alias - }; - - validateChoice(flagInfo, flags[flag].choices, parsedFlags[flag]); - } - } - - // Only keep the long name of each flag. - this.flags = _.pick(parsedFlags, normalizedFlags.concat(['_'])); - - return this.flags; + if (!this.version) { + return ''; } - /** - * A string that describes the current JSDoc version. - */ - get versionDetails() { - let revision = ''; - - if (!this.version) { - return ''; - } - - if (this.revision) { - revision = `(${this.revision.toUTCString()})`; - } - - return `JSDoc ${this.version} ${revision}`.trim(); + if (this.revision) { + revision = `(${this.revision.toUTCString()})`; } + + return `JSDoc ${this.version} ${revision}`.trim(); + } } Engine.LOG_LEVELS = LEVELS; diff --git a/packages/jsdoc-cli/lib/flags.js b/packages/jsdoc-cli/lib/flags.js index 1afe13c7..d38b1b66 100644 --- a/packages/jsdoc-cli/lib/flags.js +++ b/packages/jsdoc-cli/lib/flags.js @@ -8,100 +8,100 @@ const querystring = require('querystring'); * @alias module:@jsdoc/cli/lib/flags */ module.exports = { - access: { - alias: 'a', - array: true, - choices: ['all', 'package', 'private', 'protected', 'public', 'undefined'], - defaultDescription: 'All except `private`', - description: 'Document only symbols with the specified access level.', - requiresArg: true - }, - configure: { - alias: 'c', - description: 'The configuration file to use.', - normalize: true, - requiresArg: true - }, - debug: { - boolean: true, - description: 'Log information to help with debugging.' - }, - destination: { - alias: 'd', - default: './out', - description: 'The output directory.', - normalize: true, - requiresArg: true - }, - encoding: { - alias: 'e', - default: 'utf8', - description: 'The encoding to assume when reading source files.', - requiresArg: true - }, - explain: { - alias: 'X', - boolean: true, - description: 'Print the parse results to the console and exit.' - }, - help: { - alias: 'h', - boolean: true, - description: 'Print help information and exit.' - }, - match: { - description: 'Run only tests whose names contain this value.', - requiresArg: true - }, - package: { - alias: 'P', - description: 'The path to the `package.json` file to use.', - normalize: true, - requiresArg: true - }, - pedantic: { - boolean: true, - description: 'Treat errors as fatal errors, and treat warnings as errors.' - }, - private: { - alias: 'p', - boolean: true, - description: 'Document private symbols (equivalent to `--access all`).' - }, - query: { - alias: 'q', - coerce: ((str) => cast(querystring.parse(str))), - description: 'A query string to parse and store (for example, `foo=bar&baz=true`).', - requiresArg: true - }, - readme: { - alias: 'R', - description: 'The `README` file to include in the documentation.', - normalize: true, - requiresArg: true - }, - recurse: { - alias: 'r', - boolean: true, - description: 'Recurse into subdirectories to find source files.' - }, - template: { - alias: 't', - description: 'The template package to use.', - requiresArg: true - }, - test: { - alias: 'T', - boolean: true, - description: 'Run all tests and exit.' - }, - verbose: { - boolean: true, - description: 'Log detailed information to the console.' - }, - version: { - alias: 'v', - boolean: true, - description: 'Display the version number and exit.' - } + access: { + alias: 'a', + array: true, + choices: ['all', 'package', 'private', 'protected', 'public', 'undefined'], + defaultDescription: 'All except `private`', + description: 'Document only symbols with the specified access level.', + requiresArg: true, + }, + configure: { + alias: 'c', + description: 'The configuration file to use.', + normalize: true, + requiresArg: true, + }, + debug: { + boolean: true, + description: 'Log information to help with debugging.', + }, + destination: { + alias: 'd', + default: './out', + description: 'The output directory.', + normalize: true, + requiresArg: true, + }, + encoding: { + alias: 'e', + default: 'utf8', + description: 'The encoding to assume when reading source files.', + requiresArg: true, + }, + explain: { + alias: 'X', + boolean: true, + description: 'Print the parse results to the console and exit.', + }, + help: { + alias: 'h', + boolean: true, + description: 'Print help information and exit.', + }, + match: { + description: 'Run only tests whose names contain this value.', + requiresArg: true, + }, + package: { + alias: 'P', + description: 'The path to the `package.json` file to use.', + normalize: true, + requiresArg: true, + }, + pedantic: { + boolean: true, + description: 'Treat errors as fatal errors, and treat warnings as errors.', + }, + private: { + alias: 'p', + boolean: true, + description: 'Document private symbols (equivalent to `--access all`).', + }, + query: { + alias: 'q', + coerce: (str) => cast(querystring.parse(str)), + description: 'A query string to parse and store (for example, `foo=bar&baz=true`).', + requiresArg: true, + }, + readme: { + alias: 'R', + description: 'The `README` file to include in the documentation.', + normalize: true, + requiresArg: true, + }, + recurse: { + alias: 'r', + boolean: true, + description: 'Recurse into subdirectories to find source files.', + }, + template: { + alias: 't', + description: 'The template package to use.', + requiresArg: true, + }, + test: { + alias: 'T', + boolean: true, + description: 'Run all tests and exit.', + }, + verbose: { + boolean: true, + description: 'Log detailed information to the console.', + }, + version: { + alias: 'v', + boolean: true, + description: 'Display the version number and exit.', + }, }; diff --git a/packages/jsdoc-cli/lib/help.js b/packages/jsdoc-cli/lib/help.js index e5930493..83e22d29 100644 --- a/packages/jsdoc-cli/lib/help.js +++ b/packages/jsdoc-cli/lib/help.js @@ -1,34 +1,34 @@ const flags = require('./flags'); function padLeft(str, length) { - return str.padStart(str.length + length); + return str.padStart(str.length + length); } function padRight(str, length) { - return str.padEnd(str.length + length); + return str.padEnd(str.length + length); } function findMaxLength(arr) { - let max = 0; + let max = 0; - arr.forEach(({length}) => { - max = Math.max(max, length); - }); + arr.forEach(({ length }) => { + max = Math.max(max, length); + }); - return max; + return max; } function concatWithMaxLength(items, maxLength) { - let result = ''; + let result = ''; - // to prevent endless loops, always use the first item, regardless of length - result += items.shift(); + // to prevent endless loops, always use the first item, regardless of length + result += items.shift(); - while (items.length && (result.length + items[0].length < maxLength)) { - result += ` ${items.shift()}`; - } + while (items.length && result.length + items[0].length < maxLength) { + result += ` ${items.shift()}`; + } - return result; + return result; } /** @@ -48,41 +48,41 @@ function concatWithMaxLength(items, maxLength) { * @param {Object} opts - Options for formatting the text. * @param {number} opts.maxLength - The maximum length of each line. */ -function formatHelpInfo({names, descriptions}, {maxLength}) { - const MARGIN_SIZE = 4; - const GUTTER_SIZE = MARGIN_SIZE; - const results = []; +function formatHelpInfo({ names, descriptions }, { maxLength }) { + const MARGIN_SIZE = 4; + const GUTTER_SIZE = MARGIN_SIZE; + const results = []; - const maxNameLength = findMaxLength(names); - const wrapDescriptionAt = maxLength - (MARGIN_SIZE * 2) - GUTTER_SIZE - maxNameLength; + const maxNameLength = findMaxLength(names); + const wrapDescriptionAt = maxLength - MARGIN_SIZE * 2 - GUTTER_SIZE - maxNameLength; - // Build the string for each flag. - names.forEach((name, i) => { - let result; - let partialDescription; - let words; + // Build the string for each flag. + names.forEach((name, i) => { + let result; + let partialDescription; + let words; - // Add some whitespace before the name. - result = padLeft(name, MARGIN_SIZE); - // Make the descriptions left-justified, with a gutter between the names and descriptions. - result = padRight(result, maxNameLength - name.length + GUTTER_SIZE); + // Add some whitespace before the name. + result = padLeft(name, MARGIN_SIZE); + // Make the descriptions left-justified, with a gutter between the names and descriptions. + result = padRight(result, maxNameLength - name.length + GUTTER_SIZE); - // Split the description on spaces. - words = descriptions[i].split(' '); - // Add as much of the description as we can fit on the first line. - result += concatWithMaxLength(words, wrapDescriptionAt); - // If there's anything left, keep going until we've consumed the entire description. - while (words.length) { - // Add whitespace for the name column and the gutter. - partialDescription = padLeft('', MARGIN_SIZE + maxNameLength + GUTTER_SIZE); - partialDescription += concatWithMaxLength(words, wrapDescriptionAt); - result += `\n${partialDescription}`; - } + // Split the description on spaces. + words = descriptions[i].split(' '); + // Add as much of the description as we can fit on the first line. + result += concatWithMaxLength(words, wrapDescriptionAt); + // If there's anything left, keep going until we've consumed the entire description. + while (words.length) { + // Add whitespace for the name column and the gutter. + partialDescription = padLeft('', MARGIN_SIZE + maxNameLength + GUTTER_SIZE); + partialDescription += concatWithMaxLength(words, wrapDescriptionAt); + result += `\n${partialDescription}`; + } - results.push(result); - }); + results.push(result); + }); - return results; + return results; } /** @@ -95,41 +95,41 @@ function formatHelpInfo({names, descriptions}, {maxLength}) { * @private */ module.exports = ({ maxLength }) => { - const flagInfo = { - names: [], - descriptions: [] - }; + const flagInfo = { + names: [], + descriptions: [], + }; - Object.keys(flags) - .sort() - .forEach(flagName => { - const flagDetail = flags[flagName]; - let description = ''; - let name = ''; + Object.keys(flags) + .sort() + .forEach((flagName) => { + const flagDetail = flags[flagName]; + let description = ''; + let name = ''; - if (flagDetail.alias) { - name += `-${flagDetail.alias}, `; - } + if (flagDetail.alias) { + name += `-${flagDetail.alias}, `; + } - name += `--${flagName}`; + name += `--${flagName}`; - if (flagDetail.requiresArg) { - name += ' '; - } + if (flagDetail.requiresArg) { + name += ' '; + } - description += flagDetail.description; + description += flagDetail.description; - if (flagDetail.array) { - description += ' Can be specified more than once.'; - } + if (flagDetail.array) { + description += ' Can be specified more than once.'; + } - if (flagDetail.choices) { - description += ` Accepts these values: ${flagDetail.choices.join(', ')}`; - } + if (flagDetail.choices) { + description += ` Accepts these values: ${flagDetail.choices.join(', ')}`; + } - flagInfo.names.push(name); - flagInfo.descriptions.push(description); - }); + flagInfo.names.push(name); + flagInfo.descriptions.push(description); + }); - return `${formatHelpInfo(flagInfo, {maxLength}).join('\n')}`; + return `${formatHelpInfo(flagInfo, { maxLength }).join('\n')}`; }; diff --git a/packages/jsdoc-cli/lib/logger.js b/packages/jsdoc-cli/lib/logger.js index a7377805..a1c5fbdb 100644 --- a/packages/jsdoc-cli/lib/logger.js +++ b/packages/jsdoc-cli/lib/logger.js @@ -1,5 +1,5 @@ const _ = require('lodash'); -const {default: ow} = require('ow'); +const { default: ow } = require('ow'); /** * Logging levels for the JSDoc logger. The default logging level is @@ -10,150 +10,152 @@ const {default: ow} = require('ow'); * @type {number} */ const LEVELS = { - /** - * Do not log any messages. - * - * @alias module:@jsdoc/cli.LOG_LEVELS.SILENT - */ - SILENT: 0, - /** - * Log fatal errors that prevent JSDoc from running. - * - * @alias module:@jsdoc/cli.LOG_LEVELS.FATAL - */ - FATAL: 10, - /** - * Log all errors, including errors from which JSDoc can recover. - * - * @alias module:@jsdoc/cli.LOG_LEVELS.ERROR - */ - ERROR: 20, - /** - * Log the following messages: - * - * + Warnings - * + Errors - * - * @alias module:@jsdoc/cli.LOG_LEVELS.WARN - */ - WARN: 30, - /** - * Log the following messages: - * - * + Informational messages - * + Warnings - * + Errors - * - * @alias module:@jsdoc/cli.LOG_LEVELS.INFO - */ - INFO: 40, - /** - * Log the following messages: - * - * + Debugging messages - * + Informational messages - * + Warnings - * + Errors - * - * @alias module:@jsdoc/cli.LOG_LEVELS.DEBUG - */ - DEBUG: 50, - /** - * Log all messages. - * - * @alias module:@jsdoc/cli.LOG_LEVELS.VERBOSE - */ - VERBOSE: 1000 + /** + * Do not log any messages. + * + * @alias module:@jsdoc/cli.LOG_LEVELS.SILENT + */ + SILENT: 0, + /** + * Log fatal errors that prevent JSDoc from running. + * + * @alias module:@jsdoc/cli.LOG_LEVELS.FATAL + */ + FATAL: 10, + /** + * Log all errors, including errors from which JSDoc can recover. + * + * @alias module:@jsdoc/cli.LOG_LEVELS.ERROR + */ + ERROR: 20, + /** + * Log the following messages: + * + * + Warnings + * + Errors + * + * @alias module:@jsdoc/cli.LOG_LEVELS.WARN + */ + WARN: 30, + /** + * Log the following messages: + * + * + Informational messages + * + Warnings + * + Errors + * + * @alias module:@jsdoc/cli.LOG_LEVELS.INFO + */ + INFO: 40, + /** + * Log the following messages: + * + * + Debugging messages + * + Informational messages + * + Warnings + * + Errors + * + * @alias module:@jsdoc/cli.LOG_LEVELS.DEBUG + */ + DEBUG: 50, + /** + * Log all messages. + * + * @alias module:@jsdoc/cli.LOG_LEVELS.VERBOSE + */ + VERBOSE: 1000, }; const DEFAULT_LEVEL = LEVELS.WARN; const FUNCS = { - [LEVELS.DEBUG]: 'debug', - [LEVELS.ERROR]: 'error', - [LEVELS.INFO]: 'info', - [LEVELS.FATAL]: 'error', - [LEVELS.VERBOSE]: 'debug', - [LEVELS.WARN]: 'warn' + [LEVELS.DEBUG]: 'debug', + [LEVELS.ERROR]: 'error', + [LEVELS.INFO]: 'info', + [LEVELS.FATAL]: 'error', + [LEVELS.VERBOSE]: 'debug', + [LEVELS.WARN]: 'warn', }; const LEVELS_BY_NUMBER = _.invert(LEVELS); const PREFIXES = { - [LEVELS.DEBUG]: 'DEBUG: ', - [LEVELS.ERROR]: 'ERROR: ', - [LEVELS.FATAL]: 'FATAL: ', - [LEVELS.WARN]: 'WARNING: ' + [LEVELS.DEBUG]: 'DEBUG: ', + [LEVELS.ERROR]: 'ERROR: ', + [LEVELS.FATAL]: 'FATAL: ', + [LEVELS.WARN]: 'WARNING: ', }; // Add a prefix to a log message if necessary. function addPrefix(level, args) { - const prefix = PREFIXES[level]; + const prefix = PREFIXES[level]; - if (prefix && _.isString(args[0])) { - args[0] = prefix + args[0]; - } + if (prefix && _.isString(args[0])) { + args[0] = prefix + args[0]; + } - return args; + return args; } class Logger { - constructor(opts) { - ow(opts, ow.object); - // We validate `opts.level` in the setter, so no need to validate it here. - ow(opts.emitter, ow.object.partialShape({ - off: ow.function, - on: ow.function, - once: ow.function - })); + constructor(opts) { + ow(opts, ow.object); + // We validate `opts.level` in the setter, so no need to validate it here. + ow( + opts.emitter, + ow.object.partialShape({ + off: ow.function, + on: ow.function, + once: ow.function, + }) + ); - this._console = opts._console || console; - const emitter = this._emitter = opts.emitter; + this._console = opts._console || console; + const emitter = (this._emitter = opts.emitter); - this.level = opts.level || DEFAULT_LEVEL; + this.level = opts.level || DEFAULT_LEVEL; - for (const levelName of Object.keys(LEVELS)) { - let levelNameLower; - let levelNumber; + for (const levelName of Object.keys(LEVELS)) { + let levelNameLower; + let levelNumber; - // `logger:silent` events are not a thing. - if (levelName === 'SILENT') { - continue; - } + // `logger:silent` events are not a thing. + if (levelName === 'SILENT') { + continue; + } - levelNameLower = levelName.toLowerCase(); - levelNumber = LEVELS[levelName]; + levelNameLower = levelName.toLowerCase(); + levelNumber = LEVELS[levelName]; - emitter.on( - `logger:${levelNameLower}`, - (...args) => this._maybeLog(levelNumber, args) - ); - } + emitter.on(`logger:${levelNameLower}`, (...args) => this._maybeLog(levelNumber, args)); + } + } + + _maybeLog(level, args) { + if (this._level >= level) { + args = addPrefix(level, args); + this._console[FUNCS[level]](...args); + } + } + + get level() { + return this._level; + } + + set level(level) { + let errorMsg; + + if (_.isUndefined(LEVELS_BY_NUMBER[level])) { + errorMsg = `Unrecognized logging level ${level}. Known levels are: `; + errorMsg += Object.keys(LEVELS) + .map((k) => `${k}: ${LEVELS[k]}`) + .join(', '); + + throw new TypeError(errorMsg); } - _maybeLog(level, args) { - if (this._level >= level) { - args = addPrefix(level, args); - this._console[FUNCS[level]](...args); - } - } - - get level() { - return this._level; - } - - set level(level) { - let errorMsg; - - if (_.isUndefined(LEVELS_BY_NUMBER[level])) { - errorMsg = `Unrecognized logging level ${level}. Known levels are: `; - errorMsg += Object.keys(LEVELS).map(k => `${k}: ${LEVELS[k]}`).join(', '); - - throw new TypeError(errorMsg); - } - - this._level = level; - } + this._level = level; + } } module.exports = { - LEVELS, - Logger + LEVELS, + Logger, }; diff --git a/packages/jsdoc-cli/package-lock.json b/packages/jsdoc-cli/package-lock.json index 80aed43c..c54c2b70 100644 --- a/packages/jsdoc-cli/package-lock.json +++ b/packages/jsdoc-cli/package-lock.json @@ -1,8 +1,129 @@ { "name": "@jsdoc/cli", "version": "0.2.5", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@jsdoc/cli", + "version": "0.2.5", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21", + "ow": "^0.27.0", + "strip-bom": "^4.0.0", + "yargs-parser": "^20.2.9" + }, + "engines": { + "node": ">=v14.17.6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/type-fest": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.2.2.tgz", + "integrity": "sha512-pfkPYCcuV0TJoo/jlsUeWNV8rk7uMU6ocnYNvca1Vu+pyKi8Rl8Zo2scPt9O72gCsXIm+dMxOOWuA3VFDSdzWA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + } + }, "dependencies": { "@sindresorhus/is": { "version": "4.0.1", diff --git a/packages/jsdoc-cli/test/specs/index.js b/packages/jsdoc-cli/test/specs/index.js index daeba91b..ebcab13e 100644 --- a/packages/jsdoc-cli/test/specs/index.js +++ b/packages/jsdoc-cli/test/specs/index.js @@ -1,9 +1,9 @@ const Engine = require('../../index'); describe('@jsdoc/cli', () => { - it('is lib/engine', () => { - const engine = require('../../lib/engine'); + it('is lib/engine', () => { + const engine = require('../../lib/engine'); - expect(Engine).toBe(engine); - }); + expect(Engine).toBe(engine); + }); }); diff --git a/packages/jsdoc-cli/test/specs/lib/engine.js b/packages/jsdoc-cli/test/specs/lib/engine.js index bfcb7de1..91b13a37 100644 --- a/packages/jsdoc-cli/test/specs/lib/engine.js +++ b/packages/jsdoc-cli/test/specs/lib/engine.js @@ -6,221 +6,221 @@ const TYPE_ERROR = 'TypeError'; // Wrapper to prevent reuse of the event bus, which leads to `MaxListenersExceededWarning` messages. class Engine extends RealEngine { - constructor(opts) { - opts = opts || {}; - opts._cacheEventBus = false; + constructor(opts) { + opts = opts || {}; + opts._cacheEventBus = false; - super(opts); - } + super(opts); + } } describe('@jsdoc/cli/lib/engine', () => { - it('exists', () => { - expect(Engine).toBeFunction(); - }); + it('exists', () => { + expect(Engine).toBeFunction(); + }); + + it('works with no input', () => { + expect(() => new Engine()).not.toThrow(); + }); + + it('has a static LOG_LEVELS property', () => { + expect(Engine.LOG_LEVELS).toBeObject(); + }); + + it('has an empty array of flags by default', () => { + expect(new Engine().flags).toBeEmptyArray(); + }); + + it('has a property that contains the known flags', () => { + expect(new Engine().knownFlags).toBe(flags); + }); + + it('has a logLevel property that defaults to LEVELS.WARN', () => { + expect(new Engine().logLevel).toBe(LEVELS.WARN); + }); + + it('has an undefined revision property by default', () => { + expect(new Engine().revision).toBeUndefined(); + }); + + it('has an undefined version property by default', () => { + expect(new Engine().version).toBeUndefined(); + }); + + it('has a versionDetails property that is an empty string by default', () => { + expect(new Engine().versionDetails).toBeEmptyString(); + }); + + it('throws if the input is not an object', () => { + expect(() => new Engine('hi')).toThrow(); + }); + + it('sets the logLevel if provided', () => { + const logLevel = LEVELS.VERBOSE; + const instance = new Engine({ logLevel }); + + expect(instance.logLevel).toBe(logLevel); + }); + + it('throws if the logLevel is invalid', () => { + const logLevel = LEVELS.VERBOSE + 1; + + expect(() => new Engine({ logLevel })).toThrowErrorOfType(TYPE_ERROR); + }); + + it('sets the revision if provided', () => { + const revision = new Date(); + const instance = new Engine({ revision }); + + expect(instance.revision).toBe(revision); + }); + + it('throws if the revision is not a date', () => { + expect(() => new Engine({ revision: '1' })).toThrow(); + }); + + it('sets the version if provided', () => { + expect(new Engine({ version: '1.2.3' }).version).toBe('1.2.3'); + }); + + it('throws if the version is not a string', () => { + expect(() => new Engine({ version: 1 })).toThrow(); + }); + + describe('help', () => { + const instance = new Engine(); it('works with no input', () => { - expect(() => new Engine()).not.toThrow(); + expect(() => instance.help()).not.toThrow(); }); - it('has a static LOG_LEVELS property', () => { - expect(Engine.LOG_LEVELS).toBeObject(); + it('throws on bad input', () => { + expect(() => instance.help('hi')).toThrow(); }); - it('has an empty array of flags by default', () => { - expect(new Engine().flags).toBeEmptyArray(); + it('returns a string', () => { + expect(instance.help()).toBeNonEmptyString(); }); - it('has a property that contains the known flags', () => { - expect(new Engine().knownFlags).toBe(flags); + it('honors a reasonable maxLength option', () => { + const max = 70; + const help = instance.help({ maxLength: max }).split('\n'); + + for (let line of help) { + expect(line.length).toBeLessThanOrEqualTo(max); + } }); - it('has a logLevel property that defaults to LEVELS.WARN', () => { - expect(new Engine().logLevel).toBe(LEVELS.WARN); + it('throws on a bad maxLength option', () => { + expect(() => instance.help({ maxLength: 'long' })).toThrow(); + }); + }); + + describe('LOG_LEVELS', () => { + it('is lib/logger.LEVELS', () => { + expect(Engine.LOG_LEVELS).toBe(LEVELS); + }); + }); + + describe('parseFlags', () => { + it('throws with no input', () => { + expect(() => new Engine().parseFlags()).toThrow(); }); - it('has an undefined revision property by default', () => { - expect(new Engine().revision).toBeUndefined(); + it('throws if the input is not an array', () => { + expect(() => new Engine().parseFlags({ foo: 'bar' })).toThrow(); }); - it('has an undefined version property by default', () => { - expect(new Engine().version).toBeUndefined(); + it('parses flags with no values', () => { + expect(new Engine().parseFlags(['--help']).help).toBeTrue(); }); - it('has a versionDetails property that is an empty string by default', () => { - expect(new Engine().versionDetails).toBeEmptyString(); + it('parses flags with values', () => { + const parsed = new Engine().parseFlags(['--configure', 'conf.json']); + + expect(parsed.configure).toBe('conf.json'); }); - it('throws if the input is not an object', () => { - expect(() => new Engine('hi')).toThrow(); + it('stores the flags in the `flags` property', () => { + const instance = new Engine(); + + instance.parseFlags(['--help']); + + expect(instance.flags.help).toBeTrue(); }); - it('sets the logLevel if provided', () => { - const logLevel = LEVELS.VERBOSE; - const instance = new Engine({ logLevel }); - - expect(instance.logLevel).toBe(logLevel); + it('throws on unrecognized flags', () => { + expect(() => new Engine().parseFlags(['--notarealflag'])).toThrow(); }); - it('throws if the logLevel is invalid', () => { - const logLevel = LEVELS.VERBOSE + 1; - - expect(() => new Engine({ logLevel })).toThrowErrorOfType(TYPE_ERROR); + it('throws on invalid flag values', () => { + expect(() => new Engine().parseFlags(['--access', 'maybe'])).toThrow(); }); - it('sets the revision if provided', () => { - const revision = new Date(); - const instance = new Engine({ revision }); + it('includes the long and short name in the error if a value is invalid', () => { + let error; - expect(instance.revision).toBe(revision); + try { + new Engine().parseFlags(['--access', 'just-this-once']); + } catch (e) { + error = e; + } + + expect(error.message).toContain('-a/--access'); }); - it('throws if the revision is not a date', () => { - expect(() => new Engine({ revision: '1' })).toThrow(); + it('includes the allowed values in the error if a value is invalid', () => { + let error; + + try { + new Engine().parseFlags(['--access', 'maybe-later']); + } catch (e) { + error = e; + } + + expect(error.message).toContain(flags.access.choices.join(', ')); }); - it('sets the version if provided', () => { - expect(new Engine({ version: '1.2.3' }).version).toBe('1.2.3'); + it('throws if a required value is missing', () => { + expect(() => new Engine().parseFlags(['--template'])).toThrow(); }); - it('throws if the version is not a string', () => { - expect(() => new Engine({ version: 1 })).toThrow(); + it('always uses the long flag name in the parsed flags', () => { + expect(new Engine().parseFlags(['-h']).help).toBeTrue(); }); - describe('help', () => { - const instance = new Engine(); + it('coerces values to other types when appropriate', () => { + const parsed = new Engine().parseFlags(['--query', 'foo=bar&baz=true']); - it('works with no input', () => { - expect(() => instance.help()).not.toThrow(); - }); + expect(parsed.query).toEqual({ + foo: 'bar', + baz: true, + }); + }); + }); - it('throws on bad input', () => { - expect(() => instance.help('hi')).toThrow(); - }); + describe('versionDetails', () => { + it('works with a version but no revision', () => { + const instance = new Engine({ version: '1.2.3' }); - it('returns a string', () => { - expect(instance.help()).toBeNonEmptyString(); - }); - - it('honors a reasonable maxLength option', () => { - const max = 70; - const help = instance.help({ maxLength: max }).split('\n'); - - for (let line of help) { - expect(line.length).toBeLessThanOrEqualTo(max); - } - }); - - it('throws on a bad maxLength option', () => { - expect(() => instance.help({ maxLength: 'long' })).toThrow(); - }); + expect(instance.versionDetails).toBe('JSDoc 1.2.3'); }); - describe('LOG_LEVELS', () => { - it('is lib/logger.LEVELS', () => { - expect(Engine.LOG_LEVELS).toBe(LEVELS); - }); + it('contains an empty string with a revision but no version', () => { + const revision = new Date(); + const instance = new Engine({ revision }); + + expect(instance.versionDetails).toBeEmptyString(); }); - describe('parseFlags', () => { - it('throws with no input', () => { - expect(() => new Engine().parseFlags()).toThrow(); - }); + it('works with a version and a revision', () => { + const revision = new Date(); + const instance = new Engine({ + version: '1.2.3', + revision, + }); - it('throws if the input is not an array', () => { - expect(() => new Engine().parseFlags({ foo: 'bar' })).toThrow(); - }); - - it('parses flags with no values', () => { - expect(new Engine().parseFlags(['--help']).help).toBeTrue(); - }); - - it('parses flags with values', () => { - const parsed = new Engine().parseFlags(['--configure', 'conf.json']); - - expect(parsed.configure).toBe('conf.json'); - }); - - it('stores the flags in the `flags` property', () => { - const instance = new Engine(); - - instance.parseFlags(['--help']); - - expect(instance.flags.help).toBeTrue(); - }); - - it('throws on unrecognized flags', () => { - expect(() => new Engine().parseFlags(['--notarealflag'])).toThrow(); - }); - - it('throws on invalid flag values', () => { - expect(() => new Engine().parseFlags(['--access', 'maybe'])).toThrow(); - }); - - it('includes the long and short name in the error if a value is invalid', () => { - let error; - - try { - new Engine().parseFlags(['--access', 'just-this-once']); - } catch (e) { - error = e; - } - - expect(error.message).toContain('-a/--access'); - }); - - it('includes the allowed values in the error if a value is invalid', () => { - let error; - - try { - new Engine().parseFlags(['--access', 'maybe-later']); - } catch (e) { - error = e; - } - - expect(error.message).toContain(flags.access.choices.join(', ')); - }); - - it('throws if a required value is missing', () => { - expect(() => new Engine().parseFlags(['--template'])).toThrow(); - }); - - it('always uses the long flag name in the parsed flags', () => { - expect(new Engine().parseFlags(['-h']).help).toBeTrue(); - }); - - it('coerces values to other types when appropriate', () => { - const parsed = new Engine().parseFlags(['--query', 'foo=bar&baz=true']); - - expect(parsed.query).toEqual({ - foo: 'bar', - baz: true - }); - }); - }); - - describe('versionDetails', () => { - it('works with a version but no revision', () => { - const instance = new Engine({ version: '1.2.3' }); - - expect(instance.versionDetails).toBe('JSDoc 1.2.3'); - }); - - it('contains an empty string with a revision but no version', () => { - const revision = new Date(); - const instance = new Engine({ revision }); - - expect(instance.versionDetails).toBeEmptyString(); - }); - - it('works with a version and a revision', () => { - const revision = new Date(); - const instance = new Engine({ - version: '1.2.3', - revision - }); - - expect(instance.versionDetails).toBe(`JSDoc 1.2.3 (${revision.toUTCString()})`); - }); + expect(instance.versionDetails).toBe(`JSDoc 1.2.3 (${revision.toUTCString()})`); }); + }); }); diff --git a/packages/jsdoc-cli/test/specs/lib/flags.js b/packages/jsdoc-cli/test/specs/lib/flags.js index 97921396..03405aa2 100644 --- a/packages/jsdoc-cli/test/specs/lib/flags.js +++ b/packages/jsdoc-cli/test/specs/lib/flags.js @@ -1,40 +1,40 @@ const flags = require('../../../lib/flags'); -const {default: ow} = require('ow'); +const { default: ow } = require('ow'); function validate(name, opts) { - name = `--${name}`; + name = `--${name}`; - if (!opts.description) { - throw new TypeError(`${name} is missing its description`); - } + if (!opts.description) { + throw new TypeError(`${name} is missing its description`); + } - if (opts.array && opts.boolean) { - throw new TypeError(`${name} can be an array or a boolean, but not both`); - } + if (opts.array && opts.boolean) { + throw new TypeError(`${name} can be an array or a boolean, but not both`); + } - if (opts.requiresArg && opts.boolean) { - throw new TypeError(`${name} can require an argument or be a boolean, but not both`); - } + if (opts.requiresArg && opts.boolean) { + throw new TypeError(`${name} can require an argument or be a boolean, but not both`); + } - try { - ow(opts.coerce, ow.optional.function); - } catch (e) { - throw new TypeError(`The coerce value for ${name} is not a function`); - } + try { + ow(opts.coerce, ow.optional.function); + } catch (e) { + throw new TypeError(`The coerce value for ${name} is not a function`); + } - if (opts.choices && !opts.requiresArg) { - throw new TypeError(`${name} specifies choices, but not requiresArg`); - } + if (opts.choices && !opts.requiresArg) { + throw new TypeError(`${name} specifies choices, but not requiresArg`); + } } describe('@jsdoc/cli/lib/flags', () => { - it('is an object', () => { - expect(flags).toBeObject(); - }); + it('is an object', () => { + expect(flags).toBeObject(); + }); - it('has reasonable settings for each flag', () => { - for (let flag of Object.keys(flags)) { - expect(() => validate(flag, flags[flag])).not.toThrow(); - } - }); + it('has reasonable settings for each flag', () => { + for (let flag of Object.keys(flags)) { + expect(() => validate(flag, flags[flag])).not.toThrow(); + } + }); }); diff --git a/packages/jsdoc-cli/test/specs/lib/help.js b/packages/jsdoc-cli/test/specs/lib/help.js index 73a2ec77..f3f86849 100644 --- a/packages/jsdoc-cli/test/specs/lib/help.js +++ b/packages/jsdoc-cli/test/specs/lib/help.js @@ -1,3 +1,3 @@ describe('@jsdoc/cli/lib/help', () => { - // Tested indirectly by the tests for `@jsdoc/cli/lib/engine`. + // Tested indirectly by the tests for `@jsdoc/cli/lib/engine`. }); diff --git a/packages/jsdoc-cli/test/specs/lib/logger.js b/packages/jsdoc-cli/test/specs/lib/logger.js index 1fb7ce68..2c6ce4db 100644 --- a/packages/jsdoc-cli/test/specs/lib/logger.js +++ b/packages/jsdoc-cli/test/specs/lib/logger.js @@ -5,203 +5,204 @@ const ARGUMENT_ERROR = 'ArgumentError'; const TYPE_ERROR = 'TypeError'; describe('@jsdoc/cli/lib/logger', () => { - describe('Logger', () => { - let bus; - let logger; + describe('Logger', () => { + let bus; + let logger; - beforeEach(() => { - bus = new EventBus('loggerTest', { - _console: console, - cache: false - }); - logger = new Logger({ emitter: bus }); + beforeEach(() => { + bus = new EventBus('loggerTest', { + _console: console, + cache: false, + }); + logger = new Logger({ emitter: bus }); - ['debug', 'error', 'info', 'warn'].forEach(func => spyOn(console, func)); - }); - - it('exports a Logger constructor', () => { - expect(() => new Logger({ emitter: bus })).not.toThrow(); - }); - - it('exports a LEVELS enum', () => { - expect(LEVELS).toBeNonEmptyObject(); - }); - - describe('constructor', () => { - it('throws on invalid input', () => { - expect(() => new Logger()).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('accepts a valid emitter', () => { - expect(() => new Logger({ emitter: bus })).not.toThrow(); - }); - - it('throws on an invalid emitter', () => { - expect(() => new Logger({ emitter: {} })).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('accepts a valid level', () => { - expect(() => new Logger({ - emitter: bus, - level: LEVELS.VERBOSE - })).not.toThrow(); - }); - - it('throws on an invalid level', () => { - expect(() => new Logger({ - emitter: bus, - level: LEVELS.VERBOSE + 1 - })).toThrowErrorOfType(TYPE_ERROR); - }); - }); - - describe('events', () => { - it('passes all event arguments through', () => { - const args = [ - 'My name is %s %s %s', - 'foo', - 'bar', - 'baz' - ]; - const eventType = 'logger:info'; - - logger.level = LEVELS.VERBOSE; - bus.emit(eventType, ...args); - - expect(console.info).toHaveBeenCalledWith(...args); - }); - - it('logs logger:fatal events by default', () => { - bus.emit('logger:fatal'); - - expect(console.error).toHaveBeenCalled(); - }); - - it('does not log logger:fatal events when level is SILENT', () => { - logger.level = LEVELS.SILENT; - bus.emit('logger:fatal'); - - expect(console.error).not.toHaveBeenCalled(); - }); - - it('logs logger:error events by default', () => { - bus.emit('logger:error'); - - expect(console.error).toHaveBeenCalled(); - }); - - it('does not log logger:error events when level is FATAL', () => { - logger.level = LEVELS.FATAL; - bus.emit('logger:error'); - - expect(console.error).not.toHaveBeenCalled(); - }); - - it('logs logger:warn events by default', () => { - bus.emit('logger:warn'); - - expect(console.warn).toHaveBeenCalled(); - }); - - it('does not log logger:warn events when level is ERROR', () => { - logger.level = LEVELS.ERROR; - bus.emit('logger:warn'); - - expect(console.warn).not.toHaveBeenCalled(); - }); - - it('does not log logger:info events by default', () => { - bus.emit('logger:info'); - - expect(console.info).not.toHaveBeenCalled(); - }); - - it('logs logger:info events when level is INFO', () => { - logger.level = LEVELS.INFO; - bus.emit('logger:info'); - - expect(console.info).toHaveBeenCalled(); - }); - - it('does not log logger:debug events by default', () => { - bus.emit('logger:debug'); - - expect(console.debug).not.toHaveBeenCalled(); - }); - - it('logs logger:debug events when level is DEBUG', () => { - logger.level = LEVELS.DEBUG; - bus.emit('logger:debug'); - - expect(console.debug).toHaveBeenCalled(); - }); - - it('does not log logger:verbose events by default', () => { - bus.emit('logger:verbose'); - - expect(console.debug).not.toHaveBeenCalled(); - }); - - it('logs logger:verbose events when level is VERBOSE', () => { - logger.level = LEVELS.VERBOSE; - bus.emit('logger:verbose'); - - expect(console.debug).toHaveBeenCalled(); - }); - }); - - describe('level', () => { - it('contains the current log level', () => { - expect(logger.level).toBe(LEVELS.WARN); - }); - - it('throws when set to an invalid value', () => { - expect(() => { - logger.level = LEVELS.VERBOSE + 1; - }).toThrowErrorOfType(TYPE_ERROR); - }); - - // The `events` tests set this property to valid values, so no need to test that - // behavior again here. - }); + ['debug', 'error', 'info', 'warn'].forEach((func) => spyOn(console, func)); }); - describe('LEVELS', () => { - it('has a numeric SILENT property', () => { - expect(LEVELS.SILENT).toBeWholeNumber(); - }); - - it('has a numeric FATAL property', () => { - expect(LEVELS.FATAL).toBeWholeNumber(); - }); - - it('has a numeric ERROR property', () => { - expect(LEVELS.ERROR).toBeWholeNumber(); - }); - - it('has a numeric WARN property', () => { - expect(LEVELS.WARN).toBeWholeNumber(); - }); - - it('has a numeric INFO property', () => { - expect(LEVELS.INFO).toBeWholeNumber(); - }); - - it('has a numeric DEBUG property', () => { - expect(LEVELS.DEBUG).toBeWholeNumber(); - }); - - it('has a numeric VERBOSE property', () => { - expect(LEVELS.VERBOSE).toBeWholeNumber(); - }); - - it('orders the log levels correctly', () => { - expect(LEVELS.SILENT).toBeLessThan(LEVELS.FATAL); - expect(LEVELS.FATAL).toBeLessThan(LEVELS.ERROR); - expect(LEVELS.ERROR).toBeLessThan(LEVELS.WARN); - expect(LEVELS.WARN).toBeLessThan(LEVELS.INFO); - expect(LEVELS.INFO).toBeLessThan(LEVELS.DEBUG); - expect(LEVELS.DEBUG).toBeLessThan(LEVELS.VERBOSE); - }); + it('exports a Logger constructor', () => { + expect(() => new Logger({ emitter: bus })).not.toThrow(); }); + + it('exports a LEVELS enum', () => { + expect(LEVELS).toBeNonEmptyObject(); + }); + + describe('constructor', () => { + it('throws on invalid input', () => { + expect(() => new Logger()).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('accepts a valid emitter', () => { + expect(() => new Logger({ emitter: bus })).not.toThrow(); + }); + + it('throws on an invalid emitter', () => { + expect(() => new Logger({ emitter: {} })).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('accepts a valid level', () => { + expect( + () => + new Logger({ + emitter: bus, + level: LEVELS.VERBOSE, + }) + ).not.toThrow(); + }); + + it('throws on an invalid level', () => { + expect( + () => + new Logger({ + emitter: bus, + level: LEVELS.VERBOSE + 1, + }) + ).toThrowErrorOfType(TYPE_ERROR); + }); + }); + + describe('events', () => { + it('passes all event arguments through', () => { + const args = ['My name is %s %s %s', 'foo', 'bar', 'baz']; + const eventType = 'logger:info'; + + logger.level = LEVELS.VERBOSE; + bus.emit(eventType, ...args); + + expect(console.info).toHaveBeenCalledWith(...args); + }); + + it('logs logger:fatal events by default', () => { + bus.emit('logger:fatal'); + + expect(console.error).toHaveBeenCalled(); + }); + + it('does not log logger:fatal events when level is SILENT', () => { + logger.level = LEVELS.SILENT; + bus.emit('logger:fatal'); + + expect(console.error).not.toHaveBeenCalled(); + }); + + it('logs logger:error events by default', () => { + bus.emit('logger:error'); + + expect(console.error).toHaveBeenCalled(); + }); + + it('does not log logger:error events when level is FATAL', () => { + logger.level = LEVELS.FATAL; + bus.emit('logger:error'); + + expect(console.error).not.toHaveBeenCalled(); + }); + + it('logs logger:warn events by default', () => { + bus.emit('logger:warn'); + + expect(console.warn).toHaveBeenCalled(); + }); + + it('does not log logger:warn events when level is ERROR', () => { + logger.level = LEVELS.ERROR; + bus.emit('logger:warn'); + + expect(console.warn).not.toHaveBeenCalled(); + }); + + it('does not log logger:info events by default', () => { + bus.emit('logger:info'); + + expect(console.info).not.toHaveBeenCalled(); + }); + + it('logs logger:info events when level is INFO', () => { + logger.level = LEVELS.INFO; + bus.emit('logger:info'); + + expect(console.info).toHaveBeenCalled(); + }); + + it('does not log logger:debug events by default', () => { + bus.emit('logger:debug'); + + expect(console.debug).not.toHaveBeenCalled(); + }); + + it('logs logger:debug events when level is DEBUG', () => { + logger.level = LEVELS.DEBUG; + bus.emit('logger:debug'); + + expect(console.debug).toHaveBeenCalled(); + }); + + it('does not log logger:verbose events by default', () => { + bus.emit('logger:verbose'); + + expect(console.debug).not.toHaveBeenCalled(); + }); + + it('logs logger:verbose events when level is VERBOSE', () => { + logger.level = LEVELS.VERBOSE; + bus.emit('logger:verbose'); + + expect(console.debug).toHaveBeenCalled(); + }); + }); + + describe('level', () => { + it('contains the current log level', () => { + expect(logger.level).toBe(LEVELS.WARN); + }); + + it('throws when set to an invalid value', () => { + expect(() => { + logger.level = LEVELS.VERBOSE + 1; + }).toThrowErrorOfType(TYPE_ERROR); + }); + + // The `events` tests set this property to valid values, so no need to test that + // behavior again here. + }); + }); + + describe('LEVELS', () => { + it('has a numeric SILENT property', () => { + expect(LEVELS.SILENT).toBeWholeNumber(); + }); + + it('has a numeric FATAL property', () => { + expect(LEVELS.FATAL).toBeWholeNumber(); + }); + + it('has a numeric ERROR property', () => { + expect(LEVELS.ERROR).toBeWholeNumber(); + }); + + it('has a numeric WARN property', () => { + expect(LEVELS.WARN).toBeWholeNumber(); + }); + + it('has a numeric INFO property', () => { + expect(LEVELS.INFO).toBeWholeNumber(); + }); + + it('has a numeric DEBUG property', () => { + expect(LEVELS.DEBUG).toBeWholeNumber(); + }); + + it('has a numeric VERBOSE property', () => { + expect(LEVELS.VERBOSE).toBeWholeNumber(); + }); + + it('orders the log levels correctly', () => { + expect(LEVELS.SILENT).toBeLessThan(LEVELS.FATAL); + expect(LEVELS.FATAL).toBeLessThan(LEVELS.ERROR); + expect(LEVELS.ERROR).toBeLessThan(LEVELS.WARN); + expect(LEVELS.WARN).toBeLessThan(LEVELS.INFO); + expect(LEVELS.INFO).toBeLessThan(LEVELS.DEBUG); + expect(LEVELS.DEBUG).toBeLessThan(LEVELS.VERBOSE); + }); + }); }); diff --git a/packages/jsdoc-core/index.js b/packages/jsdoc-core/index.js index 5bfa93ee..da297df1 100644 --- a/packages/jsdoc-core/index.js +++ b/packages/jsdoc-core/index.js @@ -8,6 +8,6 @@ const config = require('./lib/config'); const name = require('./lib/name'); module.exports = { - config, - name + config, + name, }; diff --git a/packages/jsdoc-core/lib/config.js b/packages/jsdoc-core/lib/config.js index 6621848f..2a727f91 100644 --- a/packages/jsdoc-core/lib/config.js +++ b/packages/jsdoc-core/lib/config.js @@ -11,125 +11,119 @@ const stripJsonComments = require('strip-json-comments'); const MODULE_NAME = 'jsdoc'; -const defaults = exports.defaults = { - // TODO(hegemonic): Integrate CLI options with other options. - opts: { - destination: './out', - encoding: 'utf8' - }, +const defaults = (exports.defaults = { + // TODO(hegemonic): Integrate CLI options with other options. + opts: { + destination: './out', + encoding: 'utf8', + }, + /** + * The JSDoc plugins to load. + */ + plugins: [], + // TODO(hegemonic): Move to `source` or remove. + recurseDepth: 10, + /** + * Settings for loading and parsing source files. + */ + source: { /** - * The JSDoc plugins to load. + * A regular expression that matches source files to exclude from processing. + * + * To exclude files if any portion of their path begins with an underscore, use the value + * `(^|\\/|\\\\)_`. */ - plugins: [], - // TODO(hegemonic): Move to `source` or remove. - recurseDepth: 10, + excludePattern: '', /** - * Settings for loading and parsing source files. + * A regular expression that matches source files that JSDoc should process. + * + * By default, all source files with the extensions `.js`, `.jsdoc`, and `.jsx` are + * processed. */ - source: { - /** - * A regular expression that matches source files to exclude from processing. - * - * To exclude files if any portion of their path begins with an underscore, use the value - * `(^|\\/|\\\\)_`. - */ - excludePattern: '', - /** - * A regular expression that matches source files that JSDoc should process. - * - * By default, all source files with the extensions `.js`, `.jsdoc`, and `.jsx` are - * processed. - */ - includePattern: '.+\\.js(doc|x)?$', - /** - * The type of source file. In general, you should use the value `module`. If none of your - * source files use ECMAScript >=2015 syntax, you can use the value `script`. - */ - type: 'module' - }, + includePattern: '.+\\.js(doc|x)?$', /** - * Settings for interpreting JSDoc tags. + * The type of source file. In general, you should use the value `module`. If none of your + * source files use ECMAScript >=2015 syntax, you can use the value `script`. */ - tags: { - /** - * Set to `true` to allow tags that JSDoc does not recognize. - */ - allowUnknownTags: true, - // TODO(hegemonic): Use module paths, not magic strings. - /** - * The JSDoc tag dictionaries to load. - * - * If you specify two or more tag dictionaries, and a tag is defined in multiple - * dictionaries, JSDoc uses the definition from the first dictionary that includes that tag. - */ - dictionaries: [ - 'jsdoc', - 'closure' - ] - }, + type: 'module', + }, + /** + * Settings for interpreting JSDoc tags. + */ + tags: { /** - * Settings for generating output with JSDoc templates. Some JSDoc templates might ignore these - * settings. + * Set to `true` to allow tags that JSDoc does not recognize. */ - templates: { - /** - * Set to `true` to use a monospaced font for links to other code symbols, but not links to - * websites. - */ - cleverLinks: false, - /** - * Set to `true` to use a monospaced font for all links. - */ - monospaceLinks: false - } -}; + allowUnknownTags: true, + // TODO(hegemonic): Use module paths, not magic strings. + /** + * The JSDoc tag dictionaries to load. + * + * If you specify two or more tag dictionaries, and a tag is defined in multiple + * dictionaries, JSDoc uses the definition from the first dictionary that includes that tag. + */ + dictionaries: ['jsdoc', 'closure'], + }, + /** + * Settings for generating output with JSDoc templates. Some JSDoc templates might ignore these + * settings. + */ + templates: { + /** + * Set to `true` to use a monospaced font for links to other code symbols, but not links to + * websites. + */ + cleverLinks: false, + /** + * Set to `true` to use a monospaced font for all links. + */ + monospaceLinks: false, + }, +}); // TODO: Consider exporting this class. class Config { - constructor(filepath, config) { - this.config = config; - this.filepath = filepath; - } + constructor(filepath, config) { + this.config = config; + this.filepath = filepath; + } } function loadJson(filepath, content) { - return defaultLoaders['.json'](filepath, stripBom(stripJsonComments(content))); + return defaultLoaders['.json'](filepath, stripBom(stripJsonComments(content))); } function loadYaml(filepath, content) { - return defaultLoaders['.yaml'](filepath, stripBom(content)); + return defaultLoaders['.yaml'](filepath, stripBom(content)); } const explorerSync = cosmiconfigSync(MODULE_NAME, { - cache: false, - loaders: { - '.json': loadJson, - '.yaml': loadYaml, - '.yml': loadYaml, - noExt: loadYaml - }, - searchPlaces: [ - 'package.json', - `.${MODULE_NAME}rc`, - `.${MODULE_NAME}rc.json`, - `.${MODULE_NAME}rc.yaml`, - `.${MODULE_NAME}rc.yml`, - `.${MODULE_NAME}rc.js`, - `${MODULE_NAME}.config.js` - ] + cache: false, + loaders: { + '.json': loadJson, + '.yaml': loadYaml, + '.yml': loadYaml, + noExt: loadYaml, + }, + searchPlaces: [ + 'package.json', + `.${MODULE_NAME}rc`, + `.${MODULE_NAME}rc.json`, + `.${MODULE_NAME}rc.yaml`, + `.${MODULE_NAME}rc.yml`, + `.${MODULE_NAME}rc.js`, + `${MODULE_NAME}.config.js`, + ], }); exports.loadSync = (filepath) => { - let loaded; + let loaded; - if (filepath) { - loaded = explorerSync.load(filepath); - } else { - loaded = explorerSync.search() || {}; - } + if (filepath) { + loaded = explorerSync.load(filepath); + } else { + loaded = explorerSync.search() || {}; + } - return new Config( - loaded.filepath, - _.defaultsDeep({}, loaded.config, defaults) - ); + return new Config(loaded.filepath, _.defaultsDeep({}, loaded.config, defaults)); }; diff --git a/packages/jsdoc-core/lib/name.js b/packages/jsdoc-core/lib/name.js index 716e04c2..5f6bc66f 100644 --- a/packages/jsdoc-core/lib/name.js +++ b/packages/jsdoc-core/lib/name.js @@ -16,10 +16,10 @@ const hasOwnProp = Object.prototype.hasOwnProperty; * @memberof module:jsdoc/name */ exports.LONGNAMES = { - /** Longname used for doclets that do not have a longname, such as anonymous functions. */ - ANONYMOUS: '', - /** Longname that represents global scope. */ - GLOBAL: '' + /** Longname used for doclets that do not have a longname, such as anonymous functions. */ + ANONYMOUS: '', + /** Longname that represents global scope. */ + GLOBAL: '', }; // Module namespace prefix. @@ -32,26 +32,26 @@ exports.MODULE_NAMESPACE = 'module:'; * @static * @memberof module:jsdoc/name */ -const SCOPE = exports.SCOPE = { - NAMES: { - GLOBAL: 'global', - INNER: 'inner', - INSTANCE: 'instance', - STATIC: 'static' - }, - PUNC: { - INNER: '~', - INSTANCE: '#', - STATIC: '.' - } -}; +const SCOPE = (exports.SCOPE = { + NAMES: { + GLOBAL: 'global', + INNER: 'inner', + INSTANCE: 'instance', + STATIC: 'static', + }, + PUNC: { + INNER: '~', + INSTANCE: '#', + STATIC: '.', + }, +}); // Keys must be lowercase. -const SCOPE_TO_PUNC = exports.SCOPE_TO_PUNC = { - inner: SCOPE.PUNC.INNER, - instance: SCOPE.PUNC.INSTANCE, - static: SCOPE.PUNC.STATIC -}; +const SCOPE_TO_PUNC = (exports.SCOPE_TO_PUNC = { + inner: SCOPE.PUNC.INNER, + instance: SCOPE.PUNC.INSTANCE, + static: SCOPE.PUNC.STATIC, +}); exports.PUNC_TO_SCOPE = _.invert(SCOPE_TO_PUNC); @@ -78,9 +78,9 @@ const REGEXP_NAME_DESCRIPTION = new RegExp(`^(\\[[^\\]]+\\]|\\S+)${DESCRIPTION}` * parent; otherwise, `false`. */ exports.nameIsLongname = (name, memberof) => { - const regexp = new RegExp(`^${escape(memberof)}${SCOPE_PUNC_STRING}`); + const regexp = new RegExp(`^${escape(memberof)}${SCOPE_PUNC_STRING}`); - return regexp.test(name); + return regexp.test(name); }; /** @@ -91,14 +91,14 @@ exports.nameIsLongname = (name, memberof) => { * @param {string} name - The name in which to change `prototype` to `#`. * @returns {string} The updated name. */ -const prototypeToPunc = exports.prototypeToPunc = name => { - // Don't mangle symbols named `prototype`. - if (name === 'prototype') { - return name; - } +const prototypeToPunc = (exports.prototypeToPunc = (name) => { + // Don't mangle symbols named `prototype`. + if (name === 'prototype') { + return name; + } - return name.replace(/(?:^|\.)prototype\.?/g, SCOPE.PUNC.INSTANCE); -}; + return name.replace(/(?:^|\.)prototype\.?/g, SCOPE.PUNC.INSTANCE); +}); /** * Check whether a name begins with a character that identifies a scope. @@ -106,7 +106,7 @@ const prototypeToPunc = exports.prototypeToPunc = name => { * @param {string} name - The name to check. * @returns {boolean} `true` if the name begins with a scope character; otherwise, `false`. */ -exports.hasLeadingScope = name => REGEXP_LEADING_SCOPE.test(name); +exports.hasLeadingScope = (name) => REGEXP_LEADING_SCOPE.test(name); /** * Check whether a name ends with a character that identifies a scope. @@ -114,7 +114,7 @@ exports.hasLeadingScope = name => REGEXP_LEADING_SCOPE.test(name); * @param {string} name - The name to check. * @returns {boolean} `true` if the name ends with a scope character; otherwise, `false`. */ -exports.hasTrailingScope = name => REGEXP_TRAILING_SCOPE.test(name); +exports.hasTrailingScope = (name) => REGEXP_TRAILING_SCOPE.test(name); /** * Get a symbol's basename, which is the first part of its full name before any punctuation (other @@ -128,94 +128,92 @@ exports.hasTrailingScope = name => REGEXP_TRAILING_SCOPE.test(name); * @param {?string} [name] - The symbol's full name. * @returns {?string} The symbol's basename. */ -exports.getBasename = name => { - if (!name) { - return null; - } +exports.getBasename = (name) => { + if (!name) { + return null; + } - return name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1'); + return name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1'); }; // TODO: docs -exports.stripNamespace = longname => longname.replace(/^[a-zA-Z]+:/, ''); +exports.stripNamespace = (longname) => longname.replace(/^[a-zA-Z]+:/, ''); // TODO: docs function slice(longname, sliceChars, forcedMemberof) { - let i; - let memberof = ''; - let name = ''; - let parts; - let partsRegExp; - let scopePunc = ''; - let token; - const tokens = []; - let variation; + let i; + let memberof = ''; + let name = ''; + let parts; + let partsRegExp; + let scopePunc = ''; + let token; + const tokens = []; + let variation; - sliceChars = sliceChars || SCOPE_PUNC; + sliceChars = sliceChars || SCOPE_PUNC; - // Quoted strings in a longname are atomic, so we convert them to tokens: - // foo["bar"] => foo.@{1}@ - // Foo.prototype["bar"] => Foo#@{1} - longname = longname.replace(/(prototype|#)?(\[?["'].+?["']\]?)/g, ($, p1, p2) => { - let punc = ''; + // Quoted strings in a longname are atomic, so we convert them to tokens: + // foo["bar"] => foo.@{1}@ + // Foo.prototype["bar"] => Foo#@{1} + longname = longname.replace(/(prototype|#)?(\[?["'].+?["']\]?)/g, ($, p1, p2) => { + let punc = ''; - // Is there a leading bracket? - if ( /^\[/.test(p2) ) { - // Is it a static or instance member? - punc = p1 ? SCOPE.PUNC.INSTANCE : SCOPE.PUNC.STATIC; - p2 = p2.replace(/^\[/g, '') - .replace(/\]$/g, ''); - } - - token = `@{${tokens.length}}@`; - tokens.push(p2); - - return punc + token; - }); - - longname = prototypeToPunc(longname); - - if (typeof forcedMemberof !== 'undefined') { - partsRegExp = new RegExp(`^(.*?)([${sliceChars.join()}]?)$`); - name = longname.substr(forcedMemberof.length); - parts = forcedMemberof.match(partsRegExp); - - if (parts[1]) { - memberof = parts[1] || forcedMemberof; - } - if (parts[2]) { - scopePunc = parts[2]; - } - } - else if (longname) { - parts = longname.match(new RegExp(`^(:?(.+)([${sliceChars.join()}]))?(.+?)$`)) || []; - name = parts.pop() || ''; - scopePunc = parts.pop() || ''; - memberof = parts.pop() || ''; + // Is there a leading bracket? + if (/^\[/.test(p2)) { + // Is it a static or instance member? + punc = p1 ? SCOPE.PUNC.INSTANCE : SCOPE.PUNC.STATIC; + p2 = p2.replace(/^\[/g, '').replace(/\]$/g, ''); } - // Like `@name foo.bar(2)`. - if (/(.+)\(([^)]+)\)$/.test(name)) { - name = RegExp.$1; - variation = RegExp.$2; - } + token = `@{${tokens.length}}@`; + tokens.push(p2); - // Restore quoted strings. - i = tokens.length; - while (i--) { - longname = longname.replace(`@{${i}}@`, tokens[i]); - memberof = memberof.replace(`@{${i}}@`, tokens[i]); - scopePunc = scopePunc.replace(`@{${i}}@`, tokens[i]); - name = name.replace(`@{${i}}@`, tokens[i]); - } + return punc + token; + }); - return { - longname: longname, - memberof: memberof, - scope: scopePunc, - name: name, - variation: variation - }; + longname = prototypeToPunc(longname); + + if (typeof forcedMemberof !== 'undefined') { + partsRegExp = new RegExp(`^(.*?)([${sliceChars.join()}]?)$`); + name = longname.substr(forcedMemberof.length); + parts = forcedMemberof.match(partsRegExp); + + if (parts[1]) { + memberof = parts[1] || forcedMemberof; + } + if (parts[2]) { + scopePunc = parts[2]; + } + } else if (longname) { + parts = longname.match(new RegExp(`^(:?(.+)([${sliceChars.join()}]))?(.+?)$`)) || []; + name = parts.pop() || ''; + scopePunc = parts.pop() || ''; + memberof = parts.pop() || ''; + } + + // Like `@name foo.bar(2)`. + if (/(.+)\(([^)]+)\)$/.test(name)) { + name = RegExp.$1; + variation = RegExp.$2; + } + + // Restore quoted strings. + i = tokens.length; + while (i--) { + longname = longname.replace(`@{${i}}@`, tokens[i]); + memberof = memberof.replace(`@{${i}}@`, tokens[i]); + scopePunc = scopePunc.replace(`@{${i}}@`, tokens[i]); + name = name.replace(`@{${i}}@`, tokens[i]); + } + + return { + longname: longname, + memberof: memberof, + scope: scopePunc, + name: name, + variation: variation, + }; } /** @@ -231,9 +229,7 @@ function slice(longname, sliceChars, forcedMemberof) { * @param {string} forcedMemberof * @returns {object} Representing the properties of the given name. */ -exports.toParts = (longname, forcedMemberof) => slice( - longname, null, forcedMemberof -); +exports.toParts = (longname, forcedMemberof) => slice(longname, null, forcedMemberof); // TODO: docs /** @@ -242,16 +238,16 @@ exports.toParts = (longname, forcedMemberof) => slice( * @returns {string} The longname with the namespace applied. */ exports.applyNamespace = (longname, ns) => { - const nameParts = slice(longname); - const name = nameParts.name; + const nameParts = slice(longname); + const name = nameParts.name; - longname = nameParts.longname; + longname = nameParts.longname; - if (!/^[a-zA-Z]+?:.+$/i.test(name)) { - longname = longname.replace(new RegExp(`${escape(name)}$`), `${ns}:${name}`); - } + if (!/^[a-zA-Z]+?:.+$/i.test(name)) { + longname = longname.replace(new RegExp(`${escape(name)}$`), `${ns}:${name}`); + } - return longname; + return longname; }; /** @@ -262,70 +258,66 @@ exports.applyNamespace = (longname, ns) => { * @return {boolean} `true` if the parent is an ancestor of the child; otherwise, `false`. */ exports.hasAncestor = (parent, child) => { - let hasAncestor = false; - let memberof = child; - - if (!parent || !child) { - return hasAncestor; - } - - // Fast path for obvious non-ancestors. - if (child.indexOf(parent) !== 0) { - return hasAncestor; - } - - do { - memberof = slice(memberof).memberof; - - if (memberof === parent) { - hasAncestor = true; - } - } while (!hasAncestor && memberof); + let hasAncestor = false; + let memberof = child; + if (!parent || !child) { return hasAncestor; + } + + // Fast path for obvious non-ancestors. + if (child.indexOf(parent) !== 0) { + return hasAncestor; + } + + do { + memberof = slice(memberof).memberof; + + if (memberof === parent) { + hasAncestor = true; + } + } while (!hasAncestor && memberof); + + return hasAncestor; }; // TODO: docs -const fromParts = exports.fromParts = ({memberof, scope, name, variation}) => [ - (memberof || ''), - (scope || ''), - (name || ''), - (variation ? `(${variation})` : '') -].join(''); +const fromParts = (exports.fromParts = ({ memberof, scope, name, variation }) => + [memberof || '', scope || '', name || '', variation ? `(${variation})` : ''].join('')); // TODO: docs -exports.stripVariation = name => { - const parts = slice(name); +exports.stripVariation = (name) => { + const parts = slice(name); - parts.variation = ''; + parts.variation = ''; - return fromParts(parts); + return fromParts(parts); }; function splitLongname(longname, options) { - const chunks = []; - let currentNameInfo; - const nameInfo = {}; - let previousName = longname; - const splitters = SCOPE_PUNC.concat('/'); + const chunks = []; + let currentNameInfo; + const nameInfo = {}; + let previousName = longname; + const splitters = SCOPE_PUNC.concat('/'); - options = _.defaults(options || {}, { - includeVariation: true - }); + options = _.defaults(options || {}, { + includeVariation: true, + }); - do { - if (!options.includeVariation) { - previousName = exports.stripVariation(previousName); - } - currentNameInfo = nameInfo[previousName] = slice(previousName, splitters); - previousName = currentNameInfo.memberof; - chunks.push(currentNameInfo.scope + currentNameInfo.name); - } while (previousName); + do { + if (!options.includeVariation) { + previousName = exports.stripVariation(previousName); + } + currentNameInfo = nameInfo[previousName] = slice(previousName, splitters); + previousName = currentNameInfo.memberof; + chunks.push(currentNameInfo.scope + currentNameInfo.name); + } while (previousName); - return { - chunks: chunks.reverse(), - nameInfo: nameInfo - }; + return { + chunks: chunks.reverse(), + nameInfo: nameInfo, + }; } /** @@ -411,43 +403,43 @@ function splitLongname(longname, options) { * @return {Object} A tree with information about each longname in the format shown above. */ exports.longnamesToTree = (longnames, doclets) => { - const splitOptions = { includeVariation: false }; - const tree = {}; + const splitOptions = { includeVariation: false }; + const tree = {}; - longnames.forEach(longname => { - let currentLongname = ''; - let currentParent = tree; - let nameInfo; - let processed; + longnames.forEach((longname) => { + let currentLongname = ''; + let currentParent = tree; + let nameInfo; + let processed; - // Don't try to add empty longnames to the tree. - if (!longname) { - return; - } + // Don't try to add empty longnames to the tree. + if (!longname) { + return; + } - processed = splitLongname(longname, splitOptions); - nameInfo = processed.nameInfo; + processed = splitLongname(longname, splitOptions); + nameInfo = processed.nameInfo; - processed.chunks.forEach(chunk => { - currentLongname += chunk; + processed.chunks.forEach((chunk) => { + currentLongname += chunk; - if (currentParent !== tree) { - currentParent.children = currentParent.children || {}; - currentParent = currentParent.children; - } + if (currentParent !== tree) { + currentParent.children = currentParent.children || {}; + currentParent = currentParent.children; + } - if (!hasOwnProp.call(currentParent, chunk)) { - currentParent[chunk] = nameInfo[currentLongname]; - } + if (!hasOwnProp.call(currentParent, chunk)) { + currentParent[chunk] = nameInfo[currentLongname]; + } - if (currentParent[chunk]) { - currentParent[chunk].doclet = doclets ? doclets[currentLongname] : null; - currentParent = currentParent[chunk]; - } - }); + if (currentParent[chunk]) { + currentParent[chunk].doclet = doclets ? doclets[currentLongname] : null; + currentParent = currentParent[chunk]; + } }); + }); - return tree; + return tree; }; /** @@ -459,69 +451,68 @@ exports.longnamesToTree = (longnames, doclets) => { * @returns {?Object} Hash with "name" and "description" properties. */ function splitNameMatchingBrackets(nameDesc) { - const buffer = []; - let c; - let stack = 0; - let stringEnd = null; + const buffer = []; + let c; + let stack = 0; + let stringEnd = null; - for (var i = 0; i < nameDesc.length; ++i) { - c = nameDesc[i]; - buffer.push(c); + for (var i = 0; i < nameDesc.length; ++i) { + c = nameDesc[i]; + buffer.push(c); - if (stringEnd) { - if (c === '\\' && i + 1 < nameDesc.length) { - buffer.push(nameDesc[++i]); - } else if (c === stringEnd) { - stringEnd = null; - } - } else if (c === '"' || c === "'") { - stringEnd = c; - } else if (c === '[') { - ++stack; - } else if (c === ']') { - if (--stack === 0) { - break; - } - } + if (stringEnd) { + if (c === '\\' && i + 1 < nameDesc.length) { + buffer.push(nameDesc[++i]); + } else if (c === stringEnd) { + stringEnd = null; + } + } else if (c === '"' || c === "'") { + stringEnd = c; + } else if (c === '[') { + ++stack; + } else if (c === ']') { + if (--stack === 0) { + break; + } } + } - if (stack || stringEnd) { - return null; - } + if (stack || stringEnd) { + return null; + } - nameDesc.substr(i).match(REGEXP_DESCRIPTION); + nameDesc.substr(i).match(REGEXP_DESCRIPTION); - return { - name: buffer.join(''), - description: RegExp.$1 - }; + return { + name: buffer.join(''), + description: RegExp.$1, + }; } - /** * Split a string that starts with a name and ends with a description into separate parts. * @param {string} str - The string that contains the name and description. * @returns {object} An object with `name` and `description` properties. */ -exports.splitNameAndDescription = str => { - // Like: `name`, `[name]`, `name text`, `[name] text`, `name - text`, or `[name] - text`. - // To ensure that we don't get confused by leading dashes in Markdown list items, the hyphen - // must be on the same line as the name. +exports.splitNameAndDescription = (str) => { + // Like: `name`, `[name]`, `name text`, `[name] text`, `name - text`, or `[name] - text`. + // To ensure that we don't get confused by leading dashes in Markdown list items, the hyphen + // must be on the same line as the name. - // Optional values get special treatment, - let result = null; + // Optional values get special treatment, + let result = null; - if (str[0] === '[') { - result = splitNameMatchingBrackets(str); - if (result !== null) { - return result; - } + if (str[0] === '[') { + result = splitNameMatchingBrackets(str); + if (result !== null) { + return result; } + } - str.match(REGEXP_NAME_DESCRIPTION); + str.match(REGEXP_NAME_DESCRIPTION); - return { - name: RegExp.$1, - description: RegExp.$2 - }; + return { + name: RegExp.$1, + description: RegExp.$2, + }; }; diff --git a/packages/jsdoc-core/package-lock.json b/packages/jsdoc-core/package-lock.json index db14d297..27c1154a 100644 --- a/packages/jsdoc-core/package-lock.json +++ b/packages/jsdoc-core/package-lock.json @@ -1,8 +1,279 @@ { "name": "@jsdoc/core", "version": "0.4.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@jsdoc/core", + "version": "0.4.0", + "license": "Apache-2.0", + "dependencies": { + "cosmiconfig": "^7.0.1", + "escape-string-regexp": "^4.0.0", + "lodash": "^4.17.21", + "strip-bom": "^4.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": ">=v14.17.6" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", + "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.14.5", diff --git a/packages/jsdoc-core/test/specs/index.js b/packages/jsdoc-core/test/specs/index.js index ed289221..2dafb8fb 100644 --- a/packages/jsdoc-core/test/specs/index.js +++ b/packages/jsdoc-core/test/specs/index.js @@ -1,23 +1,23 @@ const core = require('../../index'); describe('@jsdoc/core', () => { - it('is an object', () => { - expect(core).toBeObject(); + it('is an object', () => { + expect(core).toBeObject(); + }); + + describe('config', () => { + it('is lib/config', () => { + const config = require('../../lib/config'); + + expect(core.config).toBe(config); }); + }); - describe('config', () => { - it('is lib/config', () => { - const config = require('../../lib/config'); + describe('name', () => { + it('is lib/name', () => { + const name = require('../../lib/name'); - expect(core.config).toBe(config); - }); - }); - - describe('name', () => { - it('is lib/name', () => { - const name = require('../../lib/name'); - - expect(core.name).toBe(name); - }); + expect(core.name).toBe(name); }); + }); }); diff --git a/packages/jsdoc-core/test/specs/lib/config.js b/packages/jsdoc-core/test/specs/lib/config.js index 450a40b2..36a28c58 100644 --- a/packages/jsdoc-core/test/specs/lib/config.js +++ b/packages/jsdoc-core/test/specs/lib/config.js @@ -2,189 +2,189 @@ const mockFs = require('mock-fs'); const config = require('../../../lib/config'); describe('@jsdoc/core/lib/config', () => { - // Explicitly require `yaml` before we run any tests. `cosmiconfig` tries to load `yaml` lazily, - // but that doesn't work when the file system is mocked. - beforeAll(() => require('yaml')); + // Explicitly require `yaml` before we run any tests. `cosmiconfig` tries to load `yaml` lazily, + // but that doesn't work when the file system is mocked. + beforeAll(() => require('yaml')); - afterEach(() => mockFs.restore()); + afterEach(() => mockFs.restore()); + + it('is an object', () => { + expect(config).toBeObject(); + }); + + describe('loadSync', () => { + it('is a function', () => { + expect(config.loadSync).toBeFunction(); + }); + + it('returns an object with `config` and `filepath` properties', () => { + mockFs({ + 'conf.json': '{}', + }); + + const conf = config.loadSync('conf.json'); + + expect(conf.config).toBeObject(); + expect(conf.filepath).toEndWith('conf.json'); + }); + + it('loads settings from the specified filepath if there is one', () => { + mockFs({ + 'conf.json': '{"foo":"bar"}', + }); + + const conf = config.loadSync('conf.json'); + + expect(conf.config.foo).toBe('bar'); + }); + + it('finds the config file when no filepath is specified', () => { + mockFs({ + 'package.json': '{"jsdoc":{"foo":"bar"}}', + }); + + const conf = config.loadSync(); + + expect(conf.config.foo).toBe('bar'); + }); + + it('parses JSON config files that have an extension and contain comments', () => { + mockFs({ + '.jsdocrc.json': '// comment\n{"foo":"bar"}', + }); + + const conf = config.loadSync(); + + expect(conf.config.foo).toBe('bar'); + }); + + it('parses JSON files that start with a BOM', () => { + mockFs({ + '.jsdocrc.json': '\uFEFF{"foo":"bar"}', + }); + + const conf = config.loadSync(); + + expect(conf.config.foo).toBe('bar'); + }); + + it('parses YAML files that start with a BOM', () => { + mockFs({ + '.jsdocrc.yaml': '\uFEFF{"foo":"bar"}', + }); + + const conf = config.loadSync(); + + expect(conf.config.foo).toBe('bar'); + }); + + it('provides the default config if the user config is an empty object', () => { + mockFs({ + '.jsdocrc.json': '{}', + }); + + const conf = config.loadSync(); + + expect(conf.config).toEqual(config.defaults); + }); + + it('provides the default config if there is no user config', () => { + const conf = config.loadSync(); + + expect(conf.config).toEqual(config.defaults); + }); + + it('merges nested defaults with nested user settings as expected', () => { + mockFs({ + '.jsdocrc.json': '{"tags":{"foo":"bar"}}', + }); + + const conf = config.loadSync(); + + expect(conf.config.tags.allowUnknownTags).toBe(config.defaults.tags.allowUnknownTags); + expect(conf.config.tags.foo).toBe('bar'); + }); + }); + + describe('defaults', () => { + const { defaults } = config; it('is an object', () => { - expect(config).toBeObject(); + expect(defaults).toBeObject(); }); - describe('loadSync', () => { - it('is a function', () => { - expect(config.loadSync).toBeFunction(); - }); - - it('returns an object with `config` and `filepath` properties', () => { - mockFs({ - 'conf.json': '{}' - }); - - const conf = config.loadSync('conf.json'); - - expect(conf.config).toBeObject(); - expect(conf.filepath).toEndWith('conf.json'); - }); - - it('loads settings from the specified filepath if there is one', () => { - mockFs({ - 'conf.json': '{"foo":"bar"}' - }); - - const conf = config.loadSync('conf.json'); - - expect(conf.config.foo).toBe('bar'); - }); - - it('finds the config file when no filepath is specified', () => { - mockFs({ - 'package.json': '{"jsdoc":{"foo":"bar"}}' - }); - - const conf = config.loadSync(); - - expect(conf.config.foo).toBe('bar'); - }); - - it('parses JSON config files that have an extension and contain comments', () => { - mockFs({ - '.jsdocrc.json': '// comment\n{"foo":"bar"}' - }); - - const conf = config.loadSync(); - - expect(conf.config.foo).toBe('bar'); - }); - - it('parses JSON files that start with a BOM', () => { - mockFs({ - '.jsdocrc.json': '\uFEFF{"foo":"bar"}' - }); - - const conf = config.loadSync(); - - expect(conf.config.foo).toBe('bar'); - }); - - it('parses YAML files that start with a BOM', () => { - mockFs({ - '.jsdocrc.yaml': '\uFEFF{"foo":"bar"}' - }); - - const conf = config.loadSync(); - - expect(conf.config.foo).toBe('bar'); - }); - - it('provides the default config if the user config is an empty object', () => { - mockFs({ - '.jsdocrc.json': '{}' - }); - - const conf = config.loadSync(); - - expect(conf.config).toEqual(config.defaults); - }); - - it('provides the default config if there is no user config', () => { - const conf = config.loadSync(); - - expect(conf.config).toEqual(config.defaults); - }); - - it('merges nested defaults with nested user settings as expected', () => { - mockFs({ - '.jsdocrc.json': '{"tags":{"foo":"bar"}}' - }); - - const conf = config.loadSync(); - - expect(conf.config.tags.allowUnknownTags).toBe(config.defaults.tags.allowUnknownTags); - expect(conf.config.tags.foo).toBe('bar'); - }); + describe('plugins', () => { + it('is an array', () => { + expect(defaults.plugins).toBeArray(); + }); }); - describe('defaults', () => { - const { defaults } = config; + describe('source', () => { + it('is an object', () => { + expect(defaults.source).toBeObject(); + }); + describe('excludePattern', () => { + it('is a string', () => { + expect(defaults.source.excludePattern).toBeString(); + }); + + it('represents a valid regexp', () => { + expect(() => new RegExp(defaults.source.excludePattern)).not.toThrow(); + }); + }); + + describe('includePattern', () => { + it('is a string', () => { + expect(defaults.source.includePattern).toBeString(); + }); + + it('represents a valid regexp', () => { + expect(() => new RegExp(defaults.source.includePattern)).not.toThrow(); + }); + }); + + describe('type', () => { + it('is a string', () => { + expect(defaults.source.type).toBeString(); + }); + }); + + describe('tags', () => { it('is an object', () => { - expect(defaults).toBeObject(); + expect(defaults.tags).toBeObject(); }); - describe('plugins', () => { - it('is an array', () => { - expect(defaults.plugins).toBeArray(); - }); + describe('allowUnknownTags', () => { + it('is a boolean', () => { + expect(defaults.tags.allowUnknownTags).toBeBoolean(); + }); }); - describe('source', () => { - it('is an object', () => { - expect(defaults.source).toBeObject(); - }); - - describe('excludePattern', () => { - it('is a string', () => { - expect(defaults.source.excludePattern).toBeString(); - }); - - it('represents a valid regexp', () => { - expect(() => new RegExp(defaults.source.excludePattern)).not.toThrow(); - }); - }); - - describe('includePattern', () => { - it('is a string', () => { - expect(defaults.source.includePattern).toBeString(); - }); - - it('represents a valid regexp', () => { - expect(() => new RegExp(defaults.source.includePattern)).not.toThrow(); - }); - }); - - describe('type', () => { - it('is a string', () => { - expect(defaults.source.type).toBeString(); - }); - }); - - describe('tags', () => { - it('is an object', () => { - expect(defaults.tags).toBeObject(); - }); - - describe('allowUnknownTags', () => { - it('is a boolean', () => { - expect(defaults.tags.allowUnknownTags).toBeBoolean(); - }); - }); - - describe('dictionaries', () => { - it('is an array of strings', () => { - expect(defaults.tags.dictionaries).toBeArrayOfStrings(); - }); - }); - }); - - describe('templates', () => { - it('is an object', () => { - expect(defaults.templates).toBeObject(); - }); - - describe('cleverLinks', () => { - it('is a boolean', () => { - expect(defaults.templates.cleverLinks).toBeBoolean(); - }); - }); - - describe('monospaceLinks', () => { - it('is a boolean', () => { - expect(defaults.templates.monospaceLinks).toBeBoolean(); - }); - }); - }); + describe('dictionaries', () => { + it('is an array of strings', () => { + expect(defaults.tags.dictionaries).toBeArrayOfStrings(); + }); }); + }); + + describe('templates', () => { + it('is an object', () => { + expect(defaults.templates).toBeObject(); + }); + + describe('cleverLinks', () => { + it('is a boolean', () => { + expect(defaults.templates.cleverLinks).toBeBoolean(); + }); + }); + + describe('monospaceLinks', () => { + it('is a boolean', () => { + expect(defaults.templates.monospaceLinks).toBeBoolean(); + }); + }); + }); }); + }); }); diff --git a/packages/jsdoc-core/test/specs/lib/name.js b/packages/jsdoc-core/test/specs/lib/name.js index dc730991..bddda3e8 100644 --- a/packages/jsdoc-core/test/specs/lib/name.js +++ b/packages/jsdoc-core/test/specs/lib/name.js @@ -1,439 +1,434 @@ describe('@jsdoc/core.name', () => { - const { name } = require('@jsdoc/core'); + const { name } = require('@jsdoc/core'); - it('exists', () => { - expect(name).toBeObject(); + it('exists', () => { + expect(name).toBeObject(); + }); + + it('has an applyNamespace method', () => { + expect(name.applyNamespace).toBeFunction(); + }); + + it('has a fromParts method', () => { + expect(name.fromParts).toBeFunction(); + }); + + it('has a getBasename method', () => { + expect(name.getBasename).toBeFunction(); + }); + + it('has a hasAncestor method', () => { + expect(name.hasAncestor).toBeFunction(); + }); + + it('has a hasLeadingScope method', () => { + expect(name.hasLeadingScope).toBeFunction(); + }); + + it('has a hasTrailingScope method', () => { + expect(name.hasTrailingScope).toBeFunction(); + }); + + it('has a LONGNAMES enum', () => { + expect(name.LONGNAMES).toBeObject(); + }); + + it('has a longnamesToTree method', () => { + expect(name.longnamesToTree).toBeFunction(); + }); + + it('has a MODULE_NAMESPACE property', () => { + expect(name.MODULE_NAMESPACE).toBeString(); + }); + + it('has a nameIsLongname method', () => { + expect(name.nameIsLongname).toBeFunction(); + }); + + it('has a prototypeToPunc method', () => { + expect(name.prototypeToPunc).toBeFunction(); + }); + + it('has a PUNC_TO_SCOPE enum', () => { + expect(name.PUNC_TO_SCOPE).toBeObject(); + }); + + it('has a SCOPE enum', () => { + expect(name.SCOPE).toBeObject(); + }); + + it('has a SCOPE_TO_PUNC enum', () => { + expect(name.SCOPE_TO_PUNC).toBeObject(); + }); + + it('has a splitNameAndDescription method', () => { + expect(name.splitNameAndDescription).toBeFunction(); + }); + + it('has a stripNamespace method', () => { + expect(name.stripNamespace).toBeFunction(); + }); + + it('has a stripVariation method', () => { + expect(name.stripVariation).toBeFunction(); + }); + + it('has a toParts method', () => { + expect(name.toParts).toBeFunction(); + }); + + describe('applyNamespace', () => { + it('applies the namespace to the name part of the longname', () => { + expect(name.applyNamespace('lib.Panel#open', 'event')).toBe('lib.Panel#event:open'); }); - it('has an applyNamespace method', () => { - expect(name.applyNamespace).toBeFunction(); + it('applies the namespace to the start of a top-level longname', () => { + expect(name.applyNamespace('math/bigint', 'module')).toBe('module:math/bigint'); }); - it('has a fromParts method', () => { - expect(name.fromParts).toBeFunction(); + // TODO(hegemonic): This has never worked + xit('handles longnames with quoted portions', () => { + expect(name.applyNamespace('foo."*don\'t.look~in#here!"', 'event')).toBe( + 'foo.event:"*don\'t.look~in#here!"' + ); }); - it('has a getBasename method', () => { - expect(name.getBasename).toBeFunction(); + it('handles longnames that already have namespaces', () => { + expect(name.applyNamespace('lib.Panel#event:open', 'event')).toBe('lib.Panel#event:open'); + }); + }); + + xdescribe('fromParts', () => { + // TODO: tests + }); + + describe('getBasename', () => { + it('returns null on empty input', () => { + expect(name.getBasename()).toBeNull(); }); - it('has a hasAncestor method', () => { - expect(name.hasAncestor).toBeFunction(); + it('returns the original value if it has no punctuation except underscores', () => { + expect(name.getBasename('foo_bar')).toBe('foo_bar'); }); - it('has a hasLeadingScope method', () => { - expect(name.hasLeadingScope).toBeFunction(); + it('returns the basename if the original value has punctuation', () => { + expect(name.getBasename('foo.Bar#baz')).toBe('foo'); + }); + }); + + describe('hasAncestor', () => { + it('returns false if no parent is specified', () => { + expect(name.hasAncestor(null, 'foo')).toBe(false); }); - it('has a hasTrailingScope method', () => { - expect(name.hasTrailingScope).toBeFunction(); + it('returns false if no child is specified', () => { + expect(name.hasAncestor('foo')).toBe(false); }); - it('has a LONGNAMES enum', () => { - expect(name.LONGNAMES).toBeObject(); + it('returns true when the ancestor is the immediate parent', () => { + expect(name.hasAncestor('module:foo', 'module:foo~bar')).toBe(true); }); - it('has a longnamesToTree method', () => { - expect(name.longnamesToTree).toBeFunction(); + it('returns true when the ancestor is not the immediate parent', () => { + expect(name.hasAncestor('module:foo', 'module:foo~bar.Baz#qux')).toBe(true); }); - it('has a MODULE_NAMESPACE property', () => { - expect(name.MODULE_NAMESPACE).toBeString(); + it('returns false when a non-ancestor is passed in', () => { + expect(name.hasAncestor('module:foo', 'foo')).toBe(false); }); - it('has a nameIsLongname method', () => { - expect(name.nameIsLongname).toBeFunction(); + it('returns false if the parent and child are the same', () => { + expect(name.hasAncestor('module:foo', 'module:foo')).toBe(false); + }); + }); + + describe('hasLeadingScope', () => { + it('returns true if the string starts with a scope character', () => { + expect(name.hasLeadingScope('#foo')).toBeTrue(); }); - it('has a prototypeToPunc method', () => { - expect(name.prototypeToPunc).toBeFunction(); + it('returns false if the string does not start with a scope character', () => { + expect(name.hasLeadingScope('!foo')).toBeFalse(); + }); + }); + + describe('hasTrailingScope', () => { + it('returns true if the string ends with a scope character', () => { + expect(name.hasTrailingScope('Foo#')).toBeTrue(); }); - it('has a PUNC_TO_SCOPE enum', () => { - expect(name.PUNC_TO_SCOPE).toBeObject(); + it('returns false if the string does not end with a scope character', () => { + expect(name.hasTrailingScope('Foo!')).toBeFalse(); + }); + }); + + describe('LONGNAMES', () => { + it('has an ANONYMOUS property', () => { + expect(name.LONGNAMES.ANONYMOUS).toBeString(); }); - it('has a SCOPE enum', () => { - expect(name.SCOPE).toBeObject(); + it('has a GLOBAL property', () => { + expect(name.LONGNAMES.GLOBAL).toBeString(); + }); + }); + + xdescribe('longnamesToTree', () => { + // TODO: tests + }); + + describe('MODULE_NAMESPACE', () => { + // This is just a string, so nothing to test. + }); + + xdescribe('nameIsLongname', () => { + // TODO(hegemonic) + }); + + xdescribe('prototypeToPunc', () => { + // TODO(hegemonic) + }); + + describe('PUNC_TO_SCOPE', () => { + it('has the same number of properties as SCOPE_TO_PUNC', () => { + expect(Object.keys(name.PUNC_TO_SCOPE).length).toBe(Object.keys(name.SCOPE_TO_PUNC).length); + }); + }); + + describe('SCOPE', () => { + const SCOPE = name.SCOPE; + + it('has a NAMES enum', () => { + expect(SCOPE.NAMES).toBeObject(); }); - it('has a SCOPE_TO_PUNC enum', () => { - expect(name.SCOPE_TO_PUNC).toBeObject(); + it('has a PUNC enum', () => { + expect(SCOPE.PUNC).toBeObject(); }); - it('has a splitNameAndDescription method', () => { - expect(name.splitNameAndDescription).toBeFunction(); + describe('NAMES', () => { + it('has a GLOBAL property', () => { + expect(SCOPE.NAMES.GLOBAL).toBeString(); + }); + + it('has an INNER property', () => { + expect(SCOPE.NAMES.INNER).toBeString(); + }); + + it('has an INSTANCE property', () => { + expect(SCOPE.NAMES.INSTANCE).toBeString(); + }); + + it('has a STATIC property', () => { + expect(SCOPE.NAMES.STATIC).toBeString(); + }); }); - it('has a stripNamespace method', () => { - expect(name.stripNamespace).toBeFunction(); + describe('PUNC', () => { + it('has an INNER property', () => { + expect(SCOPE.PUNC.INNER).toBeString(); + }); + + it('has an INSTANCE property', () => { + expect(SCOPE.PUNC.INSTANCE).toBeString(); + }); + + it('has a STATIC property', () => { + expect(SCOPE.PUNC.STATIC).toBeString(); + }); + }); + }); + + describe('SCOPE_TO_PUNC', () => { + it('has an inner property', () => { + expect(name.SCOPE_TO_PUNC.inner).toBeString(); }); - it('has a stripVariation method', () => { - expect(name.stripVariation).toBeFunction(); + it('has an instance property', () => { + expect(name.SCOPE_TO_PUNC.instance).toBeString(); }); - it('has a toParts method', () => { - expect(name.toParts).toBeFunction(); + it('has a static property', () => { + expect(name.SCOPE_TO_PUNC.static).toBeString(); + }); + }); + + describe('splitNameAndDescription', () => { + // TODO(hegemonic): This has never worked + xit('separates the name from the description', () => { + const parts = name.splitNameAndDescription( + 'ns.Page#"last \\"sentence\\"".words~sort(2) - This is a description. ' + ); + + expect(parts.name).toBe('ns.Page#"last \\"sentence\\"".words~sort(2)'); + expect(parts.description).toBe('This is a description.'); }); - describe('applyNamespace', () => { - it('applies the namespace to the name part of the longname', () => { - expect(name.applyNamespace('lib.Panel#open', 'event')).toBe('lib.Panel#event:open'); - }); + it('strips a separator when it starts on the same line as the name', () => { + const parts = name.splitNameAndDescription('socket - The networking kind, not the wrench.'); - it('applies the namespace to the start of a top-level longname', () => { - expect(name.applyNamespace('math/bigint', 'module')).toBe('module:math/bigint'); - }); - - // TODO(hegemonic): This has never worked - xit('handles longnames with quoted portions', () => { - expect(name.applyNamespace('foo."*don\'t.look~in#here!"', 'event')) - .toBe('foo.event:"*don\'t.look~in#here!"'); - }); - - it('handles longnames that already have namespaces', () => { - expect(name.applyNamespace('lib.Panel#event:open', 'event')) - .toBe('lib.Panel#event:open'); - }); + expect(parts.name).toBe('socket'); + expect(parts.description).toBe('The networking kind, not the wrench.'); }); - xdescribe('fromParts', () => { - // TODO: tests + it('does not strip a separator that is preceded by a line break', () => { + const parts = name.splitNameAndDescription('socket\n - The networking kind, not the wrench.'); + + expect(parts.name).toBe('socket'); + expect(parts.description).toBe('- The networking kind, not the wrench.'); }); - describe('getBasename', () => { - it('returns null on empty input', () => { - expect(name.getBasename()).toBeNull(); - }); + it('allows default values to contain square brackets', () => { + const parts = name.splitNameAndDescription( + '[path=["home", "user"]] - Path split into components' + ); - it('returns the original value if it has no punctuation except underscores', () => { - expect(name.getBasename('foo_bar')).toBe('foo_bar'); - }); - - it('returns the basename if the original value has punctuation', () => { - expect(name.getBasename('foo.Bar#baz')).toBe('foo'); - }); + expect(parts.name).toBe('[path=["home", "user"]]'); + expect(parts.description).toBe('Path split into components'); }); - describe('hasAncestor', () => { - it('returns false if no parent is specified', () => { - expect(name.hasAncestor(null, 'foo')).toBe(false); - }); + it('allows default values to contain unmatched square brackets inside strings', () => { + const parts = name.splitNameAndDescription( + '[path=["Unmatched begin: ["]] - Path split into components' + ); - it('returns false if no child is specified', () => { - expect(name.hasAncestor('foo')).toBe(false); - }); - - it('returns true when the ancestor is the immediate parent', () => { - expect(name.hasAncestor('module:foo', 'module:foo~bar')).toBe(true); - }); - - it('returns true when the ancestor is not the immediate parent', () => { - expect(name.hasAncestor('module:foo', 'module:foo~bar.Baz#qux')).toBe(true); - }); - - it('returns false when a non-ancestor is passed in', () => { - expect(name.hasAncestor('module:foo', 'foo')).toBe(false); - }); - - it('returns false if the parent and child are the same', () => { - expect(name.hasAncestor('module:foo', 'module:foo')).toBe(false); - }); + expect(parts.name).toBe('[path=["Unmatched begin: ["]]'); + expect(parts.description).toBe('Path split into components'); }); - describe('hasLeadingScope', () => { - it('returns true if the string starts with a scope character', () => { - expect(name.hasLeadingScope('#foo')).toBeTrue(); - }); + it('fails gracefully when the default value has an unmatched square bracket', () => { + const parts = name.splitNameAndDescription( + '[path=["home", "user"] - Path split into components' + ); - it('returns false if the string does not start with a scope character', () => { - expect(name.hasLeadingScope('!foo')).toBeFalse(); - }); + expect(parts).toBeObject(); + expect(parts.name).toBe('[path=["home", "user"]'); + expect(parts.description).toBe('Path split into components'); }); - describe('hasTrailingScope', () => { - it('returns true if the string ends with a scope character', () => { - expect(name.hasTrailingScope('Foo#')).toBeTrue(); - }); + it('fails gracefully when the default value has an unmatched quote', () => { + const parts = name.splitNameAndDescription( + '[path=["home", "user] - Path split into components' + ); - it('returns false if the string does not end with a scope character', () => { - expect(name.hasTrailingScope('Foo!')).toBeFalse(); - }); + expect(parts).toBeObject(); + expect(parts.name).toBe('[path=["home", "user]'); + expect(parts.description).toBe('Path split into components'); + }); + }); + + describe('stripNamespace', () => { + it('removes the namespace from the longname', () => { + expect(name.stripNamespace('module:foo/bar/baz')).toBe('foo/bar/baz'); }); - describe('LONGNAMES', () => { - it('has an ANONYMOUS property', () => { - expect(name.LONGNAMES.ANONYMOUS).toBeString(); - }); - - it('has a GLOBAL property', () => { - expect(name.LONGNAMES.GLOBAL).toBeString(); - }); + it('does not remove the namespace from a child member', () => { + expect(name.stripNamespace('foo/bar.baz~event:qux')).toBe('foo/bar.baz~event:qux'); }); - xdescribe('longnamesToTree', () => { - // TODO: tests + it('does not change longnames that do not have a namespace', () => { + expect(name.stripNamespace('Foo#bar')).toBe('Foo#bar'); + }); + }); + + describe('stripVariation', () => { + it('does not change longnames with no variation', () => { + expect(name.stripVariation('Foo#bar')).toBe('Foo#bar'); }); - describe('MODULE_NAMESPACE', () => { - // This is just a string, so nothing to test. + it('removes the variation if present', () => { + expect(name.stripVariation('Foo#bar(qux)')).toBe('Foo#bar'); + }); + }); + + describe('toParts', () => { + it('breaks up a longname into the correct parts', () => { + const parts = name.toParts('lib.Panel#open'); + + expect(parts.name).toBe('open'); + expect(parts.memberof).toBe('lib.Panel'); + expect(parts.scope).toBe('#'); }); - xdescribe('nameIsLongname', () => { - // TODO(hegemonic) + it('handles static names', () => { + const parts = name.toParts('elements.selected.getVisible'); + + expect(parts.name).toBe('getVisible'); + expect(parts.memberof).toBe('elements.selected'); + expect(parts.scope).toBe('.'); }); - xdescribe('prototypeToPunc', () => { - // TODO(hegemonic) + it('handles members of a prototype', () => { + const parts = name.toParts('Validator.prototype.$element'); + + expect(parts.name).toEqual('$element'); + expect(parts.memberof).toEqual('Validator'); + expect(parts.scope).toEqual('#'); }); - describe('PUNC_TO_SCOPE', () => { - it('has the same number of properties as SCOPE_TO_PUNC', () => { - expect(Object.keys(name.PUNC_TO_SCOPE).length) - .toBe(Object.keys(name.SCOPE_TO_PUNC).length); - }); + it('handles inner names', () => { + const parts = name.toParts('Button~_onclick'); + + expect(parts.name).toEqual('_onclick'); + expect(parts.memberof).toEqual('Button'); + expect(parts.scope).toEqual('~'); }); - describe('SCOPE', () => { - const SCOPE = name.SCOPE; + it('handles global names', () => { + const parts = name.toParts('close'); - it('has a NAMES enum', () => { - expect(SCOPE.NAMES).toBeObject(); - }); - - it('has a PUNC enum', () => { - expect(SCOPE.PUNC).toBeObject(); - }); - - describe('NAMES', () => { - it('has a GLOBAL property', () => { - expect(SCOPE.NAMES.GLOBAL).toBeString(); - }); - - it('has an INNER property', () => { - expect(SCOPE.NAMES.INNER).toBeString(); - }); - - it('has an INSTANCE property', () => { - expect(SCOPE.NAMES.INSTANCE).toBeString(); - }); - - it('has a STATIC property', () => { - expect(SCOPE.NAMES.STATIC).toBeString(); - }); - }); - - describe('PUNC', () => { - it('has an INNER property', () => { - expect(SCOPE.PUNC.INNER).toBeString(); - }); - - it('has an INSTANCE property', () => { - expect(SCOPE.PUNC.INSTANCE).toBeString(); - }); - - it('has a STATIC property', () => { - expect(SCOPE.PUNC.STATIC).toBeString(); - }); - }); + expect(parts.name).toEqual('close'); + expect(parts.memberof).toEqual(''); + expect(parts.scope).toEqual(''); }); - describe('SCOPE_TO_PUNC', () => { - it('has an inner property', () => { - expect(name.SCOPE_TO_PUNC.inner).toBeString(); - }); + it('handles a single property that uses bracket notation', () => { + const parts = name.toParts('channels["#ops"]#open'); - it('has an instance property', () => { - expect(name.SCOPE_TO_PUNC.instance).toBeString(); - }); - - it('has a static property', () => { - expect(name.SCOPE_TO_PUNC.static).toBeString(); - }); + expect(parts.name).toEqual('open'); + expect(parts.memberof).toEqual('channels."#ops"'); + expect(parts.scope).toEqual('#'); }); - describe('splitNameAndDescription', () => { - // TODO(hegemonic): This has never worked - xit('separates the name from the description', () => { - const parts = name.splitNameAndDescription( - 'ns.Page#"last \\"sentence\\"".words~sort(2) - This is a description. ' - ); + it('handles consecutive properties that use bracket notation', () => { + const parts = name.toParts('channels["#bots"]["log.max"]'); - expect(parts.name).toBe('ns.Page#"last \\"sentence\\"".words~sort(2)'); - expect(parts.description).toBe('This is a description.'); - }); - - it('strips a separator when it starts on the same line as the name', () => { - const parts = name.splitNameAndDescription( - 'socket - The networking kind, not the wrench.' - ); - - expect(parts.name).toBe('socket'); - expect(parts.description).toBe('The networking kind, not the wrench.'); - }); - - it('does not strip a separator that is preceded by a line break', () => { - const parts = name.splitNameAndDescription( - 'socket\n - The networking kind, not the wrench.' - ); - - expect(parts.name).toBe('socket'); - expect(parts.description).toBe('- The networking kind, not the wrench.'); - }); - - it('allows default values to contain square brackets', () => { - const parts = name.splitNameAndDescription( - '[path=["home", "user"]] - Path split into components' - ); - - expect(parts.name).toBe('[path=["home", "user"]]'); - expect(parts.description).toBe('Path split into components'); - }); - - it('allows default values to contain unmatched square brackets inside strings', () => { - const parts = name.splitNameAndDescription( - '[path=["Unmatched begin: ["]] - Path split into components' - ); - - expect(parts.name).toBe('[path=["Unmatched begin: ["]]'); - expect(parts.description).toBe('Path split into components'); - }); - - it('fails gracefully when the default value has an unmatched square bracket', () => { - const parts = name.splitNameAndDescription( - '[path=["home", "user"] - Path split into components' - ); - - expect(parts).toBeObject(); - expect(parts.name).toBe('[path=["home", "user"]'); - expect(parts.description).toBe('Path split into components'); - }); - - it('fails gracefully when the default value has an unmatched quote', () => { - const parts = name.splitNameAndDescription( - '[path=["home", "user] - Path split into components' - ); - - expect(parts).toBeObject(); - expect(parts.name).toBe('[path=["home", "user]'); - expect(parts.description).toBe('Path split into components'); - }); + expect(parts.name).toEqual('"log.max"'); + expect(parts.memberof).toEqual('channels."#bots"'); + expect(parts.scope).toEqual('.'); }); - describe('stripNamespace', () => { - it('removes the namespace from the longname', () => { - expect(name.stripNamespace('module:foo/bar/baz')).toBe('foo/bar/baz'); - }); + it('handles a property that uses single-quoted bracket notation', () => { + const parts = name.toParts("channels['#ops']"); - it('does not remove the namespace from a child member', () => { - expect(name.stripNamespace('foo/bar.baz~event:qux')).toBe('foo/bar.baz~event:qux'); - }); - - it('does not change longnames that do not have a namespace', () => { - expect(name.stripNamespace('Foo#bar')).toBe('Foo#bar'); - }); + expect(parts.name).toBe("'#ops'"); + expect(parts.memberof).toBe('channels'); + expect(parts.scope).toBe('.'); }); - describe('stripVariation', () => { - it('does not change longnames with no variation', () => { - expect(name.stripVariation('Foo#bar')).toBe('Foo#bar'); - }); + it('handles double-quoted strings', () => { + const parts = name.toParts('"foo.bar"'); - it('removes the variation if present', () => { - expect(name.stripVariation('Foo#bar(qux)')).toBe('Foo#bar'); - }); + expect(parts.name).toEqual('"foo.bar"'); + expect(parts.longname).toEqual('"foo.bar"'); + expect(parts.memberof).toEqual(''); + expect(parts.scope).toEqual(''); }); - describe('toParts', () => { - it('breaks up a longname into the correct parts', () => { - const parts = name.toParts('lib.Panel#open'); + it('handles single-quoted strings', () => { + const parts = name.toParts("'foo.bar'"); - expect(parts.name).toBe('open'); - expect(parts.memberof).toBe('lib.Panel'); - expect(parts.scope).toBe('#'); - }); - - it('handles static names', () => { - const parts = name.toParts('elements.selected.getVisible'); - - expect(parts.name).toBe('getVisible'); - expect(parts.memberof).toBe('elements.selected'); - expect(parts.scope).toBe('.'); - }); - - it('handles members of a prototype', () => { - const parts = name.toParts('Validator.prototype.$element'); - - expect(parts.name).toEqual('$element'); - expect(parts.memberof).toEqual('Validator'); - expect(parts.scope).toEqual('#'); - }); - - it('handles inner names', () => { - const parts = name.toParts('Button~_onclick'); - - expect(parts.name).toEqual('_onclick'); - expect(parts.memberof).toEqual('Button'); - expect(parts.scope).toEqual('~'); - }); - - it('handles global names', () => { - const parts = name.toParts('close'); - - expect(parts.name).toEqual('close'); - expect(parts.memberof).toEqual(''); - expect(parts.scope).toEqual(''); - }); - - it('handles a single property that uses bracket notation', () => { - const parts = name.toParts('channels["#ops"]#open'); - - expect(parts.name).toEqual('open'); - expect(parts.memberof).toEqual('channels."#ops"'); - expect(parts.scope).toEqual('#'); - }); - - it('handles consecutive properties that use bracket notation', () => { - const parts = name.toParts('channels["#bots"]["log.max"]'); - - expect(parts.name).toEqual('"log.max"'); - expect(parts.memberof).toEqual('channels."#bots"'); - expect(parts.scope).toEqual('.'); - }); - - it('handles a property that uses single-quoted bracket notation', () => { - const parts = name.toParts("channels['#ops']"); - - expect(parts.name).toBe("'#ops'"); - expect(parts.memberof).toBe('channels'); - expect(parts.scope).toBe('.'); - }); - - it('handles double-quoted strings', () => { - const parts = name.toParts('"foo.bar"'); - - expect(parts.name).toEqual('"foo.bar"'); - expect(parts.longname).toEqual('"foo.bar"'); - expect(parts.memberof).toEqual(''); - expect(parts.scope).toEqual(''); - }); - - it('handles single-quoted strings', () => { - const parts = name.toParts("'foo.bar'"); - - expect(parts.name).toBe("'foo.bar'"); - expect(parts.longname).toBe("'foo.bar'"); - expect(parts.memberof).toBe(''); - expect(parts.scope).toBe(''); - }); - - it('handles variations', () => { - const parts = name.toParts('anim.fadein(2)'); - - expect(parts.variation).toEqual('2'); - expect(parts.name).toEqual('fadein'); - expect(parts.longname).toEqual('anim.fadein(2)'); - }); + expect(parts.name).toBe("'foo.bar'"); + expect(parts.longname).toBe("'foo.bar'"); + expect(parts.memberof).toBe(''); + expect(parts.scope).toBe(''); }); + + it('handles variations', () => { + const parts = name.toParts('anim.fadein(2)'); + + expect(parts.variation).toEqual('2'); + expect(parts.name).toEqual('fadein'); + expect(parts.longname).toEqual('anim.fadein(2)'); + }); + }); }); diff --git a/packages/jsdoc-eslint-config/index.js b/packages/jsdoc-eslint-config/index.js index 966b1365..8cfb1203 100644 --- a/packages/jsdoc-eslint-config/index.js +++ b/packages/jsdoc-eslint-config/index.js @@ -1,359 +1,362 @@ module.exports = { - env: { - es6: true, - jasmine: true, - node: true - }, + env: { + es6: true, + jasmine: true, + node: true, + }, - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module' - }, + parserOptions: { + ecmaVersion: 2018, + sourceType: 'module', + }, - rules: { - // Possible errors - 'for-direction': 'error', - 'getter-return': 'error', - 'no-async-promise-executor': 'error', - 'no-await-in-loop': 'error', - 'no-compare-neg-zero': 'error', - 'no-cond-assign': 'error', - 'no-console': 'off', - 'no-constant-condition': 'off', - 'no-control-regex': 'error', - 'no-debugger': 'error', - 'no-dupe-args': 'error', - 'no-dupe-else-if': 'error', - 'no-dupe-keys': 'error', - 'no-duplicate-case': 'error', - 'no-empty': 'error', - 'no-empty-character-class': 'error', - 'no-ex-assign': 'error', - 'no-extra-boolean-cast': 'error', - 'no-extra-parens': 'off', - 'no-extra-semi': 'error', - 'no-func-assign': 'error', - 'no-import-assign': 'error', - 'no-inner-declarations': ['error', 'functions'], - 'no-invalid-regexp': 'error', - 'no-irregular-whitespace': 'error', - 'no-loss-of-precision': 'error', - 'no-misleading-character-class': 'error', - 'no-obj-calls': 'error', - 'no-prototype-builtins': 'error', - 'no-regex-spaces': 'error', - 'no-setter-return': 'error', - 'no-sparse-arrays': 'error', - 'no-template-curly-in-string': 'error', - 'no-unexpected-multiline': 'error', - 'no-unreachable': 'error', - 'no-unreachable-loop': 'error', - 'no-unsafe-finally': 'error', - 'no-unsafe-negation': 'error', - 'no-unsafe-optional-chaining': 'error', - 'no-useless-backreference': 'error', - 'require-atomic-updates': 'error', - 'use-isnan': 'error', - 'valid-typeof': 'error', + rules: { + // Possible errors + 'for-direction': 'error', + 'getter-return': 'error', + 'no-async-promise-executor': 'error', + 'no-await-in-loop': 'error', + 'no-compare-neg-zero': 'error', + 'no-cond-assign': 'error', + 'no-console': 'off', + 'no-constant-condition': 'off', + 'no-control-regex': 'error', + 'no-debugger': 'error', + 'no-dupe-args': 'error', + 'no-dupe-else-if': 'error', + 'no-dupe-keys': 'error', + 'no-duplicate-case': 'error', + 'no-empty': 'error', + 'no-empty-character-class': 'error', + 'no-ex-assign': 'error', + 'no-extra-boolean-cast': 'error', + 'no-extra-parens': 'off', + 'no-extra-semi': 'error', + 'no-func-assign': 'error', + 'no-import-assign': 'error', + 'no-inner-declarations': ['error', 'functions'], + 'no-invalid-regexp': 'error', + 'no-irregular-whitespace': 'error', + 'no-loss-of-precision': 'error', + 'no-misleading-character-class': 'error', + 'no-obj-calls': 'error', + 'no-prototype-builtins': 'error', + 'no-regex-spaces': 'error', + 'no-setter-return': 'error', + 'no-sparse-arrays': 'error', + 'no-template-curly-in-string': 'error', + 'no-unexpected-multiline': 'error', + 'no-unreachable': 'error', + 'no-unreachable-loop': 'error', + 'no-unsafe-finally': 'error', + 'no-unsafe-negation': 'error', + 'no-unsafe-optional-chaining': 'error', + 'no-useless-backreference': 'error', + 'require-atomic-updates': 'error', + 'use-isnan': 'error', + 'valid-typeof': 'error', - // Best practices - 'accessor-pairs': 'error', - 'array-callback-return': 'error', - 'block-scoped-var': 'off', - 'class-methods-use-this': 'off', - complexity: 'off', // TODO: enable - 'consistent-return': 'error', - curly: ['error', 'all'], - 'default-case': 'error', - 'default-case-last': 'error', - 'default-param-last': 'error', - 'dot-location': ['error', 'property'], - 'dot-notation': 'error', - eqeqeq: ['error', 'smart'], - 'grouped-accessor-pairs': 'error', - 'guard-for-in': 'error', - 'max-classes-per-file': 'off', - 'no-alert': 'error', - 'no-caller': 'error', - 'no-case-declarations': 'error', - 'no-constructor-return': 'off', - 'no-div-regex': 'error', - 'no-else-return': 'off', - 'no-empty-function': 'error', - 'no-empty-pattern': 'error', - 'no-eq-null': 'error', - 'no-eval': 'error', - 'no-extend-native': 'error', - 'no-extra-bind': 'error', - 'no-extra-label': 'error', - 'no-fallthrough': 'off', // disabled due to bug in ESLint - 'no-floating-decimal': 'error', - 'no-global-assign': 'error', - 'no-implicit-coercion': 'error', - 'no-implicit-globals': 'error', - 'no-implied-eval': 'error', - 'no-invalid-this': 'error', - 'no-iterator': 'error', - 'no-labels': 'error', - 'no-lone-blocks': 'error', - 'no-loop-func': 'error', - 'no-magic-numbers': 'off', // TODO: enable? - 'no-multi-spaces': 'error', - 'no-multi-str': 'error', - 'no-new': 'error', - 'no-new-func': 'error', - 'no-new-wrappers': 'error', - 'no-nonoctal-decimal-escape': 'error', - 'no-octal': 'error', - 'no-octal-escape': 'error', - 'no-param-reassign': 'off', - 'no-proto': 'error', - 'no-redeclare': 'error', - 'no-restricted-properties': 'off', - 'no-return-assign': 'error', - 'no-return-await': 'error', - 'no-script-url': 'error', - 'no-self-assign': 'error', - 'no-self-compare': 'error', - 'no-sequences': 'error', - 'no-throw-literal': 'error', - 'no-unmodified-loop-condition': 'error', - 'no-unused-expressions': 'error', - 'no-unused-labels': 'error', - 'no-useless-call': 'error', - 'no-useless-catch': 'error', - 'no-useless-concat': 'error', - 'no-useless-escape': 'error', - 'no-useless-return': 'error', - 'no-void': 'error', - 'no-warning-comments': 'off', - 'no-with': 'error', - 'prefer-named-capture-group': 'off', // TODO: enable - 'prefer-promise-reject-errors': 'error', - 'prefer-regex-literals': 'error', - radix: 'error', - 'require-await': 'error', - 'require-unicode-regexp': 'off', - 'vars-on-top': 'off', // TODO: enable - 'wrap-iife': ['error', 'inside'], - yoda: 'error', + // Best practices + 'accessor-pairs': 'error', + 'array-callback-return': 'error', + 'block-scoped-var': 'off', + 'class-methods-use-this': 'off', + complexity: 'off', // TODO: enable + 'consistent-return': 'error', + curly: ['error', 'all'], + 'default-case': 'error', + 'default-case-last': 'error', + 'default-param-last': 'error', + 'dot-location': ['error', 'property'], + 'dot-notation': 'error', + eqeqeq: ['error', 'smart'], + 'grouped-accessor-pairs': 'error', + 'guard-for-in': 'error', + 'max-classes-per-file': 'off', + 'no-alert': 'error', + 'no-caller': 'error', + 'no-case-declarations': 'error', + 'no-constructor-return': 'off', + 'no-div-regex': 'error', + 'no-else-return': 'off', + 'no-empty-function': 'error', + 'no-empty-pattern': 'error', + 'no-eq-null': 'error', + 'no-eval': 'error', + 'no-extend-native': 'error', + 'no-extra-bind': 'error', + 'no-extra-label': 'error', + 'no-fallthrough': 'off', // disabled due to bug in ESLint + 'no-floating-decimal': 'error', + 'no-global-assign': 'error', + 'no-implicit-coercion': 'error', + 'no-implicit-globals': 'error', + 'no-implied-eval': 'error', + 'no-invalid-this': 'error', + 'no-iterator': 'error', + 'no-labels': 'error', + 'no-lone-blocks': 'error', + 'no-loop-func': 'error', + 'no-magic-numbers': 'off', // TODO: enable? + 'no-multi-spaces': 'error', + 'no-multi-str': 'error', + 'no-new': 'error', + 'no-new-func': 'error', + 'no-new-wrappers': 'error', + 'no-nonoctal-decimal-escape': 'error', + 'no-octal': 'error', + 'no-octal-escape': 'error', + 'no-param-reassign': 'off', + 'no-proto': 'error', + 'no-redeclare': 'error', + 'no-restricted-properties': 'off', + 'no-return-assign': 'error', + 'no-return-await': 'error', + 'no-script-url': 'error', + 'no-self-assign': 'error', + 'no-self-compare': 'error', + 'no-sequences': 'error', + 'no-throw-literal': 'error', + 'no-unmodified-loop-condition': 'error', + 'no-unused-expressions': 'error', + 'no-unused-labels': 'error', + 'no-useless-call': 'error', + 'no-useless-catch': 'error', + 'no-useless-concat': 'error', + 'no-useless-escape': 'error', + 'no-useless-return': 'error', + 'no-void': 'error', + 'no-warning-comments': 'off', + 'no-with': 'error', + 'prefer-named-capture-group': 'off', // TODO: enable + 'prefer-promise-reject-errors': 'error', + 'prefer-regex-literals': 'error', + radix: 'error', + 'require-await': 'error', + 'require-unicode-regexp': 'off', + 'vars-on-top': 'off', // TODO: enable + 'wrap-iife': ['error', 'inside'], + yoda: 'error', - // Strict mode - strict: ['error', 'global'], + // Strict mode + strict: ['error', 'global'], - // Variables - 'init-declarations': 'off', - 'no-delete-var': 'error', - 'no-label-var': 'error', - 'no-restricted-globals': ['error', 'app', 'env'], - 'no-shadow': 'error', - 'no-shadow-restricted-names': 'error', - 'no-undef': 'error', - 'no-undef-init': 'error', - 'no-undefined': 'off', - 'no-unused-vars': 'error', - 'no-use-before-define': 'error', + // Variables + 'init-declarations': 'off', + 'no-delete-var': 'error', + 'no-label-var': 'error', + 'no-restricted-globals': ['error', 'app', 'env'], + 'no-shadow': 'error', + 'no-shadow-restricted-names': 'error', + 'no-undef': 'error', + 'no-undef-init': 'error', + 'no-undefined': 'off', + 'no-unused-vars': 'error', + 'no-use-before-define': 'error', - // Stylistic issues - 'array-bracket-newline': 'off', - 'array-bracket-spacing': ['error', 'never'], - 'array-element-newline': 'off', - 'block-spacing': ['error', 'always'], - 'brace-style': 'off', // TODO: enable with "stroustrup" (or "1tbsp" + lots of cleanup) - camelcase: 'error', - 'capitalized-comments': 'off', - 'comma-dangle': 'error', - 'comma-spacing': [ - 'error', - { - before: false, - after: true - } - ], - 'comma-style': ['error', 'last'], - 'computed-property-spacing': ['error', 'never'], - 'consistent-this': ['error', 'self'], - 'eol-last': 'error', - 'func-call-spacing': ['error', 'never'], - 'func-name-matching': ['error', 'always'], - 'func-names': 'off', - 'func-style': 'off', - 'function-call-argument-newline:': 'off', - 'function-paren-newline': 'off', - 'id-denylist': 'off', - 'id-length': 'off', - 'id-match': 'off', - 'implicit-arrow-linebreak': 'off', - indent: [ - 'error', - 4, - { - SwitchCase: 1 - } - ], - 'jsx-quotes': ['error', 'prefer-double'], - 'key-spacing': [ - 'error', - { - beforeColon: false, - afterColon: true - } - ], - 'keyword-spacing': [ - 'error', - { - before: true, - after: true - } - ], - 'line-comment-position': 'off', - 'linebreak-style': 'off', - 'lines-around-comment': 'off', - 'lines-between-class-members': 'off', - 'max-depth': 'off', // TODO: enable - 'max-len': 'off', // TODO: enable - 'max-lines': 'off', - 'max-lines-per-function': 'off', - 'max-nested-callbacks': 'off', - 'max-params': 'off', // TODO: enable - 'max-statements': 'off', - 'max-statements-per-line': 'off', - 'multiline-comment-style': 'off', - 'multiline-ternary': 'off', - 'new-cap': 'error', - 'new-parens': 'error', - 'newline-per-chained-call': 'off', // TODO: enable - 'no-array-constructor': 'error', - 'no-bitwise': 'error', - 'no-continue': 'off', - 'no-inline-comments': 'off', - 'no-lonely-if': 'error', - 'no-mixed-operators': 'error', - 'no-mixed-spaces-and-tabs': 'error', - 'no-multi-assign': 'off', - 'no-multiple-empty-lines': [ - 'error', - { - max: 2 - } - ], - 'no-negated-condition': 'off', - 'no-nested-ternary': 'error', - 'no-new-object': 'error', - 'no-plusplus': 'off', - 'no-restricted-syntax': 'off', - 'no-tabs': 'error', - 'no-ternary': 'off', - 'no-trailing-spaces': 'error', - 'no-underscore-dangle': 'off', - 'no-unneeded-ternary': 'error', - 'no-whitespace-before-property': 'error', - 'nonblock-statement-body-position': 'off', - 'object-curly-newline': 'off', - 'object-curly-spacing': 'off', - 'object-property-newline': 'error', - 'one-var': 'off', - 'one-var-declaration-per-line': 'error', - 'operator-assignment': 'off', - 'operator-linebreak': ['error', 'after'], - 'padded-blocks': ['error', 'never'], - 'padding-line-between-statements': [ - 'error', - { - blankLine: 'always', - prev: '*', - next: 'return' - }, - { - blankLine: 'always', - prev: ['const', 'let', 'var'], - next: '*' - }, - { - blankLine: 'any', - prev: ['const', 'let', 'var'], - next: ['const', 'let', 'var'] - } - ], - 'prefer-exponentiation-operator': 'error', - 'prefer-object-spread': 'off', - 'quote-props': 'off', - quotes: ['error', 'single', 'avoid-escape'], - semi: ['error', 'always'], - 'semi-spacing': 'error', - 'semi-style': ['error', 'last'], - 'sort-keys': 'off', - 'sort-vars': 'off', // TODO: enable? - 'space-before-blocks': ['error', 'always'], - 'space-before-function-paren': ['error', { - anonymous: 'never', - named: 'never', - asyncArrow: 'always' - }], - 'space-in-parens': 'off', // TODO: enable? - 'space-infix-ops': 'error', - 'space-unary-ops': 'error', - 'spaced-comment': ['error', 'always'], - 'switch-colon-spacing': [ - 'error', - { - after: true, - before: false - } - ], - 'template-tag-spacing': ['error', 'never'], - 'unicode-bom': ['error', 'never'], - 'wrap-regex': 'off', + // Stylistic issues + 'array-bracket-newline': 'off', + 'array-bracket-spacing': ['error', 'never'], + 'array-element-newline': 'off', + 'block-spacing': ['error', 'always'], + 'brace-style': 'off', // TODO: enable with "stroustrup" (or "1tbsp" + lots of cleanup) + camelcase: 'error', + 'capitalized-comments': 'off', + 'comma-dangle': 'error', + 'comma-spacing': [ + 'error', + { + before: false, + after: true, + }, + ], + 'comma-style': ['error', 'last'], + 'computed-property-spacing': ['error', 'never'], + 'consistent-this': ['error', 'self'], + 'eol-last': 'error', + 'func-call-spacing': ['error', 'never'], + 'func-name-matching': ['error', 'always'], + 'func-names': 'off', + 'func-style': 'off', + 'function-call-argument-newline:': 'off', + 'function-paren-newline': 'off', + 'id-denylist': 'off', + 'id-length': 'off', + 'id-match': 'off', + 'implicit-arrow-linebreak': 'off', + indent: [ + 'error', + 2, + { + SwitchCase: 1, + }, + ], + 'jsx-quotes': ['error', 'prefer-double'], + 'key-spacing': [ + 'error', + { + beforeColon: false, + afterColon: true, + }, + ], + 'keyword-spacing': [ + 'error', + { + before: true, + after: true, + }, + ], + 'line-comment-position': 'off', + 'linebreak-style': 'off', + 'lines-around-comment': 'off', + 'lines-between-class-members': 'off', + 'max-depth': 'off', // TODO: enable + 'max-len': 'off', // TODO: enable + 'max-lines': 'off', + 'max-lines-per-function': 'off', + 'max-nested-callbacks': 'off', + 'max-params': 'off', // TODO: enable + 'max-statements': 'off', + 'max-statements-per-line': 'off', + 'multiline-comment-style': 'off', + 'multiline-ternary': 'off', + 'new-cap': 'error', + 'new-parens': 'error', + 'newline-per-chained-call': 'off', // TODO: enable + 'no-array-constructor': 'error', + 'no-bitwise': 'error', + 'no-continue': 'off', + 'no-inline-comments': 'off', + 'no-lonely-if': 'error', + 'no-mixed-operators': 'error', + 'no-mixed-spaces-and-tabs': 'error', + 'no-multi-assign': 'off', + 'no-multiple-empty-lines': [ + 'error', + { + max: 2, + }, + ], + 'no-negated-condition': 'off', + 'no-nested-ternary': 'error', + 'no-new-object': 'error', + 'no-plusplus': 'off', + 'no-restricted-syntax': 'off', + 'no-tabs': 'error', + 'no-ternary': 'off', + 'no-trailing-spaces': 'error', + 'no-underscore-dangle': 'off', + 'no-unneeded-ternary': 'error', + 'no-whitespace-before-property': 'error', + 'nonblock-statement-body-position': 'off', + 'object-curly-newline': 'off', + 'object-curly-spacing': 'off', + 'object-property-newline': 'error', + 'one-var': 'off', + 'one-var-declaration-per-line': 'error', + 'operator-assignment': 'off', + 'operator-linebreak': ['error', 'after'], + 'padded-blocks': ['error', 'never'], + 'padding-line-between-statements': [ + 'error', + { + blankLine: 'always', + prev: '*', + next: 'return', + }, + { + blankLine: 'always', + prev: ['const', 'let', 'var'], + next: '*', + }, + { + blankLine: 'any', + prev: ['const', 'let', 'var'], + next: ['const', 'let', 'var'], + }, + ], + 'prefer-exponentiation-operator': 'error', + 'prefer-object-spread': 'off', + 'quote-props': 'off', + quotes: ['error', 'single', 'avoid-escape'], + semi: ['error', 'always'], + 'semi-spacing': 'error', + 'semi-style': ['error', 'last'], + 'sort-keys': 'off', + 'sort-vars': 'off', // TODO: enable? + 'space-before-blocks': ['error', 'always'], + 'space-before-function-paren': [ + 'error', + { + anonymous: 'never', + named: 'never', + asyncArrow: 'always', + }, + ], + 'space-in-parens': 'off', // TODO: enable? + 'space-infix-ops': 'error', + 'space-unary-ops': 'error', + 'spaced-comment': ['error', 'always'], + 'switch-colon-spacing': [ + 'error', + { + after: true, + before: false, + }, + ], + 'template-tag-spacing': ['error', 'never'], + 'unicode-bom': ['error', 'never'], + 'wrap-regex': 'off', - // ECMAScript 2015 - 'arrow-body-style': ['error', 'as-needed'], - 'arrow-parens': 'off', - 'arrow-spacing': [ - 'error', - { - before: true, - after: true - } - ], - 'constructor-super': 'error', - 'generator-star-spacing': [ - 'error', - { - before: true, - after: false - } - ], - 'no-class-assign': 'error', - 'no-confusing-arrow': 'error', - 'no-const-assign': 'error', - 'no-dupe-class-members': 'error', - 'no-duplicate-imports': [ - 'error', - { - includeExports: true - } - ], - 'no-new-symbol': 'error', - 'no-restricted-exports': 'off', - 'no-restricted-imports': 'off', - 'no-this-before-super': 'error', - 'no-useless-computed-key': 'error', - 'no-useless-constructor': 'off', - 'no-useless-rename': 'error', - 'no-var': 'off', // TODO: enable - 'object-shorthand': 'off', - 'prefer-arrow-callback': 'off', - 'prefer-const': 'off', - 'prefer-destructuring': 'off', - 'prefer-numeric-literals': 'off', - 'prefer-rest-params': 'off', - 'prefer-spread': 'off', - 'prefer-template': 'off', - 'require-yield': 'error', - 'rest-spread-spacing': ['error', 'never'], - 'sort-imports': 'error', - 'symbol-description': 'error', - 'template-curly-spacing': ['error', 'never'], - 'yield-star-spacing': ['error', 'before'] - } + // ECMAScript 2015 + 'arrow-body-style': ['error', 'as-needed'], + 'arrow-parens': 'off', + 'arrow-spacing': [ + 'error', + { + before: true, + after: true, + }, + ], + 'constructor-super': 'error', + 'generator-star-spacing': [ + 'error', + { + before: true, + after: false, + }, + ], + 'no-class-assign': 'error', + 'no-confusing-arrow': 'error', + 'no-const-assign': 'error', + 'no-dupe-class-members': 'error', + 'no-duplicate-imports': [ + 'error', + { + includeExports: true, + }, + ], + 'no-new-symbol': 'error', + 'no-restricted-exports': 'off', + 'no-restricted-imports': 'off', + 'no-this-before-super': 'error', + 'no-useless-computed-key': 'error', + 'no-useless-constructor': 'off', + 'no-useless-rename': 'error', + 'no-var': 'off', // TODO: enable + 'object-shorthand': 'off', + 'prefer-arrow-callback': 'off', + 'prefer-const': 'off', + 'prefer-destructuring': 'off', + 'prefer-numeric-literals': 'off', + 'prefer-rest-params': 'off', + 'prefer-spread': 'off', + 'prefer-template': 'off', + 'require-yield': 'error', + 'rest-spread-spacing': ['error', 'never'], + 'sort-imports': 'error', + 'symbol-description': 'error', + 'template-curly-spacing': ['error', 'never'], + 'yield-star-spacing': ['error', 'before'], + }, }; diff --git a/packages/jsdoc-parse/index.js b/packages/jsdoc-parse/index.js index 0ba0cb06..0b339838 100644 --- a/packages/jsdoc-parse/index.js +++ b/packages/jsdoc-parse/index.js @@ -3,7 +3,7 @@ const astNode = require('./lib/ast-node'); const { Syntax } = require('./lib/syntax'); module.exports = { - AstBuilder, - astNode, - Syntax + AstBuilder, + astNode, + Syntax, }; diff --git a/packages/jsdoc-parse/lib/ast-builder.js b/packages/jsdoc-parse/lib/ast-builder.js index 8845cf6d..1f4d341d 100644 --- a/packages/jsdoc-parse/lib/ast-builder.js +++ b/packages/jsdoc-parse/lib/ast-builder.js @@ -3,63 +3,68 @@ const babelParser = require('@babel/parser'); const { log } = require('@jsdoc/util'); // Exported so we can use them in tests. -const parserOptions = exports.parserOptions = { - allowAwaitOutsideFunction: true, - allowImportExportEverywhere: true, - allowReturnOutsideFunction: true, - allowSuperOutsideMethod: true, - allowUndeclaredExports: true, - plugins: [ - 'asyncGenerators', - 'bigInt', - 'classPrivateMethods', - 'classPrivateProperties', - 'classProperties', - ['decorators', { - decoratorsBeforeExport: true - }], - 'doExpressions', - 'dynamicImport', - 'estree', - 'exportDefaultFrom', - 'exportNamespaceFrom', - 'functionBind', - 'functionSent', - 'importMeta', - 'jsx', - 'logicalAssignment', - 'nullishCoalescingOperator', - 'numericSeparator', - 'objectRestSpread', - 'optionalCatchBinding', - 'optionalChaining', - ['pipelineOperator', { - proposal: 'minimal' - }], - 'throwExpressions' +const parserOptions = (exports.parserOptions = { + allowAwaitOutsideFunction: true, + allowImportExportEverywhere: true, + allowReturnOutsideFunction: true, + allowSuperOutsideMethod: true, + allowUndeclaredExports: true, + plugins: [ + 'asyncGenerators', + 'bigInt', + 'classPrivateMethods', + 'classPrivateProperties', + 'classProperties', + [ + 'decorators', + { + decoratorsBeforeExport: true, + }, ], - ranges: true -}; + 'doExpressions', + 'dynamicImport', + 'estree', + 'exportDefaultFrom', + 'exportNamespaceFrom', + 'functionBind', + 'functionSent', + 'importMeta', + 'jsx', + 'logicalAssignment', + 'nullishCoalescingOperator', + 'numericSeparator', + 'objectRestSpread', + 'optionalCatchBinding', + 'optionalChaining', + [ + 'pipelineOperator', + { + proposal: 'minimal', + }, + ], + 'throwExpressions', + ], + ranges: true, +}); function parse(source, filename, sourceType) { - let ast; - const options = _.defaults({}, parserOptions, {sourceType}); + let ast; + const options = _.defaults({}, parserOptions, { sourceType }); - try { - ast = babelParser.parse(source, options); - } - catch (e) { - log.error(`Unable to parse ${filename}: ${e.message}`); - } + try { + ast = babelParser.parse(source, options); + } catch (e) { + log.error(`Unable to parse ${filename}: ${e.message}`); + } - return ast; + return ast; } // TODO: docs class AstBuilder { - // TODO: docs - static build(source, filename, sourceType) { - return parse(source, filename, sourceType); - } + // TODO: docs + static build(source, filename, sourceType) { + return parse(source, filename, sourceType); + } } exports.AstBuilder = AstBuilder; diff --git a/packages/jsdoc-parse/lib/ast-node.js b/packages/jsdoc-parse/lib/ast-node.js index f3d48ce2..779688b8 100644 --- a/packages/jsdoc-parse/lib/ast-node.js +++ b/packages/jsdoc-parse/lib/ast-node.js @@ -15,23 +15,26 @@ let uid = 100000000; * @param {(Object|string)} node - The AST node to check, or the `type` property of a node. * @return {boolean} Set to `true` if the node is a function or `false` in all other cases. */ -const isFunction = exports.isFunction = node => { - let type; +const isFunction = (exports.isFunction = (node) => { + let type; - if (!node) { - return false; - } + if (!node) { + return false; + } - if (typeof node === 'string') { - type = node; - } - else { - type = node.type; - } + if (typeof node === 'string') { + type = node; + } else { + type = node.type; + } - return type === Syntax.FunctionDeclaration || type === Syntax.FunctionExpression || - type === Syntax.MethodDefinition || type === Syntax.ArrowFunctionExpression; -}; + return ( + type === Syntax.FunctionDeclaration || + type === Syntax.FunctionExpression || + type === Syntax.MethodDefinition || + type === Syntax.ArrowFunctionExpression + ); +}); /** * Check whether an AST node creates a new scope. @@ -40,513 +43,521 @@ const isFunction = exports.isFunction = node => { * @param {Object} node - The AST node to check. * @return {Boolean} Set to `true` if the node creates a new scope, or `false` in all other cases. */ -exports.isScope = node => // TODO: handle blocks with "let" declarations - Boolean(node) && typeof node === 'object' && (node.type === Syntax.CatchClause || - node.type === Syntax.ClassDeclaration || node.type === Syntax.ClassExpression || isFunction(node)); +exports.isScope = ( + node // TODO: handle blocks with "let" declarations +) => + Boolean(node) && + typeof node === 'object' && + (node.type === Syntax.CatchClause || + node.type === Syntax.ClassDeclaration || + node.type === Syntax.ClassExpression || + isFunction(node)); // TODO: docs -exports.addNodeProperties = node => { - const newProperties = {}; +exports.addNodeProperties = (node) => { + const newProperties = {}; - if (!node || typeof node !== 'object') { - return null; - } + if (!node || typeof node !== 'object') { + return null; + } - if (!node.nodeId) { - newProperties.nodeId = { - value: `astnode${uid++}`, - enumerable: true - }; - } + if (!node.nodeId) { + newProperties.nodeId = { + value: `astnode${uid++}`, + enumerable: true, + }; + } - if (_.isUndefined(node.parent)) { - newProperties.parent = { - // `null` means 'no parent', so use `undefined` for now - value: undefined, - writable: true - }; - } + if (_.isUndefined(node.parent)) { + newProperties.parent = { + // `null` means 'no parent', so use `undefined` for now + value: undefined, + writable: true, + }; + } - if (_.isUndefined(node.enclosingScope)) { - newProperties.enclosingScope = { - // `null` means 'no enclosing scope', so use `undefined` for now - value: undefined, - writable: true - }; - } + if (_.isUndefined(node.enclosingScope)) { + newProperties.enclosingScope = { + // `null` means 'no enclosing scope', so use `undefined` for now + value: undefined, + writable: true, + }; + } - if (_.isUndefined(node.parentId)) { - newProperties.parentId = { - enumerable: true, - get() { - return this.parent ? this.parent.nodeId : null; - } - }; - } + if (_.isUndefined(node.parentId)) { + newProperties.parentId = { + enumerable: true, + get() { + return this.parent ? this.parent.nodeId : null; + }, + }; + } - if (_.isUndefined(node.enclosingScopeId)) { - newProperties.enclosingScopeId = { - enumerable: true, - get() { - return this.enclosingScope ? this.enclosingScope.nodeId : null; - } - }; - } + if (_.isUndefined(node.enclosingScopeId)) { + newProperties.enclosingScopeId = { + enumerable: true, + get() { + return this.enclosingScope ? this.enclosingScope.nodeId : null; + }, + }; + } - Object.defineProperties(node, newProperties); + Object.defineProperties(node, newProperties); - return node; + return node; }; // TODO: docs -const nodeToValue = exports.nodeToValue = node => { - let key; - let parent; - let str; - let tempObject; +const nodeToValue = (exports.nodeToValue = (node) => { + let key; + let parent; + let str; + let tempObject; - switch (node.type) { - case Syntax.ArrayExpression: - tempObject = []; - node.elements.forEach((el, i) => { - // handle sparse arrays. use `null` to represent missing values, consistent with - // JSON.stringify([,]). - if (!el) { - tempObject[i] = null; - } - else { - tempObject[i] = nodeToValue(el); - } - }); + switch (node.type) { + case Syntax.ArrayExpression: + tempObject = []; + node.elements.forEach((el, i) => { + // handle sparse arrays. use `null` to represent missing values, consistent with + // JSON.stringify([,]). + if (!el) { + tempObject[i] = null; + } else { + tempObject[i] = nodeToValue(el); + } + }); - str = JSON.stringify(tempObject); - break; + str = JSON.stringify(tempObject); + break; - case Syntax.AssignmentExpression: - // falls through + case Syntax.AssignmentExpression: + // falls through - case Syntax.AssignmentPattern: - str = nodeToValue(node.left); - break; + case Syntax.AssignmentPattern: + str = nodeToValue(node.left); + break; - case Syntax.BigIntLiteral: - str = node.value; - break; + case Syntax.BigIntLiteral: + str = node.value; + break; - case Syntax.ClassDeclaration: - str = nodeToValue(node.id); - break; + case Syntax.ClassDeclaration: + str = nodeToValue(node.id); + break; - case Syntax.ClassPrivateProperty: - // TODO: Strictly speaking, the name should be '#' plus node.key, but because we - // already use '#' as scope punctuation, that causes JSDoc to get extremely confused. - // The solution probably involves quoting part or all of the name, but JSDoc doesn't - // deal with quoted names very nicely right now, and most people probably won't want to - // document class private properties anyhow. So for now, we'll just cheat and omit the - // leading '#'. - str = nodeToValue(node.key.id); - break; + case Syntax.ClassPrivateProperty: + // TODO: Strictly speaking, the name should be '#' plus node.key, but because we + // already use '#' as scope punctuation, that causes JSDoc to get extremely confused. + // The solution probably involves quoting part or all of the name, but JSDoc doesn't + // deal with quoted names very nicely right now, and most people probably won't want to + // document class private properties anyhow. So for now, we'll just cheat and omit the + // leading '#'. + str = nodeToValue(node.key.id); + break; - case Syntax.ClassProperty: - str = nodeToValue(node.key); - break; + case Syntax.ClassProperty: + str = nodeToValue(node.key); + break; - case Syntax.ExportAllDeclaration: - // falls through + case Syntax.ExportAllDeclaration: + // falls through - case Syntax.ExportDefaultDeclaration: - str = 'module.exports'; - break; + case Syntax.ExportDefaultDeclaration: + str = 'module.exports'; + break; - case Syntax.ExportNamedDeclaration: - if (node.declaration) { - // like `var` in: export var foo = 'bar'; - // we need a single value, so we use the first variable name - if (node.declaration.declarations) { - str = `exports.${nodeToValue(node.declaration.declarations[0])}`; - } - else { - str = `exports.${nodeToValue(node.declaration)}`; - } - } + case Syntax.ExportNamedDeclaration: + if (node.declaration) { + // like `var` in: export var foo = 'bar'; + // we need a single value, so we use the first variable name + if (node.declaration.declarations) { + str = `exports.${nodeToValue(node.declaration.declarations[0])}`; + } else { + str = `exports.${nodeToValue(node.declaration)}`; + } + } - // otherwise we'll use the ExportSpecifier nodes - break; + // otherwise we'll use the ExportSpecifier nodes + break; - case Syntax.ExportSpecifier: - str = `exports.${nodeToValue(node.exported)}`; - break; + case Syntax.ExportSpecifier: + str = `exports.${nodeToValue(node.exported)}`; + break; - case Syntax.ArrowFunctionExpression: - // falls through + case Syntax.ArrowFunctionExpression: + // falls through - case Syntax.FunctionDeclaration: - // falls through + case Syntax.FunctionDeclaration: + // falls through - case Syntax.FunctionExpression: - if (node.id && node.id.name) { - str = node.id.name; - } - break; + case Syntax.FunctionExpression: + if (node.id && node.id.name) { + str = node.id.name; + } + break; - case Syntax.Identifier: - str = node.name; - break; + case Syntax.Identifier: + str = node.name; + break; - case Syntax.Literal: - str = node.value; - break; + case Syntax.Literal: + str = node.value; + break; - case Syntax.MemberExpression: - // could be computed (like foo['bar']) or not (like foo.bar) - str = nodeToValue(node.object); - if (node.computed) { - str += `[${node.property.raw}]`; - } - else { - str += `.${nodeToValue(node.property)}`; - } - break; + case Syntax.MemberExpression: + // could be computed (like foo['bar']) or not (like foo.bar) + str = nodeToValue(node.object); + if (node.computed) { + str += `[${node.property.raw}]`; + } else { + str += `.${nodeToValue(node.property)}`; + } + break; - case Syntax.MethodDefinition: - parent = node.parent.parent; - // for class expressions, we want the name of the variable the class is assigned to - // (but there won't be a name if the class is returned by an arrow function expression) - // TODO: we should use `LONGNAMES.ANONYMOUS` instead of an empty string, but that - // causes problems downstream if the parent class has an `@alias` tag - if (parent.type === Syntax.ClassExpression) { - str = nodeToValue(parent.parent) || ''; - } - // for the constructor of a module's default export, use a special name - else if (node.kind === 'constructor' && parent.parent && - parent.parent.type === Syntax.ExportDefaultDeclaration) { - str = 'module.exports'; - } - // for the constructor of a module's named export, use the name of the export - // declaration - else if (node.kind === 'constructor' && parent.parent && - parent.parent.type === Syntax.ExportNamedDeclaration) { - str = nodeToValue(parent.parent); - } - // for other constructors, use the name of the parent class - else if (node.kind === 'constructor') { - str = nodeToValue(parent); - } - // if the method is a member of a module's default export, ignore the name, because it's - // irrelevant - else if (parent.parent && parent.parent.type === Syntax.ExportDefaultDeclaration) { - str = ''; - } - // otherwise, use the class's name - else { - str = parent.id ? nodeToValue(parent.id) : ''; - } + case Syntax.MethodDefinition: + parent = node.parent.parent; + // for class expressions, we want the name of the variable the class is assigned to + // (but there won't be a name if the class is returned by an arrow function expression) + // TODO: we should use `LONGNAMES.ANONYMOUS` instead of an empty string, but that + // causes problems downstream if the parent class has an `@alias` tag + if (parent.type === Syntax.ClassExpression) { + str = nodeToValue(parent.parent) || ''; + } + // for the constructor of a module's default export, use a special name + else if ( + node.kind === 'constructor' && + parent.parent && + parent.parent.type === Syntax.ExportDefaultDeclaration + ) { + str = 'module.exports'; + } + // for the constructor of a module's named export, use the name of the export + // declaration + else if ( + node.kind === 'constructor' && + parent.parent && + parent.parent.type === Syntax.ExportNamedDeclaration + ) { + str = nodeToValue(parent.parent); + } + // for other constructors, use the name of the parent class + else if (node.kind === 'constructor') { + str = nodeToValue(parent); + } + // if the method is a member of a module's default export, ignore the name, because it's + // irrelevant + else if (parent.parent && parent.parent.type === Syntax.ExportDefaultDeclaration) { + str = ''; + } + // otherwise, use the class's name + else { + str = parent.id ? nodeToValue(parent.id) : ''; + } - if (node.kind !== 'constructor') { - if (str) { - str += node.static ? SCOPE.PUNC.STATIC : SCOPE.PUNC.INSTANCE; - } - str += nodeToValue(node.key); - } - break; + if (node.kind !== 'constructor') { + if (str) { + str += node.static ? SCOPE.PUNC.STATIC : SCOPE.PUNC.INSTANCE; + } + str += nodeToValue(node.key); + } + break; - case Syntax.ObjectExpression: - tempObject = {}; - node.properties.forEach(prop => { - // ExperimentalSpreadProperty have no key - // like var hello = {...hi}; - if (!prop.key) { - return; - } + case Syntax.ObjectExpression: + tempObject = {}; + node.properties.forEach((prop) => { + // ExperimentalSpreadProperty have no key + // like var hello = {...hi}; + if (!prop.key) { + return; + } - key = prop.key.name; + key = prop.key.name; - // preserve literal values so that the JSON form shows the correct type - if (prop.value.type === Syntax.Literal) { - tempObject[key] = prop.value.value; - } - else { - tempObject[key] = nodeToValue(prop); - } - }); + // preserve literal values so that the JSON form shows the correct type + if (prop.value.type === Syntax.Literal) { + tempObject[key] = prop.value.value; + } else { + tempObject[key] = nodeToValue(prop); + } + }); - str = JSON.stringify(tempObject); - break; + str = JSON.stringify(tempObject); + break; - case Syntax.RestElement: - str = nodeToValue(node.argument); - break; + case Syntax.RestElement: + str = nodeToValue(node.argument); + break; - case Syntax.ThisExpression: - str = 'this'; - break; + case Syntax.ThisExpression: + str = 'this'; + break; - case Syntax.UnaryExpression: - // like -1. in theory, operator can be prefix or postfix. in practice, any value with a - // valid postfix operator (such as -- or ++) is not a UnaryExpression. - str = nodeToValue(node.argument); + case Syntax.UnaryExpression: + // like -1. in theory, operator can be prefix or postfix. in practice, any value with a + // valid postfix operator (such as -- or ++) is not a UnaryExpression. + str = nodeToValue(node.argument); - if (node.prefix === true) { - str = cast(node.operator + str); - } - else { - // this shouldn't happen - throw new Error(`Found a UnaryExpression with a postfix operator: ${node}`); - } - break; + if (node.prefix === true) { + str = cast(node.operator + str); + } else { + // this shouldn't happen + throw new Error(`Found a UnaryExpression with a postfix operator: ${node}`); + } + break; - case Syntax.VariableDeclarator: - str = nodeToValue(node.id); - break; + case Syntax.VariableDeclarator: + str = nodeToValue(node.id); + break; - default: - str = ''; - } + default: + str = ''; + } - return str; -}; + return str; +}); // backwards compatibility exports.nodeToString = nodeToValue; // TODO: docs -const getParamNames = exports.getParamNames = node => { - let params; +const getParamNames = (exports.getParamNames = (node) => { + let params; - if (!node || !node.params) { - return []; - } + if (!node || !node.params) { + return []; + } - params = node.params.slice(0); + params = node.params.slice(0); - return params.map(param => nodeToValue(param)); -}; + return params.map((param) => nodeToValue(param)); +}); // TODO: docs -const isAccessor = exports.isAccessor = node => Boolean(node) && typeof node === 'object' && - (node.type === Syntax.Property || node.type === Syntax.MethodDefinition) && - (node.kind === 'get' || node.kind === 'set'); +const isAccessor = (exports.isAccessor = (node) => + Boolean(node) && + typeof node === 'object' && + (node.type === Syntax.Property || node.type === Syntax.MethodDefinition) && + (node.kind === 'get' || node.kind === 'set')); // TODO: docs -exports.isAssignment = node => Boolean(node) && typeof node === 'object' && - (node.type === Syntax.AssignmentExpression || node.type === Syntax.VariableDeclarator); +exports.isAssignment = (node) => + Boolean(node) && + typeof node === 'object' && + (node.type === Syntax.AssignmentExpression || node.type === Syntax.VariableDeclarator); // TODO: docs /** * Retrieve information about the node, including its name and type. */ -exports.getInfo = node => { - const info = {}; +exports.getInfo = (node) => { + const info = {}; - switch (node.type) { - // like the function in: "var foo = () => {}" - case Syntax.ArrowFunctionExpression: - info.node = node; - info.name = ''; - info.type = info.node.type; - info.paramnames = getParamNames(node); - break; + switch (node.type) { + // like the function in: "var foo = () => {}" + case Syntax.ArrowFunctionExpression: + info.node = node; + info.name = ''; + info.type = info.node.type; + info.paramnames = getParamNames(node); + break; - // like: "foo = 'bar'" (after declaring foo) - // like: "MyClass.prototype.myMethod = function() {}" (after declaring MyClass) - case Syntax.AssignmentExpression: - info.node = node.right; - info.name = nodeToValue(node.left); - info.type = info.node.type; - info.value = nodeToValue(info.node); - // if the assigned value is a function, we need to capture the parameter names here - info.paramnames = getParamNames(node.right); - break; + // like: "foo = 'bar'" (after declaring foo) + // like: "MyClass.prototype.myMethod = function() {}" (after declaring MyClass) + case Syntax.AssignmentExpression: + info.node = node.right; + info.name = nodeToValue(node.left); + info.type = info.node.type; + info.value = nodeToValue(info.node); + // if the assigned value is a function, we need to capture the parameter names here + info.paramnames = getParamNames(node.right); + break; - // like "bar='baz'" in: function foo(bar='baz') {} - case Syntax.AssignmentPattern: - info.node = node; - info.name = nodeToValue(node.left); - info.type = info.node.type; - info.value = nodeToValue(info.node); + // like "bar='baz'" in: function foo(bar='baz') {} + case Syntax.AssignmentPattern: + info.node = node; + info.name = nodeToValue(node.left); + info.type = info.node.type; + info.value = nodeToValue(info.node); - break; + break; - // like: "class Foo {}" - // or "class" in: "export default class {}" - case Syntax.ClassDeclaration: - info.node = node; - // if this class is the default export, we need to use a special name - if (node.parent && node.parent.type === Syntax.ExportDefaultDeclaration) { - info.name = 'module.exports'; - } - else { - info.name = node.id ? nodeToValue(node.id) : ''; - } - info.type = info.node.type; - info.paramnames = []; + // like: "class Foo {}" + // or "class" in: "export default class {}" + case Syntax.ClassDeclaration: + info.node = node; + // if this class is the default export, we need to use a special name + if (node.parent && node.parent.type === Syntax.ExportDefaultDeclaration) { + info.name = 'module.exports'; + } else { + info.name = node.id ? nodeToValue(node.id) : ''; + } + info.type = info.node.type; + info.paramnames = []; - node.body.body.some(({kind, value}) => { - if (kind === 'constructor') { - info.paramnames = getParamNames(value); + node.body.body.some(({ kind, value }) => { + if (kind === 'constructor') { + info.paramnames = getParamNames(value); - return true; - } + return true; + } - return false; - }); + return false; + }); - break; + break; - // like "#b = 1;" in: "class A { #b = 1; }" - case Syntax.ClassPrivateProperty: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.type; - break; + // like "#b = 1;" in: "class A { #b = 1; }" + case Syntax.ClassPrivateProperty: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.type; + break; - // like "b = 1;" in: "class A { b = 1; }" - case Syntax.ClassProperty: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.type; - break; + // like "b = 1;" in: "class A { b = 1; }" + case Syntax.ClassProperty: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.type; + break; - // like: "export * from 'foo'" - case Syntax.ExportAllDeclaration: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.type; - break; + // like: "export * from 'foo'" + case Syntax.ExportAllDeclaration: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.type; + break; - // like: "export default 'foo'" - case Syntax.ExportDefaultDeclaration: - info.node = node.declaration; - info.name = nodeToValue(node); - info.type = info.node.type; + // like: "export default 'foo'" + case Syntax.ExportDefaultDeclaration: + info.node = node.declaration; + info.name = nodeToValue(node); + info.type = info.node.type; - if ( isFunction(info.node) ) { - info.paramnames = getParamNames(info.node); - } + if (isFunction(info.node)) { + info.paramnames = getParamNames(info.node); + } - break; + break; - // like: "export var foo;" (has declaration) - // or: "export {foo}" (no declaration) - case Syntax.ExportNamedDeclaration: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.declaration ? info.node.declaration.type : - Syntax.ObjectExpression; + // like: "export var foo;" (has declaration) + // or: "export {foo}" (no declaration) + case Syntax.ExportNamedDeclaration: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.declaration ? info.node.declaration.type : Syntax.ObjectExpression; - if (info.node.declaration) { - if ( isFunction(info.node.declaration) ) { - info.paramnames = getParamNames(info.node.declaration); - } + if (info.node.declaration) { + if (isFunction(info.node.declaration)) { + info.paramnames = getParamNames(info.node.declaration); + } - // TODO: This duplicates logic for another node type in `jsdoc/src/visitor` in - // `makeSymbolFoundEvent()`. Is there a way to combine the logic for both node types - // into a single module? - if (info.node.declaration.kind === 'const') { - info.kind = 'constant'; - } - } + // TODO: This duplicates logic for another node type in `jsdoc/src/visitor` in + // `makeSymbolFoundEvent()`. Is there a way to combine the logic for both node types + // into a single module? + if (info.node.declaration.kind === 'const') { + info.kind = 'constant'; + } + } - break; + break; - // like "foo as bar" in: "export {foo as bar}" - case Syntax.ExportSpecifier: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.local.type; + // like "foo as bar" in: "export {foo as bar}" + case Syntax.ExportSpecifier: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.local.type; - if ( isFunction(info.node.local) ) { - info.paramnames = getParamNames(info.node.local); - } + if (isFunction(info.node.local)) { + info.paramnames = getParamNames(info.node.local); + } - break; + break; - // like: "function foo() {}" - // or the function in: "export default function() {}" - case Syntax.FunctionDeclaration: - info.node = node; - info.name = node.id ? nodeToValue(node.id) : ''; - info.type = info.node.type; - info.paramnames = getParamNames(node); - break; + // like: "function foo() {}" + // or the function in: "export default function() {}" + case Syntax.FunctionDeclaration: + info.node = node; + info.name = node.id ? nodeToValue(node.id) : ''; + info.type = info.node.type; + info.paramnames = getParamNames(node); + break; - // like the function in: "var foo = function() {}" - case Syntax.FunctionExpression: - info.node = node; - // TODO: should we add a name for, e.g., "var foo = function bar() {}"? - info.name = ''; - info.type = info.node.type; - info.paramnames = getParamNames(node); - break; + // like the function in: "var foo = function() {}" + case Syntax.FunctionExpression: + info.node = node; + // TODO: should we add a name for, e.g., "var foo = function bar() {}"? + info.name = ''; + info.type = info.node.type; + info.paramnames = getParamNames(node); + break; - // like the param "bar" in: "function foo(bar) {}" - case Syntax.Identifier: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.type; - break; + // like the param "bar" in: "function foo(bar) {}" + case Syntax.Identifier: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.type; + break; - // like "a.b.c" - case Syntax.MemberExpression: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.type; - break; + // like "a.b.c" + case Syntax.MemberExpression: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.type; + break; - // like: "foo() {}" - case Syntax.MethodDefinition: - info.node = node; - info.name = nodeToValue(info.node); - info.type = info.node.type; - info.paramnames = getParamNames(node.value); - break; + // like: "foo() {}" + case Syntax.MethodDefinition: + info.node = node; + info.name = nodeToValue(info.node); + info.type = info.node.type; + info.paramnames = getParamNames(node.value); + break; - // like "a: 0" in "var foo = {a: 0}" - case Syntax.Property: - info.node = node.value; - info.name = nodeToValue(node.key); - info.value = nodeToValue(info.node); + // like "a: 0" in "var foo = {a: 0}" + case Syntax.Property: + info.node = node.value; + info.name = nodeToValue(node.key); + info.value = nodeToValue(info.node); - // property names with unsafe characters must be quoted - if ( !/^[$_a-zA-Z0-9]*$/.test(info.name) ) { - info.name = `"${String(info.name).replace(/"/g, '\\"')}"`; - } + // property names with unsafe characters must be quoted + if (!/^[$_a-zA-Z0-9]*$/.test(info.name)) { + info.name = `"${String(info.name).replace(/"/g, '\\"')}"`; + } - if ( isAccessor(node) ) { - info.type = nodeToValue(info.node); - info.paramnames = getParamNames(info.node); - } - else { - info.type = info.node.type; - } + if (isAccessor(node)) { + info.type = nodeToValue(info.node); + info.paramnames = getParamNames(info.node); + } else { + info.type = info.node.type; + } - break; + break; - // like "...bar" in: function foo(...bar) {} - case Syntax.RestElement: - info.node = node; - info.name = nodeToValue(info.node.argument); - info.type = info.node.type; + // like "...bar" in: function foo(...bar) {} + case Syntax.RestElement: + info.node = node; + info.name = nodeToValue(info.node.argument); + info.type = info.node.type; - break; + break; - // like: "var i = 0" (has init property) - // like: "var i" (no init property) - case Syntax.VariableDeclarator: - info.node = node.init || node.id; - info.name = node.id.name; + // like: "var i = 0" (has init property) + // like: "var i" (no init property) + case Syntax.VariableDeclarator: + info.node = node.init || node.id; + info.name = node.id.name; - if (node.init) { - info.type = info.node.type; - info.value = nodeToValue(info.node); - } + if (node.init) { + info.type = info.node.type; + info.value = nodeToValue(info.node); + } - break; + break; - default: - info.node = node; - info.type = info.node.type; - } + default: + info.node = node; + info.type = info.node.type; + } - return info; + return info; }; diff --git a/packages/jsdoc-parse/lib/syntax.js b/packages/jsdoc-parse/lib/syntax.js index 05bd2710..36f5b723 100644 --- a/packages/jsdoc-parse/lib/syntax.js +++ b/packages/jsdoc-parse/lib/syntax.js @@ -1,96 +1,96 @@ // TODO: docs exports.Syntax = { - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - ArrowFunctionExpression: 'ArrowFunctionExpression', - AssignmentExpression: 'AssignmentExpression', - AssignmentPattern: 'AssignmentPattern', - AwaitExpression: 'AwaitExpression', - BigIntLiteral: 'BigIntLiteral', - BinaryExpression: 'BinaryExpression', - BindExpression: 'BindExpression', - BlockStatement: 'BlockStatement', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ClassBody: 'ClassBody', - ClassDeclaration: 'ClassDeclaration', - ClassExpression: 'ClassExpression', - ClassPrivateProperty: 'ClassPrivateProperty', - ClassProperty: 'ClassProperty', - ComprehensionBlock: 'ComprehensionBlock', - ComprehensionExpression: 'ComprehensionExpression', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DebuggerStatement: 'DebuggerStatement', - Decorator: 'Decorator', - DoExpression: 'DoExpression', - DoWhileStatement: 'DoWhileStatement', - EmptyStatement: 'EmptyStatement', - ExperimentalRestProperty: 'ExperimentalRestProperty', - ExperimentalSpreadProperty: 'ExperimentalSpreadProperty', - ExportAllDeclaration: 'ExportAllDeclaration', - ExportDefaultDeclaration: 'ExportDefaultDeclaration', - ExportDefaultSpecifier: 'ExportDefaultSpecifier', - ExportNamedDeclaration: 'ExportNamedDeclaration', - ExportNamespaceSpecifier: 'ExportNamespaceSpecifier', - ExportSpecifier: 'ExportSpecifier', - ExpressionStatement: 'ExpressionStatement', - File: 'File', - ForInStatement: 'ForInStatement', - ForOfStatement: 'ForOfStatement', - ForStatement: 'ForStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Import: 'Import', - ImportDeclaration: 'ImportDeclaration', - ImportDefaultSpecifier: 'ImportDefaultSpecifier', - ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', - ImportSpecifier: 'ImportSpecifier', - JSXAttribute: 'JSXAttribute', - JSXClosingElement: 'JSXClosingElement', - JSXElement: 'JSXElement', - JSXEmptyExpression: 'JSXEmptyExpression', - JSXExpressionContainer: 'JSXExpressionContainer', - JSXIdentifier: 'JSXIdentifier', - JSXMemberExpression: 'JSXMemberExpression', - JSXNamespacedName: 'JSXNamespacedName', - JSXOpeningElement: 'JSXOpeningElement', - JSXSpreadAttribute: 'JSXSpreadAttribute', - JSXText: 'JSXText', - LabeledStatement: 'LabeledStatement', - LetStatement: 'LetStatement', - Literal: 'Literal', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - MetaProperty: 'MetaProperty', - MethodDefinition: 'MethodDefinition', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - PrivateName: 'PrivateName', - Program: 'Program', - Property: 'Property', - RestElement: 'RestElement', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SpreadElement: 'SpreadElement', - Super: 'Super', - SwitchCase: 'SwitchCase', - SwitchStatement: 'SwitchStatement', - TaggedTemplateExpression: 'TaggedTemplateExpression', - TemplateElement: 'TemplateElement', - TemplateLiteral: 'TemplateLiteral', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + AssignmentExpression: 'AssignmentExpression', + AssignmentPattern: 'AssignmentPattern', + AwaitExpression: 'AwaitExpression', + BigIntLiteral: 'BigIntLiteral', + BinaryExpression: 'BinaryExpression', + BindExpression: 'BindExpression', + BlockStatement: 'BlockStatement', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ClassBody: 'ClassBody', + ClassDeclaration: 'ClassDeclaration', + ClassExpression: 'ClassExpression', + ClassPrivateProperty: 'ClassPrivateProperty', + ClassProperty: 'ClassProperty', + ComprehensionBlock: 'ComprehensionBlock', + ComprehensionExpression: 'ComprehensionExpression', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + Decorator: 'Decorator', + DoExpression: 'DoExpression', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExperimentalRestProperty: 'ExperimentalRestProperty', + ExperimentalSpreadProperty: 'ExperimentalSpreadProperty', + ExportAllDeclaration: 'ExportAllDeclaration', + ExportDefaultDeclaration: 'ExportDefaultDeclaration', + ExportDefaultSpecifier: 'ExportDefaultSpecifier', + ExportNamedDeclaration: 'ExportNamedDeclaration', + ExportNamespaceSpecifier: 'ExportNamespaceSpecifier', + ExportSpecifier: 'ExportSpecifier', + ExpressionStatement: 'ExpressionStatement', + File: 'File', + ForInStatement: 'ForInStatement', + ForOfStatement: 'ForOfStatement', + ForStatement: 'ForStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Import: 'Import', + ImportDeclaration: 'ImportDeclaration', + ImportDefaultSpecifier: 'ImportDefaultSpecifier', + ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', + ImportSpecifier: 'ImportSpecifier', + JSXAttribute: 'JSXAttribute', + JSXClosingElement: 'JSXClosingElement', + JSXElement: 'JSXElement', + JSXEmptyExpression: 'JSXEmptyExpression', + JSXExpressionContainer: 'JSXExpressionContainer', + JSXIdentifier: 'JSXIdentifier', + JSXMemberExpression: 'JSXMemberExpression', + JSXNamespacedName: 'JSXNamespacedName', + JSXOpeningElement: 'JSXOpeningElement', + JSXSpreadAttribute: 'JSXSpreadAttribute', + JSXText: 'JSXText', + LabeledStatement: 'LabeledStatement', + LetStatement: 'LetStatement', + Literal: 'Literal', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + MetaProperty: 'MetaProperty', + MethodDefinition: 'MethodDefinition', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + PrivateName: 'PrivateName', + Program: 'Program', + Property: 'Property', + RestElement: 'RestElement', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SpreadElement: 'SpreadElement', + Super: 'Super', + SwitchCase: 'SwitchCase', + SwitchStatement: 'SwitchStatement', + TaggedTemplateExpression: 'TaggedTemplateExpression', + TemplateElement: 'TemplateElement', + TemplateLiteral: 'TemplateLiteral', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression', }; diff --git a/packages/jsdoc-parse/test/specs/index.js b/packages/jsdoc-parse/test/specs/index.js index c7878e17..395d3120 100644 --- a/packages/jsdoc-parse/test/specs/index.js +++ b/packages/jsdoc-parse/test/specs/index.js @@ -1,31 +1,31 @@ const parse = require('../../index'); describe('@jsdoc/parse', () => { - it('is an object', () => { - expect(parse).toBeObject(); + it('is an object', () => { + expect(parse).toBeObject(); + }); + + describe('AstBuilder', () => { + it('is lib/ast-builder.AstBuilder', () => { + const { AstBuilder } = require('../../lib/ast-builder'); + + expect(parse.AstBuilder).toBe(AstBuilder); }); + }); - describe('AstBuilder', () => { - it('is lib/ast-builder.AstBuilder', () => { - const { AstBuilder } = require('../../lib/ast-builder'); + describe('astNode', () => { + it('is lib/ast-node', () => { + const astNode = require('../../lib/ast-node'); - expect(parse.AstBuilder).toBe(AstBuilder); - }); + expect(parse.astNode).toBe(astNode); }); + }); - describe('astNode', () => { - it('is lib/ast-node', () => { - const astNode = require('../../lib/ast-node'); + describe('Syntax', () => { + it('is lib/syntax.Syntax', () => { + const { Syntax } = require('../../lib/syntax'); - expect(parse.astNode).toBe(astNode); - }); - }); - - describe('Syntax', () => { - it('is lib/syntax.Syntax', () => { - const { Syntax } = require('../../lib/syntax'); - - expect(parse.Syntax).toBe(Syntax); - }); + expect(parse.Syntax).toBe(Syntax); }); + }); }); diff --git a/packages/jsdoc-parse/test/specs/lib/ast-builder.js b/packages/jsdoc-parse/test/specs/lib/ast-builder.js index 44f6f459..e8cc17bd 100644 --- a/packages/jsdoc-parse/test/specs/lib/ast-builder.js +++ b/packages/jsdoc-parse/test/specs/lib/ast-builder.js @@ -1,41 +1,41 @@ /* global jsdoc */ describe('@jsdoc/parse/lib/ast-builder', () => { - const astBuilder = require('../../../lib/ast-builder'); + const astBuilder = require('../../../lib/ast-builder'); - it('is an object', () => { - expect(astBuilder).toBeObject(); + it('is an object', () => { + expect(astBuilder).toBeObject(); + }); + + it('exports an AstBuilder class', () => { + expect(astBuilder.AstBuilder).toBeFunction(); + }); + + it('exports a parserOptions object', () => { + expect(astBuilder.parserOptions).toBeObject(); + }); + + describe('AstBuilder', () => { + const { AstBuilder } = astBuilder; + + // TODO: more tests + it('has a "build" static method', () => { + expect(AstBuilder.build).toBeFunction(); }); - it('exports an AstBuilder class', () => { - expect(astBuilder.AstBuilder).toBeFunction(); + describe('build', () => { + // TODO: more tests + it('logs (not throws) an error when a file cannot be parsed', () => { + function parse() { + AstBuilder.build('qwerty!!!!!', 'bad.js'); + } + + expect(parse).not.toThrow(); + expect(jsdoc.didLog(parse, 'error')).toBeTrue(); + }); }); + }); - it('exports a parserOptions object', () => { - expect(astBuilder.parserOptions).toBeObject(); - }); - - describe('AstBuilder', () => { - const { AstBuilder } = astBuilder; - - // TODO: more tests - it('has a "build" static method', () => { - expect(AstBuilder.build).toBeFunction(); - }); - - describe('build', () => { - // TODO: more tests - it('logs (not throws) an error when a file cannot be parsed', () => { - function parse() { - AstBuilder.build('qwerty!!!!!', 'bad.js'); - } - - expect(parse).not.toThrow(); - expect(jsdoc.didLog(parse, 'error')).toBeTrue(); - }); - }); - }); - - describe('parserOptions', () => { - // TODO: tests - }); + describe('parserOptions', () => { + // TODO: tests + }); }); diff --git a/packages/jsdoc-parse/test/specs/lib/ast-node.js b/packages/jsdoc-parse/test/specs/lib/ast-node.js index f427a9f7..b4fca86e 100644 --- a/packages/jsdoc-parse/test/specs/lib/ast-node.js +++ b/packages/jsdoc-parse/test/specs/lib/ast-node.js @@ -1,575 +1,576 @@ describe('@jsdoc/parse/lib/ast-node', () => { - const astNode = require('../../../lib/ast-node'); - const babelParser = require('@babel/parser'); - const { parserOptions } = require('../../../lib/ast-builder'); - const { Syntax } = require('../../../lib/syntax'); + const astNode = require('../../../lib/ast-node'); + const babelParser = require('@babel/parser'); + const { parserOptions } = require('../../../lib/ast-builder'); + const { Syntax } = require('../../../lib/syntax'); - function parse(str) { - return babelParser.parse(str, parserOptions).program.body[0]; - } + function parse(str) { + return babelParser.parse(str, parserOptions).program.body[0]; + } - // create the AST nodes we'll be testing - const arrayExpression = parse('[,]').expression; - const arrowFunctionExpression = parse('var foo = () => {};').declarations[0].init; - const assignmentExpression = parse('foo = 1;').expression; - const binaryExpression = parse('foo & foo;').expression; - const experimentalObjectRestSpread = parse('var one = {...two, three: 4};').declarations[0].init; - const functionDeclaration1 = parse('function foo() {}'); - const functionDeclaration2 = parse('function foo(bar) {}'); - const functionDeclaration3 = parse('function foo(bar, baz, qux) {}'); - const functionDeclaration4 = parse('function foo(...bar) {}'); - const functionExpression1 = parse('var foo = function() {};').declarations[0].init; - const functionExpression2 = parse('var foo = function(bar) {};').declarations[0].init; - const identifier = parse('foo;').expression; - const literal = parse('1;').expression; - const memberExpression = parse('foo.bar;').expression; - const memberExpressionComputed1 = parse('foo["bar"];').expression; - const memberExpressionComputed2 = parse('foo[\'bar\'];').expression; - const methodDefinition1 = parse('class Foo { bar() {} }').body.body[0]; - const methodDefinition2 = parse('var foo = () => class { bar() {} };').declarations[0].init.body - .body[0]; - const propertyGet = parse('var foo = { get bar() {} };').declarations[0].init.properties[0]; - const propertyInit = parse('var foo = { bar: {} };').declarations[0].init.properties[0]; - const propertySet = parse('var foo = { set bar(a) {} };').declarations[0].init.properties[0]; - const thisExpression = parse('this;').expression; - const unaryExpression1 = parse('+1;').expression; - const unaryExpression2 = parse('+foo;').expression; - const variableDeclarator1 = parse('var foo = 1;').declarations[0]; - const variableDeclarator2 = parse('var foo;').declarations[0]; + // create the AST nodes we'll be testing + const arrayExpression = parse('[,]').expression; + const arrowFunctionExpression = parse('var foo = () => {};').declarations[0].init; + const assignmentExpression = parse('foo = 1;').expression; + const binaryExpression = parse('foo & foo;').expression; + const experimentalObjectRestSpread = parse('var one = {...two, three: 4};').declarations[0].init; + const functionDeclaration1 = parse('function foo() {}'); + const functionDeclaration2 = parse('function foo(bar) {}'); + const functionDeclaration3 = parse('function foo(bar, baz, qux) {}'); + const functionDeclaration4 = parse('function foo(...bar) {}'); + const functionExpression1 = parse('var foo = function() {};').declarations[0].init; + const functionExpression2 = parse('var foo = function(bar) {};').declarations[0].init; + const identifier = parse('foo;').expression; + const literal = parse('1;').expression; + const memberExpression = parse('foo.bar;').expression; + const memberExpressionComputed1 = parse('foo["bar"];').expression; + const memberExpressionComputed2 = parse("foo['bar'];").expression; + const methodDefinition1 = parse('class Foo { bar() {} }').body.body[0]; + const methodDefinition2 = parse('var foo = () => class { bar() {} };').declarations[0].init.body + .body[0]; + const propertyGet = parse('var foo = { get bar() {} };').declarations[0].init.properties[0]; + const propertyInit = parse('var foo = { bar: {} };').declarations[0].init.properties[0]; + const propertySet = parse('var foo = { set bar(a) {} };').declarations[0].init.properties[0]; + const thisExpression = parse('this;').expression; + const unaryExpression1 = parse('+1;').expression; + const unaryExpression2 = parse('+foo;').expression; + const variableDeclarator1 = parse('var foo = 1;').declarations[0]; + const variableDeclarator2 = parse('var foo;').declarations[0]; - it('should exist', () => { - expect(astNode).toBeObject(); + it('should exist', () => { + expect(astNode).toBeObject(); + }); + + it('should export an addNodeProperties method', () => { + expect(astNode.addNodeProperties).toBeFunction(); + }); + + it('should export a getInfo method', () => { + expect(astNode.getInfo).toBeFunction(); + }); + + it('should export a getParamNames method', () => { + expect(astNode.getParamNames).toBeFunction(); + }); + + it('should export an isAccessor method', () => { + expect(astNode.isAccessor).toBeFunction(); + }); + + it('should export an isAssignment method', () => { + expect(astNode.isAssignment).toBeFunction(); + }); + + it('should export an isFunction method', () => { + expect(astNode.isFunction).toBeFunction(); + }); + + it('should export an isScope method', () => { + expect(astNode.isScope).toBeFunction(); + }); + + it('should export a nodeToString method', () => { + expect(astNode.nodeToString).toBeFunction(); + }); + + it('should export a nodeToValue method', () => { + expect(astNode.nodeToValue).toBeFunction(); + }); + + describe('addNodeProperties', () => { + it('should return null for undefined input', () => { + expect(astNode.addNodeProperties()).toBe(null); }); - it('should export an addNodeProperties method', () => { - expect(astNode.addNodeProperties).toBeFunction(); + it('should return null if the input is not an object', () => { + expect(astNode.addNodeProperties('foo')).toBe(null); }); - it('should export a getInfo method', () => { - expect(astNode.getInfo).toBeFunction(); + it('should preserve existing properties that are not "node properties"', () => { + const node = astNode.addNodeProperties({ foo: 1 }); + + expect(node).toBeObject(); + expect(node.foo).toBe(1); }); - it('should export a getParamNames method', () => { - expect(astNode.getParamNames).toBeFunction(); + it('should add a nodeId if necessary', () => { + const node = astNode.addNodeProperties({}); + const descriptor = Object.getOwnPropertyDescriptor(node, 'nodeId'); + + expect(descriptor).toBeObject(); + expect(descriptor.value).toBeString(); + expect(descriptor.enumerable).toBeTrue(); }); - it('should export an isAccessor method', () => { - expect(astNode.isAccessor).toBeFunction(); + it('should not overwrite an existing nodeId', () => { + const nodeId = 'foo'; + const node = astNode.addNodeProperties({ nodeId: nodeId }); + + expect(node.nodeId).toBe(nodeId); }); - it('should export an isAssignment method', () => { - expect(astNode.isAssignment).toBeFunction(); + it('should add a non-enumerable, writable parent if necessary', () => { + const node = astNode.addNodeProperties({}); + const descriptor = Object.getOwnPropertyDescriptor(node, 'parent'); + + expect(descriptor).toBeDefined(); + expect(descriptor.value).toBeUndefined(); + expect(descriptor.enumerable).toBeFalse(); + expect(descriptor.writable).toBeTrue(); }); - it('should export an isFunction method', () => { - expect(astNode.isFunction).toBeFunction(); + it('should not overwrite an existing parent', () => { + const parent = {}; + const node = astNode.addNodeProperties({ parent: parent }); + + expect(node.parent).toBe(parent); }); - it('should export an isScope method', () => { - expect(astNode.isScope).toBeFunction(); + it('should not overwrite a null parent', () => { + const node = astNode.addNodeProperties({ parent: null }); + + expect(node.parent).toBeNull(); }); - it('should export a nodeToString method', () => { - expect(astNode.nodeToString).toBeFunction(); + it('should add an enumerable parentId', () => { + const node = astNode.addNodeProperties({}); + const descriptor = Object.getOwnPropertyDescriptor(node, 'parentId'); + + expect(descriptor).toBeObject(); + expect(descriptor.enumerable).toBeTrue(); }); - it('should export a nodeToValue method', () => { - expect(astNode.nodeToValue).toBeFunction(); + it('should provide a null parentId for nodes with no parent', () => { + const node = astNode.addNodeProperties({}); + + expect(node.parentId).toBeNull(); }); - describe('addNodeProperties', () => { - it('should return null for undefined input', () => { - expect( astNode.addNodeProperties() ).toBe(null); - }); + it('should provide a non-null parentId for nodes with a parent', () => { + const node = astNode.addNodeProperties({}); + const parent = astNode.addNodeProperties({}); - it('should return null if the input is not an object', () => { - expect( astNode.addNodeProperties('foo') ).toBe(null); - }); + node.parent = parent; - it('should preserve existing properties that are not "node properties"', () => { - const node = astNode.addNodeProperties({foo: 1}); - - expect(node).toBeObject(); - expect(node.foo).toBe(1); - }); - - it('should add a nodeId if necessary', () => { - const node = astNode.addNodeProperties({}); - const descriptor = Object.getOwnPropertyDescriptor(node, 'nodeId'); - - expect(descriptor).toBeObject(); - expect(descriptor.value).toBeString(); - expect(descriptor.enumerable).toBeTrue(); - }); - - it('should not overwrite an existing nodeId', () => { - const nodeId = 'foo'; - const node = astNode.addNodeProperties({nodeId: nodeId}); - - expect(node.nodeId).toBe(nodeId); - }); - - it('should add a non-enumerable, writable parent if necessary', () => { - const node = astNode.addNodeProperties({}); - const descriptor = Object.getOwnPropertyDescriptor(node, 'parent'); - - expect(descriptor).toBeDefined(); - expect(descriptor.value).toBeUndefined(); - expect(descriptor.enumerable).toBeFalse(); - expect(descriptor.writable).toBeTrue(); - }); - - it('should not overwrite an existing parent', () => { - const parent = {}; - const node = astNode.addNodeProperties({parent: parent}); - - expect(node.parent).toBe(parent); - }); - - it('should not overwrite a null parent', () => { - const node = astNode.addNodeProperties({parent: null}); - - expect(node.parent).toBeNull(); - }); - - it('should add an enumerable parentId', () => { - const node = astNode.addNodeProperties({}); - const descriptor = Object.getOwnPropertyDescriptor(node, 'parentId'); - - expect(descriptor).toBeObject(); - expect(descriptor.enumerable).toBeTrue(); - }); - - it('should provide a null parentId for nodes with no parent', () => { - const node = astNode.addNodeProperties({}); - - expect(node.parentId).toBeNull(); - }); - - it('should provide a non-null parentId for nodes with a parent', () => { - const node = astNode.addNodeProperties({}); - const parent = astNode.addNodeProperties({}); - - node.parent = parent; - - expect(node.parentId).toBe(parent.nodeId); - }); - - it('should add a non-enumerable, writable enclosingScope if necessary', () => { - const node = astNode.addNodeProperties({}); - const descriptor = Object.getOwnPropertyDescriptor(node, 'enclosingScope'); - - expect(descriptor).toBeObject(); - expect(descriptor.value).toBeUndefined(); - expect(descriptor.enumerable).toBeFalse(); - expect(descriptor.writable).toBeTrue(); - }); - - it('should not overwrite an existing enclosingScope', () => { - const enclosingScope = {}; - const node = astNode.addNodeProperties({enclosingScope: enclosingScope}); - - expect(node.enclosingScope).toBe(enclosingScope); - }); - - it('should not overwrite a null enclosingScope', () => { - const node = astNode.addNodeProperties({enclosingScope: null}); - - expect(node.enclosingScope).toBeNull(); - }); - - it('should add an enumerable enclosingScopeId', () => { - const node = astNode.addNodeProperties({}); - const descriptor = Object.getOwnPropertyDescriptor(node, 'enclosingScopeId'); - - expect(descriptor).toBeObject(); - expect(descriptor.enumerable).toBeTrue(); - }); - - it('should provide a null enclosingScopeId for nodes with no enclosing scope', () => { - const node = astNode.addNodeProperties({}); - - expect(node.enclosingScopeId).toBeNull(); - }); - - it('should provide a non-null enclosingScopeId for nodes with an enclosing scope', () => { - const node = astNode.addNodeProperties({}); - const enclosingScope = astNode.addNodeProperties({}); - - node.enclosingScope = enclosingScope; - - expect(node.enclosingScopeId).toBe(enclosingScope.nodeId); - }); + expect(node.parentId).toBe(parent.nodeId); }); - describe('getInfo', () => { - it('should throw an error for undefined input', () => { - function noNode() { - astNode.getInfo(); - } + it('should add a non-enumerable, writable enclosingScope if necessary', () => { + const node = astNode.addNodeProperties({}); + const descriptor = Object.getOwnPropertyDescriptor(node, 'enclosingScope'); - expect(noNode).toThrow(); - }); - - it('should return the correct info for an AssignmentExpression', () => { - const info = astNode.getInfo(assignmentExpression); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.Literal); - expect(info.node.value).toBe(1); - - expect(info.name).toBe('foo'); - expect(info.type).toBe(Syntax.Literal); - expect(info.value).toBe(1); - }); - - it('should return the correct info for a FunctionDeclaration', () => { - const info = astNode.getInfo(functionDeclaration2); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.FunctionDeclaration); - - expect(info.name).toBe('foo'); - expect(info.type).toBe(Syntax.FunctionDeclaration); - expect(info.value).toBeUndefined(); - - expect(info.paramnames).toBeArrayOfSize(1); - expect(info.paramnames[0]).toBe('bar'); - }); - - it('should return the correct info for a FunctionExpression', () => { - const info = astNode.getInfo(functionExpression2); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.FunctionExpression); - - expect(info.name).toBe(''); - expect(info.type).toBe(Syntax.FunctionExpression); - expect(info.value).toBeUndefined(); - - expect(info.paramnames).toBeArrayOfSize(1); - expect(info.paramnames[0]).toBe('bar'); - }); - - it('should return the correct info for a MemberExpression', () => { - const info = astNode.getInfo(memberExpression); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.MemberExpression); - - expect(info.name).toBe('foo.bar'); - expect(info.type).toBe(Syntax.MemberExpression); - }); - - it('should return the correct info for a computed MemberExpression', () => { - const info = astNode.getInfo(memberExpressionComputed1); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.MemberExpression); - - expect(info.name).toBe('foo["bar"]'); - expect(info.type).toBe(Syntax.MemberExpression); - }); - - it('should return the correct info for a Property initializer', () => { - const info = astNode.getInfo(propertyInit); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.ObjectExpression); - - expect(info.name).toBe('bar'); - expect(info.type).toBe(Syntax.ObjectExpression); - }); - - it('should return the correct info for a Property setter', () => { - const info = astNode.getInfo(propertySet); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.FunctionExpression); - - expect(info.name).toBe('bar'); - expect(info.type).toBeUndefined(); - expect(info.value).toBeUndefined(); - - expect(info.paramnames).toBeArrayOfSize(1); - expect(info.paramnames[0]).toBe('a'); - }); - - it('should return the correct info for a VariableDeclarator with a value', () => { - const info = astNode.getInfo(variableDeclarator1); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.Literal); - - expect(info.name).toBe('foo'); - expect(info.type).toBe(Syntax.Literal); - expect(info.value).toBe(1); - }); - - it('should return the correct info for a VariableDeclarator with no value', () => { - const info = astNode.getInfo(variableDeclarator2); - - expect(info).toBeObject(); - - expect(info.node).toBeObject(); - expect(info.node.type).toBe(Syntax.Identifier); - - expect(info.name).toBe('foo'); - expect(info.type).toBeUndefined(); - expect(info.value).toBeUndefined(); - }); - - it('should return the correct info for other node types', () => { - const info = astNode.getInfo(binaryExpression); - - expect(info).toBeObject(); - - expect(info.node).toBe(binaryExpression); - expect(info.type).toBe(Syntax.BinaryExpression); - }); + expect(descriptor).toBeObject(); + expect(descriptor.value).toBeUndefined(); + expect(descriptor.enumerable).toBeFalse(); + expect(descriptor.writable).toBeTrue(); }); - describe('getParamNames', () => { - it('should return an empty array for undefined input', () => { - const params = astNode.getParamNames(); + it('should not overwrite an existing enclosingScope', () => { + const enclosingScope = {}; + const node = astNode.addNodeProperties({ enclosingScope: enclosingScope }); - expect(params).toBeEmptyArray(); - }); - - it('should return an empty array if the input has no params property', () => { - const params = astNode.getParamNames({}); - - expect(params).toBeEmptyArray(); - }); - - it('should return an empty array if the input has no params', () => { - const params = astNode.getParamNames(functionDeclaration1); - - expect(params).toBeEmptyArray(); - }); - - it('should return a single-item array if the input has a single param', () => { - const params = astNode.getParamNames(functionDeclaration2); - - expect(params).toEqual(['bar']); - }); - - it('should return a multi-item array if the input has multiple params', () => { - const params = astNode.getParamNames(functionDeclaration3); - - expect(params).toEqual([ - 'bar', - 'baz', - 'qux' - ]); - }); - - it('should include rest parameters', () => { - const params = astNode.getParamNames(functionDeclaration4); - - expect(params).toEqual(['bar']); - }); + expect(node.enclosingScope).toBe(enclosingScope); }); - describe('isAccessor', () => { - it('should return false for undefined values', () => { - expect( astNode.isAccessor() ).toBeFalse(); - }); + it('should not overwrite a null enclosingScope', () => { + const node = astNode.addNodeProperties({ enclosingScope: null }); - it('should return false if the parameter is not an object', () => { - expect( astNode.isAccessor('foo') ).toBeFalse(); - }); - - it('should return false for non-Property nodes', () => { - expect( astNode.isAccessor(binaryExpression) ).toBeFalse(); - }); - - it('should return false for Property nodes whose kind is "init"', () => { - expect( astNode.isAccessor(propertyInit) ).toBeFalse(); - }); - - it('should return true for Property nodes whose kind is "get"', () => { - expect( astNode.isAccessor(propertyGet) ).toBeTrue(); - }); - - it('should return true for Property nodes whose kind is "set"', () => { - expect( astNode.isAccessor(propertySet) ).toBeTrue(); - }); + expect(node.enclosingScope).toBeNull(); }); - describe('isAssignment', () => { - it('should return false for undefined values', () => { - expect( astNode.isAssignment() ).toBeFalse(); - }); + it('should add an enumerable enclosingScopeId', () => { + const node = astNode.addNodeProperties({}); + const descriptor = Object.getOwnPropertyDescriptor(node, 'enclosingScopeId'); - it('should return false if the parameter is not an object', () => { - expect( astNode.isAssignment('foo') ).toBeFalse(); - }); - - it('should return false for nodes that are not assignments', () => { - expect( astNode.isAssignment(binaryExpression) ).toBeFalse(); - }); - - it('should return true for AssignmentExpression nodes', () => { - expect( astNode.isAssignment(assignmentExpression) ).toBeTrue(); - }); - - it('should return true for VariableDeclarator nodes', () => { - expect( astNode.isAssignment(variableDeclarator1) ).toBeTrue(); - }); + expect(descriptor).toBeObject(); + expect(descriptor.enumerable).toBeTrue(); }); - describe('isFunction', () => { - it('should recognize function declarations as functions', () => { - expect( astNode.isFunction(functionDeclaration1) ).toBeTrue(); - }); + it('should provide a null enclosingScopeId for nodes with no enclosing scope', () => { + const node = astNode.addNodeProperties({}); - it('should recognize function expressions as functions', () => { - expect( astNode.isFunction(functionExpression1) ).toBeTrue(); - }); - - it('should recognize method definitions as functions', () => { - expect( astNode.isFunction(methodDefinition1) ).toBeTrue(); - }); - - it('should recognize arrow function expressions as functions', () => { - expect( astNode.isFunction(arrowFunctionExpression) ).toBeTrue(); - }); - - it('should recognize non-functions', () => { - expect( astNode.isFunction(arrayExpression) ).toBeFalse(); - }); + expect(node.enclosingScopeId).toBeNull(); }); - describe('isScope', () => { - it('should return false for undefined values', () => { - expect( astNode.isScope() ).toBeFalse(); - }); + it('should provide a non-null enclosingScopeId for nodes with an enclosing scope', () => { + const node = astNode.addNodeProperties({}); + const enclosingScope = astNode.addNodeProperties({}); - it('should return false if the parameter is not an object', () => { - expect( astNode.isScope('foo') ).toBeFalse(); - }); + node.enclosingScope = enclosingScope; - it('should return true for CatchClause nodes', () => { - expect( astNode.isScope({type: Syntax.CatchClause}) ).toBeTrue(); - }); + expect(node.enclosingScopeId).toBe(enclosingScope.nodeId); + }); + }); - it('should return true for FunctionDeclaration nodes', () => { - expect( astNode.isScope({type: Syntax.FunctionDeclaration}) ).toBeTrue(); - }); + describe('getInfo', () => { + it('should throw an error for undefined input', () => { + function noNode() { + astNode.getInfo(); + } - it('should return true for FunctionExpression nodes', () => { - expect( astNode.isScope({type: Syntax.FunctionExpression}) ).toBeTrue(); - }); - - it('should return false for other nodes', () => { - expect( astNode.isScope({type: Syntax.NameExpression}) ).toBeFalse(); - }); + expect(noNode).toThrow(); }); - describe('nodeToString', () => { - it('should be an alias to nodeToValue', () => { - expect(astNode.nodeToString).toBe(astNode.nodeToValue); - }); + it('should return the correct info for an AssignmentExpression', () => { + const info = astNode.getInfo(assignmentExpression); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.Literal); + expect(info.node.value).toBe(1); + + expect(info.name).toBe('foo'); + expect(info.type).toBe(Syntax.Literal); + expect(info.value).toBe(1); }); - describe('nodeToValue', () => { - it('should return `[null]` for the sparse array `[,]`', () => { - expect( astNode.nodeToValue(arrayExpression) ).toBe('[null]'); - }); + it('should return the correct info for a FunctionDeclaration', () => { + const info = astNode.getInfo(functionDeclaration2); - it('should return the variable name for assignment expressions', () => { - expect( astNode.nodeToValue(assignmentExpression) ).toBe('foo'); - }); + expect(info).toBeObject(); - it('should return the function name for function declarations', () => { - expect( astNode.nodeToValue(functionDeclaration1) ).toBe('foo'); - }); + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.FunctionDeclaration); - it('should return undefined for anonymous function expressions', () => { - expect( astNode.nodeToValue(functionExpression1) ).toBeUndefined(); - }); + expect(info.name).toBe('foo'); + expect(info.type).toBe(Syntax.FunctionDeclaration); + expect(info.value).toBeUndefined(); - it('should return the identifier name for identifiers', () => { - expect( astNode.nodeToValue(identifier) ).toBe('foo'); - }); - - it('should return the literal value for literals', () => { - expect( astNode.nodeToValue(literal) ).toBe(1); - }); - - it('should return the object and property for noncomputed member expressions', () => { - expect( astNode.nodeToValue(memberExpression) ).toBe('foo.bar'); - }); - - it('should return the object and property, with a computed property that uses the same ' + - 'quote character as the original source, for computed member expressions', () => { - expect( astNode.nodeToValue(memberExpressionComputed1) ).toBe('foo["bar"]'); - expect( astNode.nodeToValue(memberExpressionComputed2) ).toBe('foo[\'bar\']'); - }); - - // TODO: we can't test this here because JSDoc, not Babylon, adds the `parent` property to - // nodes. also, we currently return an empty string instead of `` in this case; - // see `module:@jsdoc/parse.astNode.nodeToValue` and the comment on - // `Syntax.MethodDefinition` for details - xit('should return `` for method definitions inside classes that were ' + - 'returned by an arrow function expression', () => { - expect( astNode.nodeToValue(methodDefinition2) ).toBe(''); - }); - - it('should return "this" for this expressions', () => { - expect( astNode.nodeToValue(thisExpression) ).toBe('this'); - }); - - it('should return the operator and nodeToValue value for prefix unary expressions', - () => { - expect( astNode.nodeToValue(unaryExpression1) ).toBe('+1'); - expect( astNode.nodeToValue(unaryExpression2) ).toBe('+foo'); - }); - - it('should throw an error for postfix unary expressions', () => { - function postfixNodeToValue() { - // there's no valid source representation for this one, so we fake it - const unaryExpressionPostfix = (() => { - const node = parse('+1;').body[0].expression; - - node.prefix = false; - - return node; - })(); - - return astNode.nodeToValue(unaryExpressionPostfix); - } - - expect(postfixNodeToValue).toThrow(); - }); - - it('should return the variable name for variable declarators', () => { - expect( astNode.nodeToValue(variableDeclarator1) ).toBe('foo'); - }); - - it('should return an empty string for all other nodes', () => { - expect( astNode.nodeToValue(binaryExpression) ).toBe(''); - }); - - it('should understand and ignore ExperimentalSpreadProperty', () => { - expect( astNode.nodeToValue(experimentalObjectRestSpread) ).toBe('{"three":4}'); - }); + expect(info.paramnames).toBeArrayOfSize(1); + expect(info.paramnames[0]).toBe('bar'); }); + + it('should return the correct info for a FunctionExpression', () => { + const info = astNode.getInfo(functionExpression2); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.FunctionExpression); + + expect(info.name).toBe(''); + expect(info.type).toBe(Syntax.FunctionExpression); + expect(info.value).toBeUndefined(); + + expect(info.paramnames).toBeArrayOfSize(1); + expect(info.paramnames[0]).toBe('bar'); + }); + + it('should return the correct info for a MemberExpression', () => { + const info = astNode.getInfo(memberExpression); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.MemberExpression); + + expect(info.name).toBe('foo.bar'); + expect(info.type).toBe(Syntax.MemberExpression); + }); + + it('should return the correct info for a computed MemberExpression', () => { + const info = astNode.getInfo(memberExpressionComputed1); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.MemberExpression); + + expect(info.name).toBe('foo["bar"]'); + expect(info.type).toBe(Syntax.MemberExpression); + }); + + it('should return the correct info for a Property initializer', () => { + const info = astNode.getInfo(propertyInit); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.ObjectExpression); + + expect(info.name).toBe('bar'); + expect(info.type).toBe(Syntax.ObjectExpression); + }); + + it('should return the correct info for a Property setter', () => { + const info = astNode.getInfo(propertySet); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.FunctionExpression); + + expect(info.name).toBe('bar'); + expect(info.type).toBeUndefined(); + expect(info.value).toBeUndefined(); + + expect(info.paramnames).toBeArrayOfSize(1); + expect(info.paramnames[0]).toBe('a'); + }); + + it('should return the correct info for a VariableDeclarator with a value', () => { + const info = astNode.getInfo(variableDeclarator1); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.Literal); + + expect(info.name).toBe('foo'); + expect(info.type).toBe(Syntax.Literal); + expect(info.value).toBe(1); + }); + + it('should return the correct info for a VariableDeclarator with no value', () => { + const info = astNode.getInfo(variableDeclarator2); + + expect(info).toBeObject(); + + expect(info.node).toBeObject(); + expect(info.node.type).toBe(Syntax.Identifier); + + expect(info.name).toBe('foo'); + expect(info.type).toBeUndefined(); + expect(info.value).toBeUndefined(); + }); + + it('should return the correct info for other node types', () => { + const info = astNode.getInfo(binaryExpression); + + expect(info).toBeObject(); + + expect(info.node).toBe(binaryExpression); + expect(info.type).toBe(Syntax.BinaryExpression); + }); + }); + + describe('getParamNames', () => { + it('should return an empty array for undefined input', () => { + const params = astNode.getParamNames(); + + expect(params).toBeEmptyArray(); + }); + + it('should return an empty array if the input has no params property', () => { + const params = astNode.getParamNames({}); + + expect(params).toBeEmptyArray(); + }); + + it('should return an empty array if the input has no params', () => { + const params = astNode.getParamNames(functionDeclaration1); + + expect(params).toBeEmptyArray(); + }); + + it('should return a single-item array if the input has a single param', () => { + const params = astNode.getParamNames(functionDeclaration2); + + expect(params).toEqual(['bar']); + }); + + it('should return a multi-item array if the input has multiple params', () => { + const params = astNode.getParamNames(functionDeclaration3); + + expect(params).toEqual(['bar', 'baz', 'qux']); + }); + + it('should include rest parameters', () => { + const params = astNode.getParamNames(functionDeclaration4); + + expect(params).toEqual(['bar']); + }); + }); + + describe('isAccessor', () => { + it('should return false for undefined values', () => { + expect(astNode.isAccessor()).toBeFalse(); + }); + + it('should return false if the parameter is not an object', () => { + expect(astNode.isAccessor('foo')).toBeFalse(); + }); + + it('should return false for non-Property nodes', () => { + expect(astNode.isAccessor(binaryExpression)).toBeFalse(); + }); + + it('should return false for Property nodes whose kind is "init"', () => { + expect(astNode.isAccessor(propertyInit)).toBeFalse(); + }); + + it('should return true for Property nodes whose kind is "get"', () => { + expect(astNode.isAccessor(propertyGet)).toBeTrue(); + }); + + it('should return true for Property nodes whose kind is "set"', () => { + expect(astNode.isAccessor(propertySet)).toBeTrue(); + }); + }); + + describe('isAssignment', () => { + it('should return false for undefined values', () => { + expect(astNode.isAssignment()).toBeFalse(); + }); + + it('should return false if the parameter is not an object', () => { + expect(astNode.isAssignment('foo')).toBeFalse(); + }); + + it('should return false for nodes that are not assignments', () => { + expect(astNode.isAssignment(binaryExpression)).toBeFalse(); + }); + + it('should return true for AssignmentExpression nodes', () => { + expect(astNode.isAssignment(assignmentExpression)).toBeTrue(); + }); + + it('should return true for VariableDeclarator nodes', () => { + expect(astNode.isAssignment(variableDeclarator1)).toBeTrue(); + }); + }); + + describe('isFunction', () => { + it('should recognize function declarations as functions', () => { + expect(astNode.isFunction(functionDeclaration1)).toBeTrue(); + }); + + it('should recognize function expressions as functions', () => { + expect(astNode.isFunction(functionExpression1)).toBeTrue(); + }); + + it('should recognize method definitions as functions', () => { + expect(astNode.isFunction(methodDefinition1)).toBeTrue(); + }); + + it('should recognize arrow function expressions as functions', () => { + expect(astNode.isFunction(arrowFunctionExpression)).toBeTrue(); + }); + + it('should recognize non-functions', () => { + expect(astNode.isFunction(arrayExpression)).toBeFalse(); + }); + }); + + describe('isScope', () => { + it('should return false for undefined values', () => { + expect(astNode.isScope()).toBeFalse(); + }); + + it('should return false if the parameter is not an object', () => { + expect(astNode.isScope('foo')).toBeFalse(); + }); + + it('should return true for CatchClause nodes', () => { + expect(astNode.isScope({ type: Syntax.CatchClause })).toBeTrue(); + }); + + it('should return true for FunctionDeclaration nodes', () => { + expect(astNode.isScope({ type: Syntax.FunctionDeclaration })).toBeTrue(); + }); + + it('should return true for FunctionExpression nodes', () => { + expect(astNode.isScope({ type: Syntax.FunctionExpression })).toBeTrue(); + }); + + it('should return false for other nodes', () => { + expect(astNode.isScope({ type: Syntax.NameExpression })).toBeFalse(); + }); + }); + + describe('nodeToString', () => { + it('should be an alias to nodeToValue', () => { + expect(astNode.nodeToString).toBe(astNode.nodeToValue); + }); + }); + + describe('nodeToValue', () => { + it('should return `[null]` for the sparse array `[,]`', () => { + expect(astNode.nodeToValue(arrayExpression)).toBe('[null]'); + }); + + it('should return the variable name for assignment expressions', () => { + expect(astNode.nodeToValue(assignmentExpression)).toBe('foo'); + }); + + it('should return the function name for function declarations', () => { + expect(astNode.nodeToValue(functionDeclaration1)).toBe('foo'); + }); + + it('should return undefined for anonymous function expressions', () => { + expect(astNode.nodeToValue(functionExpression1)).toBeUndefined(); + }); + + it('should return the identifier name for identifiers', () => { + expect(astNode.nodeToValue(identifier)).toBe('foo'); + }); + + it('should return the literal value for literals', () => { + expect(astNode.nodeToValue(literal)).toBe(1); + }); + + it('should return the object and property for noncomputed member expressions', () => { + expect(astNode.nodeToValue(memberExpression)).toBe('foo.bar'); + }); + + it( + 'should return the object and property, with a computed property that uses the same ' + + 'quote character as the original source, for computed member expressions', + () => { + expect(astNode.nodeToValue(memberExpressionComputed1)).toBe('foo["bar"]'); + expect(astNode.nodeToValue(memberExpressionComputed2)).toBe("foo['bar']"); + } + ); + + // TODO: we can't test this here because JSDoc, not Babylon, adds the `parent` property to + // nodes. also, we currently return an empty string instead of `` in this case; + // see `module:@jsdoc/parse.astNode.nodeToValue` and the comment on + // `Syntax.MethodDefinition` for details + xit( + 'should return `` for method definitions inside classes that were ' + + 'returned by an arrow function expression', + () => { + expect(astNode.nodeToValue(methodDefinition2)).toBe(''); + } + ); + + it('should return "this" for this expressions', () => { + expect(astNode.nodeToValue(thisExpression)).toBe('this'); + }); + + it('should return the operator and nodeToValue value for prefix unary expressions', () => { + expect(astNode.nodeToValue(unaryExpression1)).toBe('+1'); + expect(astNode.nodeToValue(unaryExpression2)).toBe('+foo'); + }); + + it('should throw an error for postfix unary expressions', () => { + function postfixNodeToValue() { + // there's no valid source representation for this one, so we fake it + const unaryExpressionPostfix = (() => { + const node = parse('+1;').body[0].expression; + + node.prefix = false; + + return node; + })(); + + return astNode.nodeToValue(unaryExpressionPostfix); + } + + expect(postfixNodeToValue).toThrow(); + }); + + it('should return the variable name for variable declarators', () => { + expect(astNode.nodeToValue(variableDeclarator1)).toBe('foo'); + }); + + it('should return an empty string for all other nodes', () => { + expect(astNode.nodeToValue(binaryExpression)).toBe(''); + }); + + it('should understand and ignore ExperimentalSpreadProperty', () => { + expect(astNode.nodeToValue(experimentalObjectRestSpread)).toBe('{"three":4}'); + }); + }); }); diff --git a/packages/jsdoc-parse/test/specs/lib/syntax.js b/packages/jsdoc-parse/test/specs/lib/syntax.js index 5bf87438..caa55dc7 100644 --- a/packages/jsdoc-parse/test/specs/lib/syntax.js +++ b/packages/jsdoc-parse/test/specs/lib/syntax.js @@ -1,13 +1,13 @@ describe('@jsdoc/parse.Syntax', () => { - const { Syntax } = require('../../../index'); + const { Syntax } = require('../../../index'); - it('is an object', () => { - expect(Syntax).toBeObject(); - }); + it('is an object', () => { + expect(Syntax).toBeObject(); + }); - it('has values identical to their keys', () => { - for (const key of Object.keys(Syntax)) { - expect(key).toBe(Syntax[key]); - } - }); + it('has values identical to their keys', () => { + for (const key of Object.keys(Syntax)) { + expect(key).toBe(Syntax[key]); + } + }); }); diff --git a/packages/jsdoc-prettier-config/.npmignore b/packages/jsdoc-prettier-config/.npmignore new file mode 100644 index 00000000..c828232d --- /dev/null +++ b/packages/jsdoc-prettier-config/.npmignore @@ -0,0 +1,14 @@ +.editorconfig +.eslintignore +.eslintrc.js +.gitignore +.github/ +.renovaterc.json +.travis.yml +CHANGES.md +CODE_OF_CONDUCT.md +CONTRIBUTING.md +gulpfile.js +lerna.json +packages/ +test/ diff --git a/packages/jsdoc-prettier-config/LICENSE b/packages/jsdoc-prettier-config/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/packages/jsdoc-prettier-config/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/packages/jsdoc-prettier-config/README.md b/packages/jsdoc-prettier-config/README.md new file mode 100644 index 00000000..2048a499 --- /dev/null +++ b/packages/jsdoc-prettier-config/README.md @@ -0,0 +1,3 @@ +# `@jsdoc/prettier-config` + +A Prettier (https://prettier.io/) configuration for JSDoc. diff --git a/packages/jsdoc-prettier-config/index.js b/packages/jsdoc-prettier-config/index.js new file mode 100644 index 00000000..2708d326 --- /dev/null +++ b/packages/jsdoc-prettier-config/index.js @@ -0,0 +1,5 @@ +// https://prettier.io/docs/en/options.html +module.exports = { + printWidth: 100, + singleQuote: true, +}; diff --git a/packages/jsdoc-prettier-config/package.json b/packages/jsdoc-prettier-config/package.json new file mode 100644 index 00000000..9125f376 --- /dev/null +++ b/packages/jsdoc-prettier-config/package.json @@ -0,0 +1,31 @@ +{ + "name": "@jsdoc/prettier-config", + "version": "0.0.1", + "description": "A Prettier (https://prettier.io/) configuration for JSDoc.", + "keywords": [ + "prettier", + "jsdoc" + ], + "author": "Jeff Williams ", + "homepage": "https://github.com/jsdoc/jsdoc", + "license": "Apache-2.0", + "main": "index.js", + "peerDependencies": { + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^4.0.0", + "prettier": "^2.4.1" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/jsdoc/jsdoc.git" + }, + "scripts": { + "test": "echo \"Error: run tests from root\" && exit 1" + }, + "bugs": { + "url": "https://github.com/jsdoc/jsdoc/issues" + } +} diff --git a/packages/jsdoc-tag/index.js b/packages/jsdoc-tag/index.js index 33e97901..b5256b7a 100644 --- a/packages/jsdoc-tag/index.js +++ b/packages/jsdoc-tag/index.js @@ -2,6 +2,6 @@ const inline = require('./lib/inline'); const type = require('./lib/type'); module.exports = { - inline, - type + inline, + type, }; diff --git a/packages/jsdoc-tag/lib/inline.js b/packages/jsdoc-tag/lib/inline.js index 3da54f52..7fe1e637 100644 --- a/packages/jsdoc-tag/lib/inline.js +++ b/packages/jsdoc-tag/lib/inline.js @@ -45,7 +45,7 @@ * @returns {RegExp} A regular expression that matches the requested inline tag. */ function regExpFactory(tagName = '\\S+', prefix = '', suffix = '') { - return new RegExp(`${prefix}\\{@${tagName}\\s+((?:.|\n)+?)\\}${suffix}`, 'i'); + return new RegExp(`${prefix}\\{@${tagName}\\s+((?:.|\n)+?)\\}${suffix}`, 'i'); } /** @@ -70,43 +70,43 @@ exports.isInlineTag = (string, tagName) => regExpFactory(tagName, '^', '$').test * @return {module:@jsdoc/tag.inline.InlineTagResult} The updated string, as well as information * about the inline tags that were found. */ -const replaceInlineTags = exports.replaceInlineTags = (string, replacers) => { - const tagInfo = []; +const replaceInlineTags = (exports.replaceInlineTags = (string, replacers) => { + const tagInfo = []; - function replaceMatch(replacer, tag, match, text) { - const matchedTag = { - completeTag: match, - tag: tag, - text: text - }; - - tagInfo.push(matchedTag); - - return replacer(string, matchedTag); - } - - string = string || ''; - - Object.keys(replacers).forEach(replacer => { - const tagRegExp = regExpFactory(replacer); - let matches; - let previousString; - - // call the replacer once for each match - do { - matches = tagRegExp.exec(string); - if (matches) { - previousString = string; - string = replaceMatch(replacers[replacer], replacer, matches[0], matches[1]); - } - } while (matches && previousString !== string); - }); - - return { - tags: tagInfo, - newString: string.trim() + function replaceMatch(replacer, tag, match, text) { + const matchedTag = { + completeTag: match, + tag: tag, + text: text, }; -}; + + tagInfo.push(matchedTag); + + return replacer(string, matchedTag); + } + + string = string || ''; + + Object.keys(replacers).forEach((replacer) => { + const tagRegExp = regExpFactory(replacer); + let matches; + let previousString; + + // call the replacer once for each match + do { + matches = tagRegExp.exec(string); + if (matches) { + previousString = string; + string = replaceMatch(replacers[replacer], replacer, matches[0], matches[1]); + } + } while (matches && previousString !== string); + }); + + return { + tags: tagInfo, + newString: string.trim(), + }; +}); /** * Replace all instances of an inline tag with other text. @@ -118,13 +118,13 @@ const replaceInlineTags = exports.replaceInlineTags = (string, replacers) => { * @return {module:@jsdoc/tag.inline.InlineTagResult} The updated string, as well as information * about the inline tags that were found. */ -const replaceInlineTag = exports.replaceInlineTag = (string, tag, replacer) => { - const replacers = {}; +const replaceInlineTag = (exports.replaceInlineTag = (string, tag, replacer) => { + const replacers = {}; - replacers[tag] = replacer; + replacers[tag] = replacer; - return replaceInlineTags(string, replacers); -}; + return replaceInlineTags(string, replacers); +}); /** * Extract inline tags from a string, replacing them with an empty string. @@ -135,5 +135,4 @@ const replaceInlineTag = exports.replaceInlineTag = (string, tag, replacer) => { * about the inline tags that were found. */ exports.extractInlineTag = (string, tag) => - replaceInlineTag(string, tag, (str, {completeTag}) => - str.replace(completeTag, '')); + replaceInlineTag(string, tag, (str, { completeTag }) => str.replace(completeTag, '')); diff --git a/packages/jsdoc-tag/lib/type.js b/packages/jsdoc-tag/lib/type.js index c36f9327..bd4ea75f 100644 --- a/packages/jsdoc-tag/lib/type.js +++ b/packages/jsdoc-tag/lib/type.js @@ -18,8 +18,7 @@ const { splitNameAndDescription } = require('@jsdoc/core').name; /** @private */ function unescapeBraces(text) { - return text.replace(/\\\{/g, '{') - .replace(/\\\}/g, '}'); + return text.replace(/\\\{/g, '{').replace(/\\\}/g, '}'); } /** @@ -30,87 +29,87 @@ function unescapeBraces(text) { * @return {module:@jsdoc/tag.type.TypeExpressionInfo} The type expression and updated tag text. */ function extractTypeExpression(string) { - let completeExpression; - let count = 0; - let position = 0; - let expression = ''; - const startIndex = string.search(/\{[^@]/); - let textStartIndex; + let completeExpression; + let count = 0; + let position = 0; + let expression = ''; + const startIndex = string.search(/\{[^@]/); + let textStartIndex; - if (startIndex !== -1) { - // advance to the first character in the type expression - position = textStartIndex = startIndex + 1; - count++; + if (startIndex !== -1) { + // advance to the first character in the type expression + position = textStartIndex = startIndex + 1; + count++; - while (position < string.length) { - switch (string[position]) { - case '\\': - // backslash is an escape character, so skip the next character - position++; - break; - case '{': - count++; - break; - case '}': - count--; - break; - default: - // do nothing - } + while (position < string.length) { + switch (string[position]) { + case '\\': + // backslash is an escape character, so skip the next character + position++; + break; + case '{': + count++; + break; + case '}': + count--; + break; + default: + // do nothing + } - if (count === 0) { - completeExpression = string.slice(startIndex, position + 1); - expression = string.slice(textStartIndex, position).trim(); - break; - } + if (count === 0) { + completeExpression = string.slice(startIndex, position + 1); + expression = string.slice(textStartIndex, position).trim(); + break; + } - position++; - } + position++; } + } - string = completeExpression ? string.replace(completeExpression, '') : string; + string = completeExpression ? string.replace(completeExpression, '') : string; - return { - expression: unescapeBraces(expression), - newString: string.trim() - }; + return { + expression: unescapeBraces(expression), + newString: string.trim(), + }; } /** @private */ function getTagInfo(tagValue, canHaveName, canHaveType) { - let name = ''; - let typeExpression = ''; - let text = tagValue; - let expressionAndText; - let nameAndDescription; - let typeOverride; + let name = ''; + let typeExpression = ''; + let text = tagValue; + let expressionAndText; + let nameAndDescription; + let typeOverride; - if (canHaveType) { - expressionAndText = extractTypeExpression(text); - typeExpression = expressionAndText.expression; - text = expressionAndText.newString; + if (canHaveType) { + expressionAndText = extractTypeExpression(text); + typeExpression = expressionAndText.expression; + text = expressionAndText.newString; + } + + if (canHaveName) { + nameAndDescription = splitNameAndDescription(text); + name = nameAndDescription.name; + text = nameAndDescription.description; + } + + // an inline @type tag, like {@type Foo}, overrides the type expression + if (canHaveType) { + typeOverride = extractInlineTag(text, 'type'); + if (typeOverride.tags && typeOverride.tags[0]) { + typeExpression = typeOverride.tags[0].text; } + text = typeOverride.newString; + } - if (canHaveName) { - nameAndDescription = splitNameAndDescription(text); - name = nameAndDescription.name; - text = nameAndDescription.description; - } - - // an inline @type tag, like {@type Foo}, overrides the type expression - if (canHaveType) { - typeOverride = extractInlineTag(text, 'type'); - if (typeOverride.tags && typeOverride.tags[0]) { - typeExpression = typeOverride.tags[0].text; - } - text = typeOverride.newString; - } - - return { - name: name, - typeExpression: typeExpression, - text: text - }; + return { + name: name, + typeExpression: typeExpression, + text: text, + }; } /** @@ -142,80 +141,80 @@ function getTagInfo(tagValue, canHaveName, canHaveType) { * @return {module:@jsdoc/tag.type.TagInfo} Updated information from the tag. */ function parseName(tagInfo) { - // like '[foo]' or '[ foo ]' or '[foo=bar]' or '[ foo=bar ]' or '[ foo = bar ]' - // or 'foo=bar' or 'foo = bar' - if ( /^(\[)?\s*(.+?)\s*(\])?$/.test(tagInfo.name) ) { - tagInfo.name = RegExp.$2; - // were the "optional" brackets present? - if (RegExp.$1 && RegExp.$3) { - tagInfo.optional = true; - } - - // like 'foo=bar' or 'foo = bar' - if ( /^(.+?)\s*=\s*(.+)$/.test(tagInfo.name) ) { - tagInfo.name = RegExp.$1; - tagInfo.defaultvalue = cast(RegExp.$2); - } + // like '[foo]' or '[ foo ]' or '[foo=bar]' or '[ foo=bar ]' or '[ foo = bar ]' + // or 'foo=bar' or 'foo = bar' + if (/^(\[)?\s*(.+?)\s*(\])?$/.test(tagInfo.name)) { + tagInfo.name = RegExp.$2; + // were the "optional" brackets present? + if (RegExp.$1 && RegExp.$3) { + tagInfo.optional = true; } - return tagInfo; + // like 'foo=bar' or 'foo = bar' + if (/^(.+?)\s*=\s*(.+)$/.test(tagInfo.name)) { + tagInfo.name = RegExp.$1; + tagInfo.defaultvalue = cast(RegExp.$2); + } + } + + return tagInfo; } /** @private */ function getTypeStrings(parsedType, isOutermostType) { - let applications; - let typeString; + let applications; + let typeString; - let types = []; + let types = []; - const TYPES = catharsis.Types; + const TYPES = catharsis.Types; - switch (parsedType.type) { - case TYPES.AllLiteral: - types.push('*'); - break; - case TYPES.FunctionType: - types.push('function'); - break; - case TYPES.NameExpression: - types.push(parsedType.name); - break; - case TYPES.NullLiteral: - types.push('null'); - break; - case TYPES.RecordType: - types.push('Object'); - break; - case TYPES.TypeApplication: - // if this is the outermost type, we strip the modifiers; otherwise, we keep them - if (isOutermostType) { - applications = parsedType.applications.map(application => - catharsis.stringify(application)).join(', '); - typeString = `${getTypeStrings(parsedType.expression)[0]}.<${applications}>`; + switch (parsedType.type) { + case TYPES.AllLiteral: + types.push('*'); + break; + case TYPES.FunctionType: + types.push('function'); + break; + case TYPES.NameExpression: + types.push(parsedType.name); + break; + case TYPES.NullLiteral: + types.push('null'); + break; + case TYPES.RecordType: + types.push('Object'); + break; + case TYPES.TypeApplication: + // if this is the outermost type, we strip the modifiers; otherwise, we keep them + if (isOutermostType) { + applications = parsedType.applications + .map((application) => catharsis.stringify(application)) + .join(', '); + typeString = `${getTypeStrings(parsedType.expression)[0]}.<${applications}>`; - types.push(typeString); - } - else { - types.push( catharsis.stringify(parsedType) ); - } - break; - case TYPES.TypeUnion: - parsedType.elements.forEach(element => { - types = types.concat( getTypeStrings(element) ); - }); - break; - case TYPES.UndefinedLiteral: - types.push('undefined'); - break; - case TYPES.UnknownLiteral: - types.push('?'); - break; - default: - // this shouldn't happen - throw new Error(`unrecognized type ${parsedType.type} in parsed type: ${parsedType}`); - } + types.push(typeString); + } else { + types.push(catharsis.stringify(parsedType)); + } + break; + case TYPES.TypeUnion: + parsedType.elements.forEach((element) => { + types = types.concat(getTypeStrings(element)); + }); + break; + case TYPES.UndefinedLiteral: + types.push('undefined'); + break; + case TYPES.UnknownLiteral: + types.push('?'); + break; + default: + // this shouldn't happen + throw new Error(`unrecognized type ${parsedType.type} in parsed type: ${parsedType}`); + } - return types; + return types; } /** @@ -227,40 +226,39 @@ function getTypeStrings(parsedType, isOutermostType) { * @return {module:@jsdoc/tag.type.TagInfo} Updated information from the tag. */ function parseTypeExpression(tagInfo) { - let parsedType; - - // don't try to parse empty type expressions - if (!tagInfo.typeExpression) { - return tagInfo; - } - - try { - parsedType = catharsis.parse(tagInfo.typeExpression, { - jsdoc: true, - useCache: false - }); - } - catch (e) { - // always re-throw so the caller has a chance to report which file was bad - throw new Error(`Invalid type expression "${tagInfo.typeExpression}": ${e.message}`); - } - - tagInfo.type = tagInfo.type.concat( getTypeStrings(parsedType, true) ); - tagInfo.parsedType = parsedType; - - // Catharsis and JSDoc use the same names for 'optional' and 'nullable'... - ['optional', 'nullable'].forEach(key => { - if (parsedType[key] !== null && parsedType[key] !== undefined) { - tagInfo[key] = parsedType[key]; - } - }); - - // ...but not 'variable'. - if (parsedType.repeatable !== null && parsedType.repeatable !== undefined) { - tagInfo.variable = parsedType.repeatable; - } + let parsedType; + // don't try to parse empty type expressions + if (!tagInfo.typeExpression) { return tagInfo; + } + + try { + parsedType = catharsis.parse(tagInfo.typeExpression, { + jsdoc: true, + useCache: false, + }); + } catch (e) { + // always re-throw so the caller has a chance to report which file was bad + throw new Error(`Invalid type expression "${tagInfo.typeExpression}": ${e.message}`); + } + + tagInfo.type = tagInfo.type.concat(getTypeStrings(parsedType, true)); + tagInfo.parsedType = parsedType; + + // Catharsis and JSDoc use the same names for 'optional' and 'nullable'... + ['optional', 'nullable'].forEach((key) => { + if (parsedType[key] !== null && parsedType[key] !== undefined) { + tagInfo[key] = parsedType[key]; + } + }); + + // ...but not 'variable'. + if (parsedType.repeatable !== null && parsedType.repeatable !== undefined) { + tagInfo.variable = parsedType.repeatable; + } + + return tagInfo; } // TODO: allow users to add/remove type parsers (perhaps via plugins) @@ -278,23 +276,23 @@ const typeParsers = [parseName, parseTypeExpression]; * @throws {Error} Thrown if a type expression cannot be parsed. */ exports.parse = (tagValue, canHaveName, canHaveType) => { - let tagInfo; + let tagInfo; - if (typeof tagValue !== 'string') { - tagValue = ''; - } + if (typeof tagValue !== 'string') { + tagValue = ''; + } - tagInfo = getTagInfo(tagValue, canHaveName, canHaveType); - tagInfo.type = tagInfo.type || []; + tagInfo = getTagInfo(tagValue, canHaveName, canHaveType); + tagInfo.type = tagInfo.type || []; - typeParsers.forEach(parser => { - tagInfo = parser(tagInfo); - }); + typeParsers.forEach((parser) => { + tagInfo = parser(tagInfo); + }); - // if we wanted a type, but the parsers didn't add any type names, use the type expression - if (canHaveType && !tagInfo.type.length && tagInfo.typeExpression) { - tagInfo.type = [tagInfo.typeExpression]; - } + // if we wanted a type, but the parsers didn't add any type names, use the type expression + if (canHaveType && !tagInfo.type.length && tagInfo.typeExpression) { + tagInfo.type = [tagInfo.typeExpression]; + } - return tagInfo; + return tagInfo; }; diff --git a/packages/jsdoc-tag/test/specs/index.js b/packages/jsdoc-tag/test/specs/index.js index 0a36eda8..91759634 100644 --- a/packages/jsdoc-tag/test/specs/index.js +++ b/packages/jsdoc-tag/test/specs/index.js @@ -1,23 +1,23 @@ const tag = require('../../index'); describe('@jsdoc/tag', () => { - it('is an object', () => { - expect(tag).toBeObject(); + it('is an object', () => { + expect(tag).toBeObject(); + }); + + describe('inline', () => { + it('is lib/inline', () => { + const inline = require('../../lib/inline'); + + expect(tag.inline).toBe(inline); }); + }); - describe('inline', () => { - it('is lib/inline', () => { - const inline = require('../../lib/inline'); + describe('type', () => { + it('is lib/type', () => { + const type = require('../../lib/type'); - expect(tag.inline).toBe(inline); - }); - }); - - describe('type', () => { - it('is lib/type', () => { - const type = require('../../lib/type'); - - expect(tag.type).toBe(type); - }); + expect(tag.type).toBe(type); }); + }); }); diff --git a/packages/jsdoc-tag/test/specs/lib/inline.js b/packages/jsdoc-tag/test/specs/lib/inline.js index 1aa2ae21..cee6fcbb 100644 --- a/packages/jsdoc-tag/test/specs/lib/inline.js +++ b/packages/jsdoc-tag/test/specs/lib/inline.js @@ -1,256 +1,256 @@ describe('@jsdoc/tag/lib/inline', () => { - const inline = require('../../../lib/inline'); + const inline = require('../../../lib/inline'); - it('is an object', () => { - expect(inline).toBeObject(); + it('is an object', () => { + expect(inline).toBeObject(); + }); + + it('exports an isInlineTag function', () => { + expect(inline.isInlineTag).toBeFunction(); + }); + + it('exports a replaceInlineTag function', () => { + expect(inline.replaceInlineTag).toBeFunction(); + }); + + it('exports an extractInlineTag function', () => { + expect(inline.extractInlineTag).toBeFunction(); + }); + + describe('isInlineTag', () => { + const isInlineTag = inline.isInlineTag; + + it('identifies an inline tag', () => { + expect(isInlineTag('{@mytag hooray}', 'mytag')).toBeTrue(); }); - it('exports an isInlineTag function', () => { - expect(inline.isInlineTag).toBeFunction(); + it('identifies when something is not an inline tag', () => { + expect(isInlineTag('mytag hooray', 'mytag')).toBeFalse(); }); - it('exports a replaceInlineTag function', () => { - expect(inline.replaceInlineTag).toBeFunction(); + it('reports that a string containing an inline tag is not an inline tag', () => { + expect(isInlineTag('this is {@mytag hooray}', 'mytag')).toBeFalse(); }); - it('exports an extractInlineTag function', () => { - expect(inline.extractInlineTag).toBeFunction(); + it('allows any inline tag by default', () => { + expect(isInlineTag('{@anyoldtag will do}')).toBeTrue(); }); - describe('isInlineTag', () => { - const isInlineTag = inline.isInlineTag; - - it('identifies an inline tag', () => { - expect(isInlineTag('{@mytag hooray}', 'mytag')).toBeTrue(); - }); - - it('identifies when something is not an inline tag', () => { - expect(isInlineTag('mytag hooray', 'mytag')).toBeFalse(); - }); - - it('reports that a string containing an inline tag is not an inline tag', () => { - expect(isInlineTag('this is {@mytag hooray}', 'mytag')).toBeFalse(); - }); - - it('allows any inline tag by default', () => { - expect(isInlineTag('{@anyoldtag will do}')).toBeTrue(); - }); - - it('identifies things that are not inline tags when a tag name is not provided', () => { - expect(isInlineTag('mytag hooray')).toBeFalse(); - }); - - it('allows regexp characters in the tag name', () => { - expect( isInlineTag('{@mytags hooray}', 'mytag\\S') ).toBeTrue(); - }); - - it('returns false (rather than throwing) with invalid input', () => { - function badInput() { - return isInlineTag(); - } - - expect(badInput).not.toThrow(); - expect(badInput()).toBeFalse(); - }); + it('identifies things that are not inline tags when a tag name is not provided', () => { + expect(isInlineTag('mytag hooray')).toBeFalse(); }); - describe('replaceInlineTag', () => { - it('throws if the tag is matched and the replacer is invalid', () => { - function badReplacerUndefined() { - inline.replaceInlineTag('{@foo tag}', 'foo'); - } - - function badReplacerString() { - inline.replaceInlineTag('{@foo tag}', 'foo', 'hello'); - } - - expect(badReplacerUndefined).toThrow(); - expect(badReplacerString).toThrow(); - }); - - it('does not find anything if there is no text in braces', () => { - const replacer = jasmine.createSpy('replacer'); - - inline.replaceInlineTag('braceless text', 'foo', replacer); - - expect(replacer).not.toHaveBeenCalled(); - }); - - it('copes with bad escapement at the end of the string', () => { - const replacer = jasmine.createSpy('replacer'); - - inline.replaceInlineTag('bad {@foo escapement \\', 'foo', replacer); - - expect(replacer).not.toHaveBeenCalled(); - }); - - it('works if the tag is the entire string', () => { - function replacer(string, {completeTag, text}) { - expect(string).toBe('{@foo text in braces}'); - expect(completeTag).toBe('{@foo text in braces}'); - expect(text).toBe('text in braces'); - - return completeTag; - } - - const result = inline.replaceInlineTag('{@foo text in braces}', 'foo', - replacer); - - expect(result.tags[0]).toBeObject(); - expect(result.tags[0].tag).toBe('foo'); - expect(result.tags[0].text).toBe('text in braces'); - expect(result.newString).toBe('{@foo text in braces}'); - }); - - it('works if the tag is at the beginning of the string', () => { - function replacer(string, {completeTag, text}) { - expect(string).toBe('{@foo test string} ahoy'); - expect(completeTag).toBe('{@foo test string}'); - expect(text).toBe('test string'); - - return string; - } - - const result = inline.replaceInlineTag('{@foo test string} ahoy', 'foo', - replacer); - - expect(result.tags[0]).toBeObject(); - expect(result.tags[0].tag).toBe('foo'); - expect(result.tags[0].text).toBe('test string'); - expect(result.newString).toBe('{@foo test string} ahoy'); - }); - - it('works if the tag is in the middle of the string', () => { - function replacer(string, {completeTag, text}) { - expect(string).toBe('a {@foo test string} yay'); - expect(completeTag).toBe('{@foo test string}'); - expect(text).toBe('test string'); - - return string; - } - - const result = inline.replaceInlineTag('a {@foo test string} yay', 'foo', - replacer); - - expect(result.tags[0]).toBeObject(); - expect(result.tags[0].tag).toBe('foo'); - expect(result.tags[0].text).toBe('test string'); - expect(result.newString).toBe('a {@foo test string} yay'); - }); - - it('works if the tag is at the end of the string', () => { - function replacer(string, {completeTag, text}) { - expect(string).toBe('a {@foo test string}'); - expect(completeTag).toBe('{@foo test string}'); - expect(text).toBe('test string'); - - return string; - } - - const result = inline.replaceInlineTag('a {@foo test string}', 'foo', replacer); - - expect(result.tags[0]).toBeObject(); - expect(result.tags[0].tag).toBe('foo'); - expect(result.tags[0].text).toBe('test string'); - expect(result.newString).toBe('a {@foo test string}'); - }); - - it('replaces the string with the specified value', () => { - function replacer() { - return 'REPLACED!'; - } - - const result = inline.replaceInlineTag('a {@foo test string}', 'foo', replacer); - - expect(result.newString).toBe('REPLACED!'); - }); - - it('processes all occurrences of a tag', () => { - function replacer(string, {completeTag}) { - return string.replace(completeTag, 'stuff'); - } - - const result = inline.replaceInlineTag('some {@foo text} with multiple ' + - '{@foo tags}, {@foo like} {@foo this}', 'foo', replacer); - - expect(result.tags.length).toBe(4); - - expect(result.tags[0]).toBeObject(); - expect(result.tags[0].tag).toBe('foo'); - expect(result.tags[0].text).toBe('text'); - - expect(result.tags[1]).toBeObject(); - expect(result.tags[1].tag).toBe('foo'); - expect(result.tags[1].text).toBe('tags'); - - expect(result.tags[2]).toBeObject(); - expect(result.tags[2].tag).toBe('foo'); - expect(result.tags[2].text).toBe('like'); - - expect(result.tags[3]).toBeObject(); - expect(result.tags[3].tag).toBe('foo'); - expect(result.tags[3].text).toBe('this'); - - expect(result.newString).toBe('some stuff with multiple stuff, stuff stuff'); - }); + it('allows regexp characters in the tag name', () => { + expect(isInlineTag('{@mytags hooray}', 'mytag\\S')).toBeTrue(); }); - // Largely covered by the `replaceInlineTag()` tests. - describe('replaceInlineTags', () => { - it('works with an empty replacer object', () => { - const replacers = {}; - const text = 'some {@foo text} to parse'; - const result = inline.replaceInlineTags(text, replacers); + it('returns false (rather than throwing) with invalid input', () => { + function badInput() { + return isInlineTag(); + } - expect(result.newString).toBe(text); - }); + expect(badInput).not.toThrow(); + expect(badInput()).toBeFalse(); + }); + }); - it('works with one replacer', () => { - const text = 'some {@foo text} with {@bar multiple} tags'; - const replacers = { - foo(string, tagInfo) { - expect(tagInfo.completeTag).toBe('{@foo text}'); - expect(tagInfo.text).toBe('text'); + describe('replaceInlineTag', () => { + it('throws if the tag is matched and the replacer is invalid', () => { + function badReplacerUndefined() { + inline.replaceInlineTag('{@foo tag}', 'foo'); + } - return string.replace(tagInfo.completeTag, 'stuff'); - } - }; - const result = inline.replaceInlineTags(text, replacers); + function badReplacerString() { + inline.replaceInlineTag('{@foo tag}', 'foo', 'hello'); + } - expect(result.newString).toBe('some stuff with {@bar multiple} tags'); - }); - - it('works with multiple replacers', () => { - const text = 'some {@foo text} with {@bar multiple} tags'; - const replacers = { - foo(string, tagInfo) { - expect(tagInfo.completeTag).toBe('{@foo text}'); - expect(tagInfo.text).toBe('text'); - - return string.replace(tagInfo.completeTag, 'stuff'); - }, - bar(string, tagInfo) { - expect(tagInfo.completeTag).toBe('{@bar multiple}'); - expect(tagInfo.text).toBe('multiple'); - - return string.replace(tagInfo.completeTag, 'awesome'); - } - }; - const result = inline.replaceInlineTags(text, replacers); - - expect(result.newString).toBe('some stuff with awesome tags'); - }); + expect(badReplacerUndefined).toThrow(); + expect(badReplacerString).toThrow(); }); - // Largely covered by the `replaceInlineTag()` tests. - describe('extractInlineTag', () => { - it('works when a tag is specified', () => { - const result = inline.extractInlineTag('some {@tagged text}', 'tagged'); + it('does not find anything if there is no text in braces', () => { + const replacer = jasmine.createSpy('replacer'); - expect(result.tags[0]).toBeObject(); - expect(result.tags[0].tag).toBe('tagged'); - expect(result.tags[0].text).toBe('text'); - expect(result.newString).toBe('some'); - }); + inline.replaceInlineTag('braceless text', 'foo', replacer); + + expect(replacer).not.toHaveBeenCalled(); }); + + it('copes with bad escapement at the end of the string', () => { + const replacer = jasmine.createSpy('replacer'); + + inline.replaceInlineTag('bad {@foo escapement \\', 'foo', replacer); + + expect(replacer).not.toHaveBeenCalled(); + }); + + it('works if the tag is the entire string', () => { + function replacer(string, { completeTag, text }) { + expect(string).toBe('{@foo text in braces}'); + expect(completeTag).toBe('{@foo text in braces}'); + expect(text).toBe('text in braces'); + + return completeTag; + } + + const result = inline.replaceInlineTag('{@foo text in braces}', 'foo', replacer); + + expect(result.tags[0]).toBeObject(); + expect(result.tags[0].tag).toBe('foo'); + expect(result.tags[0].text).toBe('text in braces'); + expect(result.newString).toBe('{@foo text in braces}'); + }); + + it('works if the tag is at the beginning of the string', () => { + function replacer(string, { completeTag, text }) { + expect(string).toBe('{@foo test string} ahoy'); + expect(completeTag).toBe('{@foo test string}'); + expect(text).toBe('test string'); + + return string; + } + + const result = inline.replaceInlineTag('{@foo test string} ahoy', 'foo', replacer); + + expect(result.tags[0]).toBeObject(); + expect(result.tags[0].tag).toBe('foo'); + expect(result.tags[0].text).toBe('test string'); + expect(result.newString).toBe('{@foo test string} ahoy'); + }); + + it('works if the tag is in the middle of the string', () => { + function replacer(string, { completeTag, text }) { + expect(string).toBe('a {@foo test string} yay'); + expect(completeTag).toBe('{@foo test string}'); + expect(text).toBe('test string'); + + return string; + } + + const result = inline.replaceInlineTag('a {@foo test string} yay', 'foo', replacer); + + expect(result.tags[0]).toBeObject(); + expect(result.tags[0].tag).toBe('foo'); + expect(result.tags[0].text).toBe('test string'); + expect(result.newString).toBe('a {@foo test string} yay'); + }); + + it('works if the tag is at the end of the string', () => { + function replacer(string, { completeTag, text }) { + expect(string).toBe('a {@foo test string}'); + expect(completeTag).toBe('{@foo test string}'); + expect(text).toBe('test string'); + + return string; + } + + const result = inline.replaceInlineTag('a {@foo test string}', 'foo', replacer); + + expect(result.tags[0]).toBeObject(); + expect(result.tags[0].tag).toBe('foo'); + expect(result.tags[0].text).toBe('test string'); + expect(result.newString).toBe('a {@foo test string}'); + }); + + it('replaces the string with the specified value', () => { + function replacer() { + return 'REPLACED!'; + } + + const result = inline.replaceInlineTag('a {@foo test string}', 'foo', replacer); + + expect(result.newString).toBe('REPLACED!'); + }); + + it('processes all occurrences of a tag', () => { + function replacer(string, { completeTag }) { + return string.replace(completeTag, 'stuff'); + } + + const result = inline.replaceInlineTag( + 'some {@foo text} with multiple ' + '{@foo tags}, {@foo like} {@foo this}', + 'foo', + replacer + ); + + expect(result.tags.length).toBe(4); + + expect(result.tags[0]).toBeObject(); + expect(result.tags[0].tag).toBe('foo'); + expect(result.tags[0].text).toBe('text'); + + expect(result.tags[1]).toBeObject(); + expect(result.tags[1].tag).toBe('foo'); + expect(result.tags[1].text).toBe('tags'); + + expect(result.tags[2]).toBeObject(); + expect(result.tags[2].tag).toBe('foo'); + expect(result.tags[2].text).toBe('like'); + + expect(result.tags[3]).toBeObject(); + expect(result.tags[3].tag).toBe('foo'); + expect(result.tags[3].text).toBe('this'); + + expect(result.newString).toBe('some stuff with multiple stuff, stuff stuff'); + }); + }); + + // Largely covered by the `replaceInlineTag()` tests. + describe('replaceInlineTags', () => { + it('works with an empty replacer object', () => { + const replacers = {}; + const text = 'some {@foo text} to parse'; + const result = inline.replaceInlineTags(text, replacers); + + expect(result.newString).toBe(text); + }); + + it('works with one replacer', () => { + const text = 'some {@foo text} with {@bar multiple} tags'; + const replacers = { + foo(string, tagInfo) { + expect(tagInfo.completeTag).toBe('{@foo text}'); + expect(tagInfo.text).toBe('text'); + + return string.replace(tagInfo.completeTag, 'stuff'); + }, + }; + const result = inline.replaceInlineTags(text, replacers); + + expect(result.newString).toBe('some stuff with {@bar multiple} tags'); + }); + + it('works with multiple replacers', () => { + const text = 'some {@foo text} with {@bar multiple} tags'; + const replacers = { + foo(string, tagInfo) { + expect(tagInfo.completeTag).toBe('{@foo text}'); + expect(tagInfo.text).toBe('text'); + + return string.replace(tagInfo.completeTag, 'stuff'); + }, + bar(string, tagInfo) { + expect(tagInfo.completeTag).toBe('{@bar multiple}'); + expect(tagInfo.text).toBe('multiple'); + + return string.replace(tagInfo.completeTag, 'awesome'); + }, + }; + const result = inline.replaceInlineTags(text, replacers); + + expect(result.newString).toBe('some stuff with awesome tags'); + }); + }); + + // Largely covered by the `replaceInlineTag()` tests. + describe('extractInlineTag', () => { + it('works when a tag is specified', () => { + const result = inline.extractInlineTag('some {@tagged text}', 'tagged'); + + expect(result.tags[0]).toBeObject(); + expect(result.tags[0].tag).toBe('tagged'); + expect(result.tags[0].text).toBe('text'); + expect(result.newString).toBe('some'); + }); + }); }); diff --git a/packages/jsdoc-tag/test/specs/lib/type.js b/packages/jsdoc-tag/test/specs/lib/type.js index 094cd8c4..6728f624 100644 --- a/packages/jsdoc-tag/test/specs/lib/type.js +++ b/packages/jsdoc-tag/test/specs/lib/type.js @@ -1,266 +1,266 @@ function buildText(type, name, desc) { - let text = ''; + let text = ''; - if (type) { - text += `{${type}}`; - if (name || desc) { - text += ' '; - } - } - - if (name) { - text += name; - if (desc) { - text += ' '; - } + if (type) { + text += `{${type}}`; + if (name || desc) { + text += ' '; } + } + if (name) { + text += name; if (desc) { - text += desc; + text += ' '; } + } - return text; + if (desc) { + text += desc; + } + + return text; } describe('@jsdoc/tag/lib/type', () => { - const type = require('../../../lib/type'); + const type = require('../../../lib/type'); - it('is an object', () => { - expect(type).toBeObject(); + it('is an object', () => { + expect(type).toBeObject(); + }); + + it('exports a parse function', () => { + expect(type.parse).toBeFunction(); + }); + + describe('parse', () => { + it('returns an object with name, type, and text properties', () => { + const info = type.parse(''); + + expect(info.name).toBeString(); + expect(info.type).toBeArray(); + expect(info.text).toBeString(); }); - it('exports a parse function', () => { - expect(type.parse).toBeFunction(); + it('does not extract a name or type if canHaveName and canHaveType are not set', () => { + const desc = '{number} foo The foo parameter.'; + const info = type.parse(desc); + + expect(info.type).toBeEmptyArray(); + expect(info.name).toBe(''); + expect(info.text).toBe(desc); }); - describe('parse', () => { - it('returns an object with name, type, and text properties', () => { - const info = type.parse(''); + it('extracts a name, but not a type, if canHaveName is true and canHaveType is false', () => { + const name = 'bar'; + const desc = 'The bar parameter.'; + const info = type.parse(buildText(null, name, desc), true, false); - expect(info.name).toBeString(); - expect(info.type).toBeArray(); - expect(info.text).toBeString(); - }); - - it('does not extract a name or type if canHaveName and canHaveType are not set', () => { - const desc = '{number} foo The foo parameter.'; - const info = type.parse(desc); - - expect(info.type).toBeEmptyArray(); - expect(info.name).toBe(''); - expect(info.text).toBe(desc); - }); - - it('extracts a name, but not a type, if canHaveName is true and canHaveType is false', () => { - const name = 'bar'; - const desc = 'The bar parameter.'; - const info = type.parse( buildText(null, name, desc), true, false ); - - expect(info.type).toBeEmptyArray(); - expect(info.name).toBe(name); - expect(info.text).toBe(desc); - }); - - it('extracts a type, but not a name, if canHaveName is false and canHaveType is true', () => { - const typeString = 'boolean'; - const desc = 'Set to true on alternate Thursdays.'; - const info = type.parse(buildText(typeString, null, desc), false, true); - - expect(info.type).toEqual([typeString]); - expect(info.name).toBe(''); - expect(info.text).toBe(desc); - }); - - it('extracts a name and type if canHaveName and canHaveType are true', () => { - const typeString = 'string'; - const name = 'baz'; - const desc = 'The baz parameter.'; - const info = type.parse(buildText(typeString, name, desc), true, true); - - expect(info.type).toEqual([typeString]); - expect(info.name).toBe(name); - expect(info.text).toBe(desc); - }); - - it('reports optional types correctly for both JSDoc and Closure syntax', () => { - let desc = '{string} [foo]'; - let info = type.parse(desc, true, true); - - expect(info.optional).toBeTrue(); - - desc = '{string=} [foo]'; - info = type.parse(desc, true, true); - expect(info.optional).toBeTrue(); - - desc = '[foo]'; - info = type.parse(desc, true, true); - expect(info.optional).toBeTrue(); - }); - - it('returnsthe types as an array', () => { - const desc = '{string} foo'; - const info = type.parse(desc, true, true); - - expect(info.type).toEqual( ['string'] ); - }); - - it('recognizes the entire list of possible types', () => { - let desc = '{(string|number)} foo'; - let info = type.parse(desc, true, true); - - expect(info.type).toEqual( ['string', 'number'] ); - - desc = '{ ( string | number ) } foo'; - info = type.parse(desc, true, true); - expect(info.type).toEqual( ['string', 'number'] ); - - desc = '{ ( string | number)} foo'; - info = type.parse(desc, true, true); - expect(info.type).toEqual( ['string', 'number'] ); - - desc = '{(string|number|boolean|function)} foo'; - info = type.parse(desc, true, true); - expect(info.type).toEqual( ['string', 'number', 'boolean', 'function'] ); - }); - - it('does not find any type if there is no text in braces', () => { - const desc = 'braceless text'; - const info = type.parse(desc, false, true); - - expect(info.type).toBeEmptyArray(); - }); - - it('copes with bad escapement at the end of the string', () => { - const desc = 'bad {escapement \\'; - const info = type.parse(desc, false, true); - - expect(info.type).toBeEmptyArray(); - expect(info.text).toBe(desc); - }); - - it('handles escaped braces correctly', () => { - const desc = '{weirdObject."with\\}AnnoyingProperty"}'; - const info = type.parse(desc, false, true); - - expect(info.type[0]).toBe('weirdObject."with}AnnoyingProperty"'); - }); - - it('works if the type expression is the entire string', () => { - const desc = '{textInBraces}'; - const info = type.parse(desc, false, true); - - expect(info.type[0]).toBe('textInBraces'); - }); - - it('works if the type expression is at the beginning of the string', () => { - const desc = '{testString} ahoy'; - const info = type.parse(desc, false, true); - - expect(info.type[0]).toBe('testString'); - expect(info.text).toBe('ahoy'); - }); - - it('works if the type expression is in the middle of the string', () => { - const desc = 'a {testString} yay'; - const info = type.parse(desc, false, true); - - expect(info.type[0]).toBe('testString'); - expect(info.text).toBe('a yay'); - }); - - it('works if the tag is at the end of the string', () => { - const desc = 'a {testString}'; - const info = type.parse(desc, false, true); - - expect(info.type[0]).toBe('testString'); - expect(info.text).toBe('a'); - }); - - it('works when there are nested braces', () => { - const desc = 'some {{double}} braces'; - const info = type.parse(desc, false, true); - - // we currently stringify all record types as 'Object' - expect(info.type[0]).toBe('Object'); - expect(info.text).toBe('some braces'); - }); - - it('overrides the type expression if an inline @type tag is specified', () => { - let desc = '{Object} cookie {@type Monster}'; - let info = type.parse(desc, true, true); - - expect(info.type).toEqual( ['Monster'] ); - expect(info.text).toBe(''); - - desc = '{Object} cookie - {@type Monster}'; - info = type.parse(desc, true, true); - expect(info.type).toEqual( ['Monster'] ); - expect(info.text).toBe(''); - - desc = '{Object} cookie - The cookie parameter. {@type Monster}'; - info = type.parse(desc, true, true); - expect(info.type).toEqual( ['Monster'] ); - expect(info.text).toBe('The cookie parameter.'); - - desc = '{Object} cookie - The cookie parameter. {@type (Monster|Jar)}'; - info = type.parse(desc, true, true); - expect(info.type).toEqual( ['Monster', 'Jar'] ); - expect(info.text).toBe('The cookie parameter.'); - - desc = '{Object} cookie - The cookie parameter. {@type (Monster|Jar)} Mmm, cookie.'; - info = type.parse(desc, true, true); - expect(info.type).toEqual( ['Monster', 'Jar'] ); - expect(info.text).toBe('The cookie parameter. Mmm, cookie.'); - }); - - describe('JSDoc-style type info', () => { - it('parses JSDoc-style optional parameters', () => { - let name = '[qux]'; - const desc = 'The qux parameter.'; - let info = type.parse( buildText(null, name, desc), true, false ); - - expect(info.name).toBe('qux'); - expect(info.text).toBe(desc); - expect(info.optional).toBeTrue(); - - name = '[ qux ]'; - info = type.parse( buildText(null, name, desc), true, false ); - expect(info.name).toBe('qux'); - expect(info.text).toBe(desc); - expect(info.optional).toBeTrue(); - - name = '[qux=hooray]'; - info = type.parse( buildText(null, name, desc), true, false ); - expect(info.name).toBe('qux'); - expect(info.text).toBe(desc); - expect(info.optional).toBeTrue(); - expect(info.defaultvalue).toBe('hooray'); - - name = '[ qux = hooray ]'; - info = type.parse( buildText(null, name, desc), true, false ); - expect(info.name).toBe('qux'); - expect(info.text).toBe(desc); - expect(info.optional).toBeTrue(); - expect(info.defaultvalue).toBe('hooray'); - }); - }); - - // TODO: Add more tests related to how JSDoc mangles the Catharsis parse results. - describe('Closure Compiler-style type info', () => { - it('recognizes variable (repeatable) parameters', () => { - const desc = '{...string} foo - Foo.'; - const info = type.parse(desc, true, true); - - expect(info.type).toEqual( ['string'] ); - expect(info.variable).toBeTrue(); - }); - - it('sets the type correctly for type applications that contain type unions', () => { - const desc = '{Array.<(string|number)>} foo - Foo.'; - const info = type.parse(desc, true, true); - - expect(info.type).toEqual(['Array.<(string|number)>']); - }); - }); + expect(info.type).toBeEmptyArray(); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); }); + + it('extracts a type, but not a name, if canHaveName is false and canHaveType is true', () => { + const typeString = 'boolean'; + const desc = 'Set to true on alternate Thursdays.'; + const info = type.parse(buildText(typeString, null, desc), false, true); + + expect(info.type).toEqual([typeString]); + expect(info.name).toBe(''); + expect(info.text).toBe(desc); + }); + + it('extracts a name and type if canHaveName and canHaveType are true', () => { + const typeString = 'string'; + const name = 'baz'; + const desc = 'The baz parameter.'; + const info = type.parse(buildText(typeString, name, desc), true, true); + + expect(info.type).toEqual([typeString]); + expect(info.name).toBe(name); + expect(info.text).toBe(desc); + }); + + it('reports optional types correctly for both JSDoc and Closure syntax', () => { + let desc = '{string} [foo]'; + let info = type.parse(desc, true, true); + + expect(info.optional).toBeTrue(); + + desc = '{string=} [foo]'; + info = type.parse(desc, true, true); + expect(info.optional).toBeTrue(); + + desc = '[foo]'; + info = type.parse(desc, true, true); + expect(info.optional).toBeTrue(); + }); + + it('returnsthe types as an array', () => { + const desc = '{string} foo'; + const info = type.parse(desc, true, true); + + expect(info.type).toEqual(['string']); + }); + + it('recognizes the entire list of possible types', () => { + let desc = '{(string|number)} foo'; + let info = type.parse(desc, true, true); + + expect(info.type).toEqual(['string', 'number']); + + desc = '{ ( string | number ) } foo'; + info = type.parse(desc, true, true); + expect(info.type).toEqual(['string', 'number']); + + desc = '{ ( string | number)} foo'; + info = type.parse(desc, true, true); + expect(info.type).toEqual(['string', 'number']); + + desc = '{(string|number|boolean|function)} foo'; + info = type.parse(desc, true, true); + expect(info.type).toEqual(['string', 'number', 'boolean', 'function']); + }); + + it('does not find any type if there is no text in braces', () => { + const desc = 'braceless text'; + const info = type.parse(desc, false, true); + + expect(info.type).toBeEmptyArray(); + }); + + it('copes with bad escapement at the end of the string', () => { + const desc = 'bad {escapement \\'; + const info = type.parse(desc, false, true); + + expect(info.type).toBeEmptyArray(); + expect(info.text).toBe(desc); + }); + + it('handles escaped braces correctly', () => { + const desc = '{weirdObject."with\\}AnnoyingProperty"}'; + const info = type.parse(desc, false, true); + + expect(info.type[0]).toBe('weirdObject."with}AnnoyingProperty"'); + }); + + it('works if the type expression is the entire string', () => { + const desc = '{textInBraces}'; + const info = type.parse(desc, false, true); + + expect(info.type[0]).toBe('textInBraces'); + }); + + it('works if the type expression is at the beginning of the string', () => { + const desc = '{testString} ahoy'; + const info = type.parse(desc, false, true); + + expect(info.type[0]).toBe('testString'); + expect(info.text).toBe('ahoy'); + }); + + it('works if the type expression is in the middle of the string', () => { + const desc = 'a {testString} yay'; + const info = type.parse(desc, false, true); + + expect(info.type[0]).toBe('testString'); + expect(info.text).toBe('a yay'); + }); + + it('works if the tag is at the end of the string', () => { + const desc = 'a {testString}'; + const info = type.parse(desc, false, true); + + expect(info.type[0]).toBe('testString'); + expect(info.text).toBe('a'); + }); + + it('works when there are nested braces', () => { + const desc = 'some {{double}} braces'; + const info = type.parse(desc, false, true); + + // we currently stringify all record types as 'Object' + expect(info.type[0]).toBe('Object'); + expect(info.text).toBe('some braces'); + }); + + it('overrides the type expression if an inline @type tag is specified', () => { + let desc = '{Object} cookie {@type Monster}'; + let info = type.parse(desc, true, true); + + expect(info.type).toEqual(['Monster']); + expect(info.text).toBe(''); + + desc = '{Object} cookie - {@type Monster}'; + info = type.parse(desc, true, true); + expect(info.type).toEqual(['Monster']); + expect(info.text).toBe(''); + + desc = '{Object} cookie - The cookie parameter. {@type Monster}'; + info = type.parse(desc, true, true); + expect(info.type).toEqual(['Monster']); + expect(info.text).toBe('The cookie parameter.'); + + desc = '{Object} cookie - The cookie parameter. {@type (Monster|Jar)}'; + info = type.parse(desc, true, true); + expect(info.type).toEqual(['Monster', 'Jar']); + expect(info.text).toBe('The cookie parameter.'); + + desc = '{Object} cookie - The cookie parameter. {@type (Monster|Jar)} Mmm, cookie.'; + info = type.parse(desc, true, true); + expect(info.type).toEqual(['Monster', 'Jar']); + expect(info.text).toBe('The cookie parameter. Mmm, cookie.'); + }); + + describe('JSDoc-style type info', () => { + it('parses JSDoc-style optional parameters', () => { + let name = '[qux]'; + const desc = 'The qux parameter.'; + let info = type.parse(buildText(null, name, desc), true, false); + + expect(info.name).toBe('qux'); + expect(info.text).toBe(desc); + expect(info.optional).toBeTrue(); + + name = '[ qux ]'; + info = type.parse(buildText(null, name, desc), true, false); + expect(info.name).toBe('qux'); + expect(info.text).toBe(desc); + expect(info.optional).toBeTrue(); + + name = '[qux=hooray]'; + info = type.parse(buildText(null, name, desc), true, false); + expect(info.name).toBe('qux'); + expect(info.text).toBe(desc); + expect(info.optional).toBeTrue(); + expect(info.defaultvalue).toBe('hooray'); + + name = '[ qux = hooray ]'; + info = type.parse(buildText(null, name, desc), true, false); + expect(info.name).toBe('qux'); + expect(info.text).toBe(desc); + expect(info.optional).toBeTrue(); + expect(info.defaultvalue).toBe('hooray'); + }); + }); + + // TODO: Add more tests related to how JSDoc mangles the Catharsis parse results. + describe('Closure Compiler-style type info', () => { + it('recognizes variable (repeatable) parameters', () => { + const desc = '{...string} foo - Foo.'; + const info = type.parse(desc, true, true); + + expect(info.type).toEqual(['string']); + expect(info.variable).toBeTrue(); + }); + + it('sets the type correctly for type applications that contain type unions', () => { + const desc = '{Array.<(string|number)>} foo - Foo.'; + const info = type.parse(desc, true, true); + + expect(info.type).toEqual(['Array.<(string|number)>']); + }); + }); + }); }); diff --git a/packages/jsdoc-task-runner/index.js b/packages/jsdoc-task-runner/index.js index 2554ab19..437bfd6a 100644 --- a/packages/jsdoc-task-runner/index.js +++ b/packages/jsdoc-task-runner/index.js @@ -2,6 +2,6 @@ const Task = require('./lib/task'); const TaskRunner = require('./lib/task-runner'); module.exports = { - Task, - TaskRunner + Task, + TaskRunner, }; diff --git a/packages/jsdoc-task-runner/lib/task-runner.js b/packages/jsdoc-task-runner/lib/task-runner.js index 8bfc4491..70f69fc5 100644 --- a/packages/jsdoc-task-runner/lib/task-runner.js +++ b/packages/jsdoc-task-runner/lib/task-runner.js @@ -1,7 +1,7 @@ const _ = require('lodash'); const { DepGraph } = require('dependency-graph'); const Emittery = require('emittery'); -const {default: ow} = require('ow'); +const { default: ow } = require('ow'); const Queue = require('p-queue').default; const v = require('./validators'); @@ -9,319 +9,320 @@ const v = require('./validators'); DepGraph.prototype.dependentsOf = DepGraph.prototype.dependantsOf; module.exports = class TaskRunner extends Emittery { - constructor(context) { - super(); + constructor(context) { + super(); - ow(context, ow.optional.object); + ow(context, ow.optional.object); - this._init(context); - } + this._init(context); + } - _addOrRemoveTasks(tasks, func, action) { - func = _.bind(func, this); + _addOrRemoveTasks(tasks, func, action) { + func = _.bind(func, this); - if (Array.isArray(tasks)) { - tasks.forEach((task, i) => { - try { - func(task); - } catch (e) { - e.message = `Can't ${action} task ${i}: ${e.message}`; - throw e; - } - }); - } else if (tasks !== null && typeof tasks === 'object') { - for (const task of Object.keys(tasks)) { - try { - func(tasks[task]); - } catch (e) { - e.message = `Can't ${action} task "${task}": ${e.message}`; - throw e; - } - } - } - } - - _addTaskEmitters(task) { - const u = {}; - - u.start = task.on('start', t => this.emit('taskStart', t)); - u.end = task.on('end', t => this.emit('taskEnd', t)); - u.error = task.on('error', (e => { - this.emit('taskError', { - task: e.task, - error: e.error - }); - - if (!this._error) { - this._error = e.error; - } - })); - - this._unsubscribers.set(task.name, u); - } - - _bindTaskFunc(task) { - return _.bind(task.run, task, this._context); - } - - _createTaskSequence(tasks) { - if (!tasks.length) { - return null; - } - - return () => tasks.reduce((p, taskName) => { - const task = this._nameToTask.get(taskName); - - return p.then( - this._bindTaskFunc(task), - e => Promise.reject(e) - ); - }, Promise.resolve()); - } - - _init(context) { - this._context = context; - this._deps = new Map(); - this._error = null; - this._queue = new Queue(); - this._taskToName = new WeakMap(); - this._nameToTask = new Map(); - this._running = false; - this._unsubscribers = new Map(); - - this._queue.pause(); - } - - _newDependencyCycleError(cyclePath) { - return new v.DependencyCycleError( - `Tasks have circular dependencies: ${cyclePath.join(' > ')}`, - cyclePath - ); - } - - _newStateError() { - return new v.StateError('The task runner is already running.'); - } - - _newUnknownDepsError(dependent, unknownDeps) { - let errorText; - - if (unknownDeps.length === 1) { - errorText = 'an unknown task'; - } else { - errorText = 'unknown tasks'; - } - - return new v.UnknownDependencyError(`The task ${dependent} depends on ${errorText}: ` + - `${unknownDeps.join(', ')}`); - } - - _orderTasks() { - let error; - const graph = new DepGraph(); - let parallel; - let sequential; - - for (const [task] of this._nameToTask) { - graph.addNode(task); - } - - for (const [dependent] of this._deps) { - const unknownDeps = []; - - for (const dependency of this._deps.get(dependent)) { - if (!this._nameToTask.has(dependency)) { - unknownDeps.push(dependency); - } else { - graph.addDependency(dependent, dependency); - } - - if (unknownDeps.length) { - error = this._newUnknownDepsError(dependency, unknownDeps); - break; - } - } - } - - if (!error) { - try { - // Get standalone tasks with no dependencies and no dependents. - parallel = graph.overallOrder(true) - .filter(task => !(graph.dependentsOf(task).length)); - // Get tasks with dependencies, in a correctly ordered list. - sequential = graph.overallOrder().filter(task => !parallel.includes(task)); - } catch (e) { - error = this._newDependencyCycleError(e.cyclePath); - } - } - - return { - error, - parallel, - sequential - }; - } - - _rejectIfRunning() { - if (this.running) { - return Promise.reject(this._newStateError()); - } - - return null; - } - - _throwIfRunning() { - if (this.running) { - throw this._newStateError(); - } - } - - _throwIfUnknownDeps(dependent, unknownDeps) { - if (!unknownDeps.length) { - return; - } - - throw this._newUnknownDepsError(dependent, unknownDeps); - } - - addTask(task) { - ow(task, v.checkTaskOrString); - - this._throwIfRunning(); - - this._nameToTask.set(task.name, task); - if (task.dependsOn) { - this._deps.set(task.name, task.dependsOn); - } - this._taskToName.set(task, task.name); - this._addTaskEmitters(task); - - return this; - } - - addTasks(tasks) { - ow(tasks, ow.any(ow.array, ow.object)); - this._addOrRemoveTasks(tasks, this.addTask, 'add'); - - return this; - } - - end() { - this.emit('end', { - error: this._error - }); - this._queue.clear(); - this._init(); - } - - removeTask(task) { - let unsubscribers; - - ow(task, v.checkTaskOrString); - this._throwIfRunning(); - - if (typeof task === 'string') { - task = this._nameToTask.get(task); - - if (!task) { - throw new v.UnknownTaskError(`Unknown task: ${task}`); - } - } else if (typeof task === 'object') { - if (!this._taskToName.has(task)) { - throw new v.UnknownTaskError(`Unknown task: ${task}`); - } - } - - this._nameToTask.delete(task.name); - this._taskToName.delete(task); - this._deps.delete(task.name); - - unsubscribers = this._unsubscribers.get(task.name); - for (const u of Object.keys(unsubscribers)) { - unsubscribers[u](); - } - this._unsubscribers.delete(task.name); - - return this; - } - - removeTasks(tasks) { - ow(tasks, ow.any(ow.array, ow.object)); - this._addOrRemoveTasks(tasks, this.removeTask, 'remove'); - - return this; - } - - run(context) { - ow(context, ow.optional.object); - - let endPromise; - const { error, parallel, sequential } = this._orderTasks(); - let runningPromise; - let taskFuncs = []; - let taskSequence; - - // First, fail if the runner is already running. - runningPromise = this._rejectIfRunning(); - if (runningPromise) { - return runningPromise; - } - - // Then fail if the tasks couldn't be ordered. - if (error) { - return Promise.reject(error); - } - - this._context = context || this._context; - - for (const taskName of parallel) { - taskFuncs.push(this._bindTaskFunc(this._nameToTask.get(taskName))); - } - - taskSequence = this._createTaskSequence(sequential); - if (taskSequence) { - taskFuncs.push(taskSequence); - } - - endPromise = this._queue.addAll(taskFuncs).then(() => { - this.end(); - - if (this._error) { - return Promise.reject(this._error); - } else { - return Promise.resolve(); - } - }, e => { - this.end(); - - return Promise.reject(e); - }); - - this.emit('start'); - this._running = true; + if (Array.isArray(tasks)) { + tasks.forEach((task, i) => { try { - this._queue.start(); - - return endPromise; + func(task); } catch (e) { - this._error = e; - this.end(); - - return Promise.reject(e); + e.message = `Can't ${action} task ${i}: ${e.message}`; + throw e; } + }); + } else if (tasks !== null && typeof tasks === 'object') { + for (const task of Object.keys(tasks)) { + try { + func(tasks[task]); + } catch (e) { + e.message = `Can't ${action} task "${task}": ${e.message}`; + throw e; + } + } + } + } + + _addTaskEmitters(task) { + const u = {}; + + u.start = task.on('start', (t) => this.emit('taskStart', t)); + u.end = task.on('end', (t) => this.emit('taskEnd', t)); + u.error = task.on('error', (e) => { + this.emit('taskError', { + task: e.task, + error: e.error, + }); + + if (!this._error) { + this._error = e.error; + } + }); + + this._unsubscribers.set(task.name, u); + } + + _bindTaskFunc(task) { + return _.bind(task.run, task, this._context); + } + + _createTaskSequence(tasks) { + if (!tasks.length) { + return null; } - get running() { - return this._running; + return () => + tasks.reduce((p, taskName) => { + const task = this._nameToTask.get(taskName); + + return p.then(this._bindTaskFunc(task), (e) => Promise.reject(e)); + }, Promise.resolve()); + } + + _init(context) { + this._context = context; + this._deps = new Map(); + this._error = null; + this._queue = new Queue(); + this._taskToName = new WeakMap(); + this._nameToTask = new Map(); + this._running = false; + this._unsubscribers = new Map(); + + this._queue.pause(); + } + + _newDependencyCycleError(cyclePath) { + return new v.DependencyCycleError( + `Tasks have circular dependencies: ${cyclePath.join(' > ')}`, + cyclePath + ); + } + + _newStateError() { + return new v.StateError('The task runner is already running.'); + } + + _newUnknownDepsError(dependent, unknownDeps) { + let errorText; + + if (unknownDeps.length === 1) { + errorText = 'an unknown task'; + } else { + errorText = 'unknown tasks'; } - get tasks() { - const entries = []; + return new v.UnknownDependencyError( + `The task ${dependent} depends on ${errorText}: ` + `${unknownDeps.join(', ')}` + ); + } - for (const entry of this._nameToTask.entries()) { - entries.push(entry); + _orderTasks() { + let error; + const graph = new DepGraph(); + let parallel; + let sequential; + + for (const [task] of this._nameToTask) { + graph.addNode(task); + } + + for (const [dependent] of this._deps) { + const unknownDeps = []; + + for (const dependency of this._deps.get(dependent)) { + if (!this._nameToTask.has(dependency)) { + unknownDeps.push(dependency); + } else { + graph.addDependency(dependent, dependency); } - return _.fromPairs(entries); + if (unknownDeps.length) { + error = this._newUnknownDepsError(dependency, unknownDeps); + break; + } + } } + + if (!error) { + try { + // Get standalone tasks with no dependencies and no dependents. + parallel = graph.overallOrder(true).filter((task) => !graph.dependentsOf(task).length); + // Get tasks with dependencies, in a correctly ordered list. + sequential = graph.overallOrder().filter((task) => !parallel.includes(task)); + } catch (e) { + error = this._newDependencyCycleError(e.cyclePath); + } + } + + return { + error, + parallel, + sequential, + }; + } + + _rejectIfRunning() { + if (this.running) { + return Promise.reject(this._newStateError()); + } + + return null; + } + + _throwIfRunning() { + if (this.running) { + throw this._newStateError(); + } + } + + _throwIfUnknownDeps(dependent, unknownDeps) { + if (!unknownDeps.length) { + return; + } + + throw this._newUnknownDepsError(dependent, unknownDeps); + } + + addTask(task) { + ow(task, v.checkTaskOrString); + + this._throwIfRunning(); + + this._nameToTask.set(task.name, task); + if (task.dependsOn) { + this._deps.set(task.name, task.dependsOn); + } + this._taskToName.set(task, task.name); + this._addTaskEmitters(task); + + return this; + } + + addTasks(tasks) { + ow(tasks, ow.any(ow.array, ow.object)); + this._addOrRemoveTasks(tasks, this.addTask, 'add'); + + return this; + } + + end() { + this.emit('end', { + error: this._error, + }); + this._queue.clear(); + this._init(); + } + + removeTask(task) { + let unsubscribers; + + ow(task, v.checkTaskOrString); + this._throwIfRunning(); + + if (typeof task === 'string') { + task = this._nameToTask.get(task); + + if (!task) { + throw new v.UnknownTaskError(`Unknown task: ${task}`); + } + } else if (typeof task === 'object') { + if (!this._taskToName.has(task)) { + throw new v.UnknownTaskError(`Unknown task: ${task}`); + } + } + + this._nameToTask.delete(task.name); + this._taskToName.delete(task); + this._deps.delete(task.name); + + unsubscribers = this._unsubscribers.get(task.name); + for (const u of Object.keys(unsubscribers)) { + unsubscribers[u](); + } + this._unsubscribers.delete(task.name); + + return this; + } + + removeTasks(tasks) { + ow(tasks, ow.any(ow.array, ow.object)); + this._addOrRemoveTasks(tasks, this.removeTask, 'remove'); + + return this; + } + + run(context) { + ow(context, ow.optional.object); + + let endPromise; + const { error, parallel, sequential } = this._orderTasks(); + let runningPromise; + let taskFuncs = []; + let taskSequence; + + // First, fail if the runner is already running. + runningPromise = this._rejectIfRunning(); + if (runningPromise) { + return runningPromise; + } + + // Then fail if the tasks couldn't be ordered. + if (error) { + return Promise.reject(error); + } + + this._context = context || this._context; + + for (const taskName of parallel) { + taskFuncs.push(this._bindTaskFunc(this._nameToTask.get(taskName))); + } + + taskSequence = this._createTaskSequence(sequential); + if (taskSequence) { + taskFuncs.push(taskSequence); + } + + endPromise = this._queue.addAll(taskFuncs).then( + () => { + this.end(); + + if (this._error) { + return Promise.reject(this._error); + } else { + return Promise.resolve(); + } + }, + (e) => { + this.end(); + + return Promise.reject(e); + } + ); + + this.emit('start'); + this._running = true; + try { + this._queue.start(); + + return endPromise; + } catch (e) { + this._error = e; + this.end(); + + return Promise.reject(e); + } + } + + get running() { + return this._running; + } + + get tasks() { + const entries = []; + + for (const entry of this._nameToTask.entries()) { + entries.push(entry); + } + + return _.fromPairs(entries); + } }; diff --git a/packages/jsdoc-task-runner/lib/task.js b/packages/jsdoc-task-runner/lib/task.js index ad9fbf64..e68ecd31 100644 --- a/packages/jsdoc-task-runner/lib/task.js +++ b/packages/jsdoc-task-runner/lib/task.js @@ -1,52 +1,49 @@ const Emittery = require('emittery'); -const {default: ow} = require('ow'); +const { default: ow } = require('ow'); module.exports = class Task extends Emittery { - constructor(opts = {}) { - let deps; + constructor(opts = {}) { + let deps; - super(); + super(); - ow(opts.name, ow.optional.string); - ow(opts.func, ow.optional.function); - ow(opts.dependsOn, ow.any( - ow.optional.string, - ow.optional.array.ofType(ow.string) - )); + ow(opts.name, ow.optional.string); + ow(opts.func, ow.optional.function); + ow(opts.dependsOn, ow.any(ow.optional.string, ow.optional.array.ofType(ow.string))); - if (typeof opts.dependsOn === 'string') { - deps = [opts.dependsOn]; - } else if (Array.isArray(opts.dependsOn)) { - deps = opts.dependsOn.slice(0); - } - - this.name = opts.name || null; - this.func = opts.func || null; - this.dependsOn = deps || []; + if (typeof opts.dependsOn === 'string') { + deps = [opts.dependsOn]; + } else if (Array.isArray(opts.dependsOn)) { + deps = opts.dependsOn.slice(0); } - run(context) { - ow(this.name, ow.string); - ow(this.func, ow.function); - ow(this.dependsOn, ow.array.ofType(ow.string)); + this.name = opts.name || null; + this.func = opts.func || null; + this.dependsOn = deps || []; + } - this.emit('start', this); + run(context) { + ow(this.name, ow.string); + ow(this.func, ow.function); + ow(this.dependsOn, ow.array.ofType(ow.string)); - return this.func(context).then( - () => { - this.emit('end', this); + this.emit('start', this); - return Promise.resolve(); - }, - error => { - this.emit('error', { - task: this, - error - }); - this.emit('end', this); + return this.func(context).then( + () => { + this.emit('end', this); - return Promise.reject(error); - } - ); - } + return Promise.resolve(); + }, + (error) => { + this.emit('error', { + task: this, + error, + }); + this.emit('end', this); + + return Promise.reject(error); + } + ); + } }; diff --git a/packages/jsdoc-task-runner/lib/validators.js b/packages/jsdoc-task-runner/lib/validators.js index 9f4ef545..3c2e232c 100644 --- a/packages/jsdoc-task-runner/lib/validators.js +++ b/packages/jsdoc-task-runner/lib/validators.js @@ -1,47 +1,47 @@ -const {default: ow} = require('ow'); +const { default: ow } = require('ow'); const Task = require('./task'); function checkTask(t) { - return { - validator: t instanceof Task, - message: `Expected ${t} to be a Task object` - }; + return { + validator: t instanceof Task, + message: `Expected ${t} to be a Task object`, + }; } module.exports = { - checkTaskOrString: ow.any(ow.object.validate(checkTask), ow.string), - DependencyCycleError: class DependencyCycleError extends Error { - constructor(message, cyclePath) { - ow(message, ow.string); - ow(cyclePath, ow.array.ofType(ow.string)); - super(message); + checkTaskOrString: ow.any(ow.object.validate(checkTask), ow.string), + DependencyCycleError: class DependencyCycleError extends Error { + constructor(message, cyclePath) { + ow(message, ow.string); + ow(cyclePath, ow.array.ofType(ow.string)); + super(message); - this.cyclePath = cyclePath; - this.name = 'DependencyCycleError'; - } - }, - StateError: class StateError extends Error { - constructor(message) { - ow(message, ow.string); - super(message); - - this.name = 'StateError'; - } - }, - UnknownDependencyError: class UnknownDependencyError extends Error { - constructor(message) { - ow(message, ow.string); - super(message); - - this.name = 'UnknownDependencyError'; - } - }, - UnknownTaskError: class UnknownTaskError extends Error { - constructor(message) { - ow(message, ow.string); - super(message); - - this.name = 'UnknownTaskError'; - } + this.cyclePath = cyclePath; + this.name = 'DependencyCycleError'; } + }, + StateError: class StateError extends Error { + constructor(message) { + ow(message, ow.string); + super(message); + + this.name = 'StateError'; + } + }, + UnknownDependencyError: class UnknownDependencyError extends Error { + constructor(message) { + ow(message, ow.string); + super(message); + + this.name = 'UnknownDependencyError'; + } + }, + UnknownTaskError: class UnknownTaskError extends Error { + constructor(message) { + ow(message, ow.string); + super(message); + + this.name = 'UnknownTaskError'; + } + }, }; diff --git a/packages/jsdoc-task-runner/package-lock.json b/packages/jsdoc-task-runner/package-lock.json index b1c8a63e..e7a85e7c 100644 --- a/packages/jsdoc-task-runner/package-lock.json +++ b/packages/jsdoc-task-runner/package-lock.json @@ -1,8 +1,166 @@ { "name": "@jsdoc/task-runner", "version": "0.1.10", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@jsdoc/task-runner", + "version": "0.1.10", + "license": "Apache-2.0", + "dependencies": { + "dependency-graph": "^0.11.0", + "emittery": "^0.10.0", + "ow": "^0.27.0", + "p-queue": "^6.6.2" + }, + "engines": { + "node": ">=v14.17.6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/emittery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", + "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-fest": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.2.2.tgz", + "integrity": "sha512-pfkPYCcuV0TJoo/jlsUeWNV8rk7uMU6ocnYNvca1Vu+pyKi8Rl8Zo2scPt9O72gCsXIm+dMxOOWuA3VFDSdzWA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", + "engines": { + "node": ">=0.10.0" + } + } + }, "dependencies": { "@sindresorhus/is": { "version": "4.0.1", diff --git a/packages/jsdoc-task-runner/test/specs/index.js b/packages/jsdoc-task-runner/test/specs/index.js index 040937d6..f096f228 100644 --- a/packages/jsdoc-task-runner/test/specs/index.js +++ b/packages/jsdoc-task-runner/test/specs/index.js @@ -1,23 +1,23 @@ const taskRunner = require('../../index'); describe('@jsdoc/task-runner', () => { - it('is an object', () => { - expect(taskRunner).toBeObject(); + it('is an object', () => { + expect(taskRunner).toBeObject(); + }); + + describe('Task', () => { + it('is lib/task', () => { + const Task = require('../../lib/task'); + + expect(taskRunner.Task).toBe(Task); }); + }); - describe('Task', () => { - it('is lib/task', () => { - const Task = require('../../lib/task'); + describe('TaskRunner', () => { + it('is lib/task-runner', () => { + const TaskRunner = require('../../lib/task-runner'); - expect(taskRunner.Task).toBe(Task); - }); - }); - - describe('TaskRunner', () => { - it('is lib/task-runner', () => { - const TaskRunner = require('../../lib/task-runner'); - - expect(taskRunner.TaskRunner).toBe(TaskRunner); - }); + expect(taskRunner.TaskRunner).toBe(TaskRunner); }); + }); }); diff --git a/packages/jsdoc-task-runner/test/specs/lib/task-runner.js b/packages/jsdoc-task-runner/test/specs/lib/task-runner.js index d364bfba..54bb478f 100644 --- a/packages/jsdoc-task-runner/test/specs/lib/task-runner.js +++ b/packages/jsdoc-task-runner/test/specs/lib/task-runner.js @@ -9,794 +9,800 @@ const UNKNOWN_DEPENDENCY_ERROR = 'UnknownDependencyError'; const UNKNOWN_TASK_ERROR = 'UnknownTaskError'; function rethrower(e) { - return () => { - throw e; - }; + return () => { + throw e; + }; } describe('@jsdoc/task-runner/lib/task-runner', () => { - let badTask; - let bar; - let barResult; - const fakeTask = { - name: 'foo', - func: () => Promise.resolve() - }; - let foo; - let fooResult; - let runner; + let badTask; + let bar; + let barResult; + const fakeTask = { + name: 'foo', + func: () => Promise.resolve(), + }; + let foo; + let fooResult; + let runner; + + beforeEach(() => { + runner = new TaskRunner({}); + foo = new Task({ + name: 'foo', + func: () => + new Promise((resolve) => { + fooResult = true; + resolve(); + }), + }); + fooResult = null; + bar = new Task({ + name: 'bar', + func: () => + new Promise((resolve) => { + barResult = true; + resolve(); + }), + }); + barResult = null; + badTask = new Task({ + name: 'badTask', + func: () => Promise.reject(new Error()), + }); + }); + + it('is a function', () => { + expect(TaskRunner).toBeFunction(); + }); + + it('inherits from emittery', () => { + expect(runner instanceof Emittery).toBeTrue(); + }); + + it('has no required parameters', () => { + function factory() { + return new TaskRunner(); + } + + expect(factory).not.toThrow(); + }); + + it('does not accept a non-object context', () => { + function factory() { + return new TaskRunner(7); + } + + expect(factory).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + describe('addTask', () => { + it('adds `Task` objects', () => { + function add() { + runner.addTask(foo); + } + + expect(add).not.toThrow(); + }); + + it('fails with non-`Task` objects', () => { + function add() { + runner.addTask(fakeTask); + } + + expect(add).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('fails if the task runner is already running', () => { + function addWhileRunning() { + runner.run(); + runner.addTask(foo); + } + + expect(addWhileRunning).toThrowErrorOfType(STATE_ERROR); + }); + + // We run the task, rather than just checking the value of `runner.tasks`, to make sure + // _all_ the internal state was set correctly. + it('correctly adds the task', async () => { + runner.addTask(foo); + await runner.run(); + + expect(fooResult).toBeTrue(); + }); + + it('causes the task to be emitted when the task starts', async () => { + let promise; + + runner.addTask(foo); + promise = runner.once('taskStart'); + + foo.run(); + await promise.then((event) => { + expect(event).toBe(foo); + }); + }); + + it('causes the task to be emitted when the task ends', async () => { + let event; + let promise; + + runner.addTask(foo); + promise = runner.once('taskEnd'); + + foo.run(); + event = await promise; + + expect(event).toBe(foo); + }); + + it('causes an error to be emitted if the task errors', async () => { + let error; + let event; + let promise; + + runner.addTask(badTask); + promise = runner.once('taskError'); + + try { + await runner.run(); + } catch (e) { + error = e; + } + + event = await promise; + + expect(event).toBeObject(); + expect(rethrower(event.error)).toThrowError(); + expect(event.error).toBe(error); + expect(event.task).toBe(badTask); + }); + }); + + describe('addTasks', () => { + it('accepts an object whose values are tasks', () => { + function addTasks() { + runner.addTasks({ foo }); + } + + expect(addTasks).not.toThrow(); + }); + + it('fails with an object whose values are not tasks', () => { + function addTasks() { + runner.addTasks({ foo: fakeTask }); + } + + expect(addTasks).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('accepts an array of tasks', () => { + function addTasks() { + runner.addTasks([foo]); + } + + expect(addTasks).not.toThrow(); + }); + + it('fails with an array of non-tasks', () => { + function addTasks() { + runner.addTasks([fakeTask]); + } + + expect(addTasks).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('fails with non-object, non-array input', () => { + function addTasks() { + runner.addTasks(7); + } + + expect(addTasks).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('adds all the tasks in an object', () => { + let tasks; + + runner.addTasks({ + foo, + bar, + }); + tasks = runner.tasks; + + expect(tasks.foo).toBe(foo); + expect(tasks.bar).toBe(bar); + }); + + it('adds all the tasks in an array', () => { + let tasks; + + runner.addTasks([foo, bar]); + tasks = runner.tasks; + + expect(tasks.foo).toBe(foo); + expect(tasks.bar).toBe(bar); + }); + + it('returns `this`', () => { + const result = runner.addTasks({ + foo, + bar, + }); + + expect(result).toBe(runner); + }); + }); + + describe('end', () => { + it('stops the task runner', () => { + function addAfterEnding() { + runner.addTask(foo); + runner.run(); + runner.end(); + runner.addTask(bar); + } + + expect(addAfterEnding).not.toThrow(); + }); + + it('resets the tasks', async () => { + runner.addTask(foo); + runner.run(); + await runner.end(); + + expect(runner.tasks).toBeEmptyObject(); + }); + }); + + describe('removeTask', () => { + it('removes `Task` objects', () => { + runner.addTask(foo); + runner.removeTask(foo); + + expect(runner.tasks.foo).toBeUndefined(); + }); + + it('removes tasks by name', () => { + runner.addTask(foo); + runner.removeTask('foo'); + + expect(runner.tasks.foo).toBeUndefined(); + }); + + it('fails on invalid input types', () => { + function addRemove() { + runner.addTask(foo); + runner.removeTask(7); + } + + expect(addRemove).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('fails on unknown tasks', () => { + function addRemove() { + runner.addTask(foo); + runner.removeTask(bar); + } + + expect(addRemove).toThrowErrorOfType(UNKNOWN_TASK_ERROR); + }); + + it('fails if the task runner is already running', () => { + function removeWhileRunning() { + runner.addTasks([foo, bar]); + runner.run(); + runner.removeTask(foo); + } + + expect(removeWhileRunning).toThrowErrorOfType(STATE_ERROR); + }); + + it('correctly removes the task', async () => { + let error; + + runner.addTasks([foo, bar]); + runner.removeTask(foo); + + try { + await runner.run(); + } catch (e) { + error = e; + } + + expect(error).toBeUndefined(); + expect(fooResult).toBeNull(); + expect(barResult).toBeTrue(); + }); + + it('prevents `taskStart`/`taskEnd` events for the task', async () => { + let startEvent; + let endEvent; + + runner.on('taskStart', (e) => { + startEvent = e; + }); + runner.on('taskEnd', (e) => { + endEvent = e; + }); + runner.addTask(foo); + runner.removeTask(foo); + await foo.run(); + + expect(startEvent).toBeUndefined(); + expect(endEvent).toBeUndefined(); + }); + + it('prevents `taskError` events for the task', async () => { + let errorEvent; + let taskErrorEvent; + + runner.addTask(badTask); + runner.removeTask(badTask); + + badTask.on('error', (e) => { + errorEvent = e; + }); + runner.on('taskError', (e) => { + taskErrorEvent = e; + }); + + try { + await badTask.run(); + } catch (e) { + // Expected behavior. + } + + expect(errorEvent).toBeObject(); + expect(errorEvent.task).toBe(badTask); + expect(taskErrorEvent).toBeUndefined(); + }); + + it('returns `this`', () => { + let result; + + runner.addTask(foo); + result = runner.removeTask(foo); + + expect(result).toBe(runner); + }); + }); + + describe('removeTasks', () => { + it('accepts an object whose values are tasks', () => { + function removeTasks() { + runner.removeTasks({ foo }); + } + + runner.addTask(foo); + + expect(removeTasks).not.toThrow(); + }); + + it('fails with an object whose values are not tasks', () => { + function removeTasks() { + runner.removeTasks({ foo: 7 }); + } + + runner.addTask(foo); + + expect(removeTasks).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('accepts an array of tasks', () => { + function removeTasks() { + runner.removeTasks([foo]); + } + + runner.addTask(foo); + + expect(removeTasks).not.toThrow(); + }); + + it('accepts an array of strings', () => { + function removeTasks() { + runner.removeTasks(['foo']); + } + + runner.addTask(foo); + + expect(removeTasks).not.toThrow(); + }); + + it('fails with an array whose values are not tasks or strings', () => { + function removeTasks() { + runner.removeTasks([fakeTask]); + } + + expect(removeTasks).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('fails with non-object, non-array input', () => { + function removeTasks() { + runner.removeTasks(7); + } + + expect(removeTasks).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('fails with unknown tasks', () => { + function removeTasks() { + runner.removeTasks([bar]); + } + + expect(removeTasks).toThrowErrorOfType(UNKNOWN_TASK_ERROR); + }); + + it('removes all the tasks in an object', () => { + const tasks = { + foo, + bar, + }; + + runner.addTasks(tasks); + runner.removeTasks(tasks); + + expect(runner.tasks).toBeEmptyObject(); + }); + + it('removes all the tasks in an array', () => { + const tasks = [foo, bar]; + + runner.addTasks(tasks); + runner.removeTasks(tasks); + + expect(runner.tasks).toBeEmptyObject(); + }); + + it('returns `this`', () => { + runner.addTask(foo); + + expect(runner.removeTask(foo)).toBe(runner); + }); + }); + + describe('run', () => { + let a; + let b; + let c; + let taskA; + let taskB; + let taskC; beforeEach(() => { - runner = new TaskRunner({}); - foo = new Task({ + a = null; + b = null; + c = null; + + taskA = new Task({ + name: 'a', + func: () => { + a = 5; + + return Promise.resolve(); + }, + }); + taskB = new Task({ + name: 'b', + func: () => { + b = a * 3; + + return Promise.resolve(); + }, + dependsOn: ['a'], + }); + taskC = new Task({ + name: 'c', + func: () => { + c = a + b; + + return Promise.resolve(); + }, + dependsOn: ['b'], + }); + }); + + it('runs every task', async () => { + runner.addTasks([taskA, taskB, taskC]); + await runner.run(); + + expect(a).toBe(5); + expect(b).toBe(15); + expect(c).toBe(20); + }); + + it('runs tasks with dependencies in the correct order', async () => { + const results = []; + + taskA.on('end', () => { + results.push(a); + }); + taskB.on('end', () => { + results.push(b); + }); + taskC.on('end', () => { + results.push(c); + }); + + runner.addTasks([taskA, taskB, taskC]); + await runner.run(); + + expect(results).toEqual([5, 15, 20]); + }); + + it('fails if the task runner is already running', async () => { + let error; + + runner.addTask(taskA); + runner.run(); + + try { + await runner.run(); + } catch (e) { + error = e; + } + + expect(rethrower(error)).toThrowErrorOfType(STATE_ERROR); + }); + + it('clears all of its state after it runs', async () => { + runner.addTask(taskA); + await runner.run(); + + expect(runner.tasks).toBeEmptyObject(); + }); + + it('fails if a task errors', async () => { + let error; + + runner.addTask(badTask); + try { + await runner.run(); + } catch (e) { + error = e; + } + + expect(rethrower(error)).toThrowError(); + }); + + describe('context', () => { + it('prefers the context passed to `run()`', async () => { + const context = {}; + const t = new TaskRunner({}); + + t.addTask( + new Task({ name: 'foo', - func: () => new Promise(resolve => { - fooResult = true; - resolve(); - }) - }); - fooResult = null; - bar = new Task({ - name: 'bar', - func: () => new Promise(resolve => { - barResult = true; - resolve(); - }) - }); - barResult = null; - badTask = new Task({ - name: 'badTask', - func: () => Promise.reject(new Error()) - }); - }); + func: (ctx) => { + ctx.foo = 'foo'; - it('is a function', () => { - expect(TaskRunner).toBeFunction(); - }); + return Promise.resolve(); + }, + }) + ); + await t.run(context); - it('inherits from emittery', () => { - expect(runner instanceof Emittery).toBeTrue(); - }); + expect(context.foo).toBe('foo'); + }); - it('has no required parameters', () => { - function factory() { - return new TaskRunner(); + it('falls back on the context passed to the constructor', async () => { + const context = {}; + const t = new TaskRunner(context); + + t.addTask( + new Task({ + name: 'foo', + func: (ctx) => { + ctx.foo = 'foo'; + + return Promise.resolve(); + }, + }) + ); + await t.run(); + + expect(context.foo).toBe('foo'); + }); + + it('fails if the context is not an object', async () => { + let error; + + try { + await new TaskRunner().run(7); + } catch (e) { + error = e; } - expect(factory).not.toThrow(); + expect(error).toBeErrorOfType(ARGUMENT_ERROR); + }); + + it('passes the context to tasks with no dependencies', async () => { + const context = {}; + const r = new TaskRunner(context); + + r.addTask( + new Task({ + name: 'usesContext', + func: (ctx) => { + ctx.foo = 'bar'; + + return Promise.resolve(); + }, + }) + ); + + await r.run(); + expect(context.foo).toBe('bar'); + }); + + it('passes the context to tasks with dependencies', async () => { + const context = {}; + const r = new TaskRunner(context); + + r.addTasks([ + new Task({ + name: 'one', + func: (ctx) => { + ctx.foo = 'bar'; + + return Promise.resolve(); + }, + }), + new Task({ + name: 'two', + func: (ctx) => { + ctx.bar = ctx.foo + ' baz'; + + return Promise.resolve(); + }, + dependsOn: ['one'], + }), + ]); + + await r.run(); + expect(context.bar).toBe('bar baz'); + }); }); - it('does not accept a non-object context', () => { - function factory() { - return new TaskRunner(7); + describe('dependencies', () => { + it('errors if a task depends on an unknown task', async () => { + let error; + + runner.addTask( + new Task({ + name: 'badDependsOn', + func: () => Promise.resolve(), + dependsOn: ['mysteryTask'], + }) + ); + + try { + await runner.run(); + } catch (e) { + error = e; } - expect(factory).toThrowErrorOfType(ARGUMENT_ERROR); + expect(rethrower(error)).toThrowErrorOfType(UNKNOWN_DEPENDENCY_ERROR); + }); + + it('errors if there are circular dependencies', async () => { + let error; + + runner.addTasks([ + new Task({ + name: 'one', + func: () => Promise.resolve(), + dependsOn: ['two'], + }), + new Task({ + name: 'two', + func: () => Promise.resolve(), + dependsOn: ['one'], + }), + ]); + + try { + await runner.run(); + } catch (e) { + error = e; + } + + expect(rethrower(error)).toThrowErrorOfType(DEPENDENCY_CYCLE_ERROR); + }); }); - describe('addTask', () => { - it('adds `Task` objects', () => { - function add() { - runner.addTask(foo); - } + describe('events', () => { + it('emits a `start` event', async () => { + let emitted; - expect(add).not.toThrow(); + runner.addTask(foo); + runner.on('start', () => { + emitted = true; + }); + await runner.run(); + + expect(emitted).toBeTrue(); + }); + + it('emits an `end` event', async () => { + let emitted; + + runner.addTask(foo); + runner.on('end', (e) => { + emitted = e; + }); + await runner.run(); + + expect(emitted).toBeObject(); + expect(emitted.error).toBeNull(); + }); + + it('fails and emits an error in the `end` event if necessary', async () => { + let endError; + let error; + + runner.addTask(badTask); + runner.on('end', (e) => { + endError = e.error; }); - it('fails with non-`Task` objects', () => { - function add() { - runner.addTask(fakeTask); - } + try { + await runner.run(); + } catch (e) { + error = e; + } - expect(add).toThrowErrorOfType(ARGUMENT_ERROR); - }); + expect(rethrower(endError)).toThrowError(); + expect(endError).toBe(error); + }); + }); + }); - it('fails if the task runner is already running', () => { - function addWhileRunning() { - runner.run(); - runner.addTask(foo); - } + describe('running', () => { + it('is true when the task runner is running', async () => { + let running; - expect(addWhileRunning).toThrowErrorOfType(STATE_ERROR); - }); + runner.addTask( + new Task({ + name: 'checkRunning', + func: () => { + running = runner.running; - // We run the task, rather than just checking the value of `runner.tasks`, to make sure - // _all_ the internal state was set correctly. - it('correctly adds the task', async () => { - runner.addTask(foo); - await runner.run(); + return Promise.resolve(); + }, + }) + ); + await runner.run(); - expect(fooResult).toBeTrue(); - }); - - it('causes the task to be emitted when the task starts', async () => { - let promise; - - runner.addTask(foo); - promise = runner.once('taskStart'); - - foo.run(); - await promise.then(event => { - expect(event).toBe(foo); - }); - }); - - it('causes the task to be emitted when the task ends', async () => { - let event; - let promise; - - runner.addTask(foo); - promise = runner.once('taskEnd'); - - foo.run(); - event = await promise; - - expect(event).toBe(foo); - }); - - it('causes an error to be emitted if the task errors', async () => { - let error; - let event; - let promise; - - runner.addTask(badTask); - promise = runner.once('taskError'); - - try { - await runner.run(); - } catch (e) { - error = e; - } - - event = await promise; - - expect(event).toBeObject(); - expect(rethrower(event.error)).toThrowError(); - expect(event.error).toBe(error); - expect(event.task).toBe(badTask); - }); + expect(running).toBeTrue(); }); - describe('addTasks', () => { - it('accepts an object whose values are tasks', () => { - function addTasks() { - runner.addTasks({ foo }); - } + it('is false when the task runner has not started', () => { + runner.addTask(foo); - expect(addTasks).not.toThrow(); - }); - - it('fails with an object whose values are not tasks', () => { - function addTasks() { - runner.addTasks({ foo: fakeTask }); - } - - expect(addTasks).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('accepts an array of tasks', () => { - function addTasks() { - runner.addTasks([foo]); - } - - expect(addTasks).not.toThrow(); - }); - - it('fails with an array of non-tasks', () => { - function addTasks() { - runner.addTasks([fakeTask]); - } - - expect(addTasks).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('fails with non-object, non-array input', () => { - function addTasks() { - runner.addTasks(7); - } - - expect(addTasks).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('adds all the tasks in an object', () => { - let tasks; - - runner.addTasks({ - foo, - bar - }); - tasks = runner.tasks; - - expect(tasks.foo).toBe(foo); - expect(tasks.bar).toBe(bar); - }); - - it('adds all the tasks in an array', () => { - let tasks; - - runner.addTasks([ - foo, - bar - ]); - tasks = runner.tasks; - - expect(tasks.foo).toBe(foo); - expect(tasks.bar).toBe(bar); - }); - - it('returns `this`', () => { - const result = runner.addTasks({ - foo, - bar - }); - - expect(result).toBe(runner); - }); + expect(runner.running).toBeFalse(); }); - describe('end', () => { - it('stops the task runner', () => { - function addAfterEnding() { - runner.addTask(foo); - runner.run(); - runner.end(); - runner.addTask(bar); - } + it('is false after the task runner has finished', async () => { + runner.addTask(foo); + await runner.run(); - expect(addAfterEnding).not.toThrow(); - }); + expect(runner.running).toBeFalse(); + }); + }); - it('resets the tasks', async () => { - runner.addTask(foo); - runner.run(); - await runner.end(); + describe('tasks', () => { + it('is an object in which keys are task names and values are tasks', () => { + let tasks; - expect(runner.tasks).toBeEmptyObject(); - }); + runner.addTask(foo); + tasks = runner.tasks; + + expect(tasks).toBeObject(); + expect(tasks.foo).toBe(foo); }); - describe('removeTask', () => { - it('removes `Task` objects', () => { - runner.addTask(foo); - runner.removeTask(foo); - - expect(runner.tasks.foo).toBeUndefined(); - }); - - it('removes tasks by name', () => { - runner.addTask(foo); - runner.removeTask('foo'); - - expect(runner.tasks.foo).toBeUndefined(); - }); - - it('fails on invalid input types', () => { - function addRemove() { - runner.addTask(foo); - runner.removeTask(7); - } - - expect(addRemove).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('fails on unknown tasks', () => { - function addRemove() { - runner.addTask(foo); - runner.removeTask(bar); - } - - expect(addRemove).toThrowErrorOfType(UNKNOWN_TASK_ERROR); - }); - - it('fails if the task runner is already running', () => { - function removeWhileRunning() { - runner.addTasks([foo, bar]); - runner.run(); - runner.removeTask(foo); - } - - expect(removeWhileRunning).toThrowErrorOfType(STATE_ERROR); - }); - - it('correctly removes the task', async () => { - let error; - - runner.addTasks([foo, bar]); - runner.removeTask(foo); - - try { - await runner.run(); - } catch (e) { - error = e; - } - - expect(error).toBeUndefined(); - expect(fooResult).toBeNull(); - expect(barResult).toBeTrue(); - }); - - it('prevents `taskStart`/`taskEnd` events for the task', async () => { - let startEvent; - let endEvent; - - runner.on('taskStart', e => { - startEvent = e; - }); - runner.on('taskEnd', e => { - endEvent = e; - }); - runner.addTask(foo); - runner.removeTask(foo); - await foo.run(); - - expect(startEvent).toBeUndefined(); - expect(endEvent).toBeUndefined(); - }); - - it('prevents `taskError` events for the task', async () => { - let errorEvent; - let taskErrorEvent; - - runner.addTask(badTask); - runner.removeTask(badTask); - - badTask.on('error', e => { - errorEvent = e; - }); - runner.on('taskError', e => { - taskErrorEvent = e; - }); - - try { - await badTask.run(); - } catch (e) { - // Expected behavior. - } - - expect(errorEvent).toBeObject(); - expect(errorEvent.task).toBe(badTask); - expect(taskErrorEvent).toBeUndefined(); - }); - - it('returns `this`', () => { - let result; - - runner.addTask(foo); - result = runner.removeTask(foo); - - expect(result).toBe(runner); - }); - }); - - describe('removeTasks', () => { - it('accepts an object whose values are tasks', () => { - function removeTasks() { - runner.removeTasks({ foo }); - } - - runner.addTask(foo); - - expect(removeTasks).not.toThrow(); - }); - - it('fails with an object whose values are not tasks', () => { - function removeTasks() { - runner.removeTasks({ foo: 7 }); - } - - runner.addTask(foo); - - expect(removeTasks).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('accepts an array of tasks', () => { - function removeTasks() { - runner.removeTasks([foo]); - } - - runner.addTask(foo); - - expect(removeTasks).not.toThrow(); - }); - - it('accepts an array of strings', () => { - function removeTasks() { - runner.removeTasks(['foo']); - } - - runner.addTask(foo); - - expect(removeTasks).not.toThrow(); - }); - - it('fails with an array whose values are not tasks or strings', () => { - function removeTasks() { - runner.removeTasks([fakeTask]); - } - - expect(removeTasks).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('fails with non-object, non-array input', () => { - function removeTasks() { - runner.removeTasks(7); - } - - expect(removeTasks).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('fails with unknown tasks', () => { - function removeTasks() { - runner.removeTasks([bar]); - } - - expect(removeTasks).toThrowErrorOfType(UNKNOWN_TASK_ERROR); - }); - - it('removes all the tasks in an object', () => { - const tasks = { - foo, - bar - }; - - runner.addTasks(tasks); - runner.removeTasks(tasks); - - expect(runner.tasks).toBeEmptyObject(); - }); - - it('removes all the tasks in an array', () => { - const tasks = [ - foo, - bar - ]; - - runner.addTasks(tasks); - runner.removeTasks(tasks); - - expect(runner.tasks).toBeEmptyObject(); - }); - - it('returns `this`', () => { - runner.addTask(foo); - - expect(runner.removeTask(foo)).toBe(runner); - }); - }); - - describe('run', () => { - let a; - let b; - let c; - let taskA; - let taskB; - let taskC; - - beforeEach(() => { - a = null; - b = null; - c = null; - - taskA = new Task({ - name: 'a', - func: () => { - a = 5; - - return Promise.resolve(); - } - }); - taskB = new Task({ - name: 'b', - func: () => { - b = a * 3; - - return Promise.resolve(); - }, - dependsOn: ['a'] - }); - taskC = new Task({ - name: 'c', - func: () => { - c = a + b; - - return Promise.resolve(); - }, - dependsOn: ['b'] - }); - }); - - it('runs every task', async () => { - runner.addTasks([taskA, taskB, taskC]); - await runner.run(); - - expect(a).toBe(5); - expect(b).toBe(15); - expect(c).toBe(20); - }); - - it('runs tasks with dependencies in the correct order', async () => { - const results = []; - - taskA.on('end', () => { - results.push(a); - }); - taskB.on('end', () => { - results.push(b); - }); - taskC.on('end', () => { - results.push(c); - }); - - runner.addTasks([taskA, taskB, taskC]); - await runner.run(); - - expect(results).toEqual([5, 15, 20]); - }); - - it('fails if the task runner is already running', async () => { - let error; - - runner.addTask(taskA); - runner.run(); - - try { - await runner.run(); - } catch (e) { - error = e; - } - - expect(rethrower(error)).toThrowErrorOfType(STATE_ERROR); - }); - - it('clears all of its state after it runs', async () => { - runner.addTask(taskA); - await runner.run(); - - expect(runner.tasks).toBeEmptyObject(); - }); - - it('fails if a task errors', async () => { - let error; - - runner.addTask(badTask); - try { - await runner.run(); - } catch (e) { - error = e; - } - - expect(rethrower(error)).toThrowError(); - }); - - describe('context', () => { - it('prefers the context passed to `run()`', async () => { - const context = {}; - const t = new TaskRunner({}); - - t.addTask(new Task({ - name: 'foo', - func: ctx => { - ctx.foo = 'foo'; - - return Promise.resolve(); - } - })); - await t.run(context); - - expect(context.foo).toBe('foo'); - }); - - it('falls back on the context passed to the constructor', async () => { - const context = {}; - const t = new TaskRunner(context); - - t.addTask(new Task({ - name: 'foo', - func: ctx => { - ctx.foo = 'foo'; - - return Promise.resolve(); - } - })); - await t.run(); - - expect(context.foo).toBe('foo'); - }); - - it('fails if the context is not an object', async () => { - let error; - - try { - await new TaskRunner().run(7); - } catch (e) { - error = e; - } - - expect(error).toBeErrorOfType(ARGUMENT_ERROR); - }); - - it('passes the context to tasks with no dependencies', async () => { - const context = {}; - const r = new TaskRunner(context); - - r.addTask(new Task({ - name: 'usesContext', - func: ctx => { - ctx.foo = 'bar'; - - return Promise.resolve(); - } - })); - - await r.run(); - expect(context.foo).toBe('bar'); - }); - - it('passes the context to tasks with dependencies', async () => { - const context = {}; - const r = new TaskRunner(context); - - r.addTasks([ - new Task({ - name: 'one', - func: ctx => { - ctx.foo = 'bar'; - - return Promise.resolve(); - } - }), - new Task({ - name: 'two', - func: ctx => { - ctx.bar = ctx.foo + ' baz'; - - return Promise.resolve(); - }, - dependsOn: ['one'] - }) - ]); - - await r.run(); - expect(context.bar).toBe('bar baz'); - }); - }); - - describe('dependencies', () => { - it('errors if a task depends on an unknown task', async () => { - let error; - - runner.addTask(new Task({ - name: 'badDependsOn', - func: () => Promise.resolve(), - dependsOn: ['mysteryTask'] - })); - - try { - await runner.run(); - } catch (e) { - error = e; - } - - expect(rethrower(error)).toThrowErrorOfType(UNKNOWN_DEPENDENCY_ERROR); - }); - - it('errors if there are circular dependencies', async () => { - let error; - - runner.addTasks([ - new Task({ - name: 'one', - func: () => Promise.resolve(), - dependsOn: ['two'] - }), - new Task({ - name: 'two', - func: () => Promise.resolve(), - dependsOn: ['one'] - }) - ]); - - try { - await runner.run(); - } catch (e) { - error = e; - } - - expect(rethrower(error)).toThrowErrorOfType(DEPENDENCY_CYCLE_ERROR); - }); - }); - - describe('events', () => { - it('emits a `start` event', async () => { - let emitted; - - runner.addTask(foo); - runner.on('start', () => { - emitted = true; - }); - await runner.run(); - - expect(emitted).toBeTrue(); - }); - - it('emits an `end` event', async () => { - let emitted; - - runner.addTask(foo); - runner.on('end', e => { - emitted = e; - }); - await runner.run(); - - expect(emitted).toBeObject(); - expect(emitted.error).toBeNull(); - }); - - it('fails and emits an error in the `end` event if necessary', async () => { - let endError; - let error; - - runner.addTask(badTask); - runner.on('end', e => { - endError = e.error; - }); - - try { - await runner.run(); - } catch (e) { - error = e; - } - - expect(rethrower(endError)).toThrowError(); - expect(endError).toBe(error); - }); - }); - }); - - describe('running', () => { - it('is true when the task runner is running', async () => { - let running; - - runner.addTask(new Task({ - name: 'checkRunning', - func: () => { - running = runner.running; - - return Promise.resolve(); - } - })); - await runner.run(); - - expect(running).toBeTrue(); - }); - - it('is false when the task runner has not started', () => { - runner.addTask(foo); - - expect(runner.running).toBeFalse(); - }); - - it('is false after the task runner has finished', async () => { - runner.addTask(foo); - await runner.run(); - - expect(runner.running).toBeFalse(); - }); - }); - - describe('tasks', () => { - it('is an object in which keys are task names and values are tasks', () => { - let tasks; - - runner.addTask(foo); - tasks = runner.tasks; - - expect(tasks).toBeObject(); - expect(tasks.foo).toBe(foo); - }); - - it('is an empty object if no tasks have been added', () => { - expect(runner.tasks).toBeEmptyObject(); - }); + it('is an empty object if no tasks have been added', () => { + expect(runner.tasks).toBeEmptyObject(); }); + }); }); diff --git a/packages/jsdoc-task-runner/test/specs/lib/task.js b/packages/jsdoc-task-runner/test/specs/lib/task.js index 9ce5c3b3..be9a8a1a 100644 --- a/packages/jsdoc-task-runner/test/specs/lib/task.js +++ b/packages/jsdoc-task-runner/test/specs/lib/task.js @@ -4,201 +4,200 @@ const Task = require('../../../lib/task'); const ARGUMENT_ERROR = 'ArgumentError'; describe('@jsdoc/task-runner/lib/task', () => { - it('is a function', () => { - expect(Task).toBeFunction(); + it('is a function', () => { + expect(Task).toBeFunction(); + }); + + it('inherits from emittery', () => { + expect(new Task() instanceof Emittery).toBeTrue(); + }); + + it('can be constructed with no arguments', () => { + function factory() { + return new Task(); + } + + expect(factory).not.toThrow(); + }); + + it('uses the provided name', () => { + const task = new Task({ name: 'foo' }); + + expect(task.name).toBe('foo'); + }); + + it('uses the provided function', () => { + const func = () => Promise.resolve(); + const task = new Task({ func }); + + expect(task.func).toBe(func); + }); + + describe('dependsOn', () => { + it('accepts an array of task names as dependencies', () => { + const dependsOn = ['bar', 'baz']; + const task = new Task({ + name: 'foo', + func: () => Promise.resolve(), + dependsOn, + }); + + expect(task.dependsOn).toEqual(dependsOn); }); - it('inherits from emittery', () => { - expect(new Task() instanceof Emittery).toBeTrue(); + it('accepts a single task name as a dependency', () => { + const task = new Task({ + name: 'foo', + func: () => Promise.resolve(), + dependsOn: 'bar', + }); + + expect(task.dependsOn).toEqual(['bar']); }); - it('can be constructed with no arguments', () => { - function factory() { - return new Task(); + it('fails with non-string, non-array dependencies', () => { + function factory() { + return new Task({ + name: 'foo', + func: () => Promise.resolve(), + dependsOn: 7, + }); + } + + expect(factory).toThrowErrorOfType(ARGUMENT_ERROR); + }); + + it('fails with non-string arrays of dependencies', () => { + function factory() { + return new Task({ + name: 'foo', + func: () => Promise.resolve(), + dependsOn: [7], + }); + } + + expect(factory).toThrowErrorOfType(ARGUMENT_ERROR); + }); + }); + + it('uses the provided dependencies', () => { + const dependsOn = ['foo', 'bar']; + const task = new Task({ dependsOn }); + + expect(task.dependsOn).toEqual(dependsOn); + }); + + describe('run', () => { + it('requires a name', async () => { + let error; + + async function start() { + const task = new Task({ + func: () => Promise.resolve(), + }); + + await task.run(); + } + + try { + await start(); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + }); + + it('requires a function', async () => { + let error; + + async function run() { + const task = new Task({ + name: 'foo', + }); + + await task.run(); + } + + try { + await run(); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + }); + + it('accepts a context object', async () => { + const context = {}; + const task = new Task({ + name: 'foo', + func: (c) => { + c.foo = 'bar'; + + return Promise.resolve(); + }, + }); + + await task.run(context); + + expect(context.foo).toBe('bar'); + }); + + describe('events', () => { + it('emits a `start` event', async () => { + let event; + const task = new Task({ + name: 'foo', + func: () => Promise.resolve(), + }); + + task.on('start', (e) => { + event = e; + }); + + await task.run(); + + expect(event).toBe(task); + }); + + it('emits an `end` event', async () => { + let event; + const task = new Task({ + name: 'foo', + func: () => Promise.resolve(), + }); + + task.on('end', (e) => { + event = e; + }); + + await task.run(); + + expect(event).toBe(task); + }); + + it('emits an `error` event if necessary', async () => { + let error = new Error('oh no!'); + let event; + const task = new Task({ + name: 'foo', + func: () => Promise.reject(error), + }); + + task.on('error', (e) => { + event = e; + }); + + try { + await task.run(); + } catch (e) { + // Expected behavior. } - expect(factory).not.toThrow(); - }); - - it('uses the provided name', () => { - const task = new Task({ name: 'foo' }); - - expect(task.name).toBe('foo'); - }); - - it('uses the provided function', () => { - const func = () => Promise.resolve(); - const task = new Task({ func }); - - expect(task.func).toBe(func); - }); - - describe('dependsOn', () => { - it('accepts an array of task names as dependencies', () => { - const dependsOn = ['bar', 'baz']; - const task = new Task({ - name: 'foo', - func: () => Promise.resolve(), - dependsOn - }); - - expect(task.dependsOn).toEqual(dependsOn); - }); - - it('accepts a single task name as a dependency', () => { - const task = new Task({ - name: 'foo', - func: () => Promise.resolve(), - dependsOn: 'bar' - }); - - expect(task.dependsOn).toEqual(['bar']); - }); - - it('fails with non-string, non-array dependencies', () => { - function factory() { - return new Task({ - name: 'foo', - func: () => Promise.resolve(), - dependsOn: 7 - }); - } - - expect(factory).toThrowErrorOfType(ARGUMENT_ERROR); - }); - - it('fails with non-string arrays of dependencies', () => { - function factory() { - return new Task({ - name: 'foo', - func: () => Promise.resolve(), - dependsOn: [7] - }); - } - - expect(factory).toThrowErrorOfType(ARGUMENT_ERROR); - }); - }); - - it('uses the provided dependencies', () => { - const dependsOn = ['foo', 'bar']; - const task = new Task({ dependsOn }); - - expect(task.dependsOn).toEqual(dependsOn); - }); - - describe('run', () => { - it('requires a name', async () => { - let error; - - async function start() { - const task = new Task({ - func: () => Promise.resolve() - }); - - await task.run(); - } - - try { - await start(); - } catch (e) { - error = e; - } - - expect(error).toBeDefined(); - }); - - it('requires a function', async () => { - let error; - - async function run() { - const task = new Task({ - name: 'foo' - }); - - await task.run(); - } - - try { - await run(); - } catch (e) { - error = e; - } - - expect(error).toBeDefined(); - }); - - it('accepts a context object', async () => { - const context = {}; - const task = new Task({ - name: 'foo', - func: c => { - c.foo = 'bar'; - - return Promise.resolve(); - } - }); - - await task.run(context); - - expect(context.foo).toBe('bar'); - }); - - describe('events', () => { - it('emits a `start` event', async () => { - let event; - const task = new Task({ - name: 'foo', - func: () => Promise.resolve() - }); - - task.on('start', e => { - event = e; - }); - - await task.run(); - - expect(event).toBe(task); - }); - - it('emits an `end` event', async () => { - let event; - const task = new Task({ - name: 'foo', - func: () => Promise.resolve() - }); - - task.on('end', e => { - event = e; - }); - - await task.run(); - - expect(event).toBe(task); - }); - - it('emits an `error` event if necessary', async () => { - let error = new Error('oh no!'); - let event; - const task = new Task({ - name: 'foo', - func: () => Promise.reject(error) - }); - - task.on('error', e => { - event = e; - }); - - try { - await task.run(); - } catch (e) { - // Expected behavior. - } - - - expect(event.error).toBe(error); - expect(event.task).toBe(task); - }); - }); + expect(event.error).toBe(error); + expect(event.task).toBe(task); + }); }); + }); }); diff --git a/packages/jsdoc-test-matchers/index.js b/packages/jsdoc-test-matchers/index.js index ab3831a5..e3c5d6fe 100644 --- a/packages/jsdoc-test-matchers/index.js +++ b/packages/jsdoc-test-matchers/index.js @@ -3,32 +3,32 @@ const { addMatchers } = require('add-matchers'); require('jasmine-expect'); addMatchers({ - toBeError(value) { - return value instanceof Error; - }, - toBeErrorOfType(other, value) { - return value instanceof Error && value.name === other; - }, - toBeInstanceOf(other, value) { - let otherName; - let valueName; + toBeError(value) { + return value instanceof Error; + }, + toBeErrorOfType(other, value) { + return value instanceof Error && value.name === other; + }, + toBeInstanceOf(other, value) { + let otherName; + let valueName; - if (typeof value !== 'object') { - throw new TypeError(`Expected object value, got ${typeof value}`); - } - - valueName = value.constructor.name; - - // Class name. - if (typeof other === 'string') { - otherName = other; - // Class constructor. - } else if (typeof other === 'function') { - otherName = other.name; - } else { - otherName = other.constructor.name; - } - - return valueName === otherName; + if (typeof value !== 'object') { + throw new TypeError(`Expected object value, got ${typeof value}`); } + + valueName = value.constructor.name; + + // Class name. + if (typeof other === 'string') { + otherName = other; + // Class constructor. + } else if (typeof other === 'function') { + otherName = other.name; + } else { + otherName = other.constructor.name; + } + + return valueName === otherName; + }, }); diff --git a/packages/jsdoc-test-matchers/package-lock.json b/packages/jsdoc-test-matchers/package-lock.json index 18380c77..dceb035a 100644 --- a/packages/jsdoc-test-matchers/package-lock.json +++ b/packages/jsdoc-test-matchers/package-lock.json @@ -1,8 +1,35 @@ { "name": "@jsdoc/test-matchers", "version": "0.1.6", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@jsdoc/test-matchers", + "version": "0.1.6", + "license": "Apache-2.0", + "dependencies": { + "add-matchers": "^0.6.2", + "jasmine-expect": "^5.0.0" + }, + "engines": { + "node": ">=v14.17.6" + } + }, + "node_modules/add-matchers": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/add-matchers/-/add-matchers-0.6.2.tgz", + "integrity": "sha512-hVO2wodMei9RF00qe+506MoeJ/NEOdCMEkSJ12+fC3hx/5Z4zmhNiP92nJEF6XhmXokeB0hOtuQrjHCx2vmXrQ==" + }, + "node_modules/jasmine-expect": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/jasmine-expect/-/jasmine-expect-5.0.0.tgz", + "integrity": "sha512-byn1zq0EQBA9UKs5A+H6gk5TRcanV+TqQMRxrjurGuqKkclaqgjw/vV6aT/jtf5tabXGonTH6VDZJ33Z1pxSxw==", + "dependencies": { + "add-matchers": "0.6.2" + } + } + }, "dependencies": { "add-matchers": { "version": "0.6.2", diff --git a/packages/jsdoc-util/index.js b/packages/jsdoc-util/index.js index 2d5835b7..a5acaef1 100644 --- a/packages/jsdoc-util/index.js +++ b/packages/jsdoc-util/index.js @@ -10,8 +10,8 @@ const fs = require('./lib/fs'); const log = require('./lib/log'); module.exports = { - cast, - EventBus, - fs, - log + cast, + EventBus, + fs, + log, }; diff --git a/packages/jsdoc-util/lib/bus.js b/packages/jsdoc-util/lib/bus.js index e3cc865f..43291d3f 100644 --- a/packages/jsdoc-util/lib/bus.js +++ b/packages/jsdoc-util/lib/bus.js @@ -1,6 +1,6 @@ const _ = require('lodash'); const EventEmitter = require('events').EventEmitter; -const {default: ow} = require('ow'); +const { default: ow } = require('ow'); let cache = {}; const hasOwnProp = Object.prototype.hasOwnProperty; @@ -22,31 +22,31 @@ const hasOwnProp = Object.prototype.hasOwnProperty; * @extends module:events.EventEmitter */ class EventBus extends EventEmitter { - /** - * Create a new event bus, or retrieve the cached event bus for the ID you specify. - * - * @param {(string|Symbol)} id - The ID for the event bus. - * @param {Object} opts - Options for the event bus. - * @param {boolean} [opts.cache=true] - Set to `false` to prevent the event bus from being - * cached, and to return a new event bus even if there is already an event bus with the same ID. - */ - constructor(id, opts = {}) { - super(); + /** + * Create a new event bus, or retrieve the cached event bus for the ID you specify. + * + * @param {(string|Symbol)} id - The ID for the event bus. + * @param {Object} opts - Options for the event bus. + * @param {boolean} [opts.cache=true] - Set to `false` to prevent the event bus from being + * cached, and to return a new event bus even if there is already an event bus with the same ID. + */ + constructor(id, opts = {}) { + super(); - ow(id, ow.any(ow.string, ow.symbol)); + ow(id, ow.any(ow.string, ow.symbol)); - const shouldCache = _.isBoolean(opts.cache) ? opts.cache : true; + const shouldCache = _.isBoolean(opts.cache) ? opts.cache : true; - if (hasOwnProp.call(cache, id) && shouldCache) { - return cache[id]; - } - - this._id = id; - - if (shouldCache) { - cache[id] = this; - } + if (hasOwnProp.call(cache, id) && shouldCache) { + return cache[id]; } + + this._id = id; + + if (shouldCache) { + cache[id] = this; + } + } } module.exports = EventBus; diff --git a/packages/jsdoc-util/lib/cast.js b/packages/jsdoc-util/lib/cast.js index e34c9663..75cc2e38 100644 --- a/packages/jsdoc-util/lib/cast.js +++ b/packages/jsdoc-util/lib/cast.js @@ -13,49 +13,47 @@ * @return {(string|number|boolean)} The converted value. */ function castString(str) { - let number; - let result; + let number; + let result; - switch (str) { - case 'true': - result = true; - break; + switch (str) { + case 'true': + result = true; + break; - case 'false': - result = false; - break; + case 'false': + result = false; + break; - case 'NaN': - result = NaN; - break; + case 'NaN': + result = NaN; + break; - case 'null': - result = null; - break; + case 'null': + result = null; + break; - case 'undefined': - result = undefined; - break; + case 'undefined': + result = undefined; + break; - default: - if (typeof str === 'string') { - if (str.includes('.')) { - number = parseFloat(str); - } - else { - number = parseInt(str, 10); - } + default: + if (typeof str === 'string') { + if (str.includes('.')) { + number = parseFloat(str); + } else { + number = parseInt(str, 10); + } - if (String(number) === str && !isNaN(number)) { - result = number; - } - else { - result = str; - } - } - } + if (String(number) === str && !isNaN(number)) { + result = number; + } else { + result = str; + } + } + } - return result; + return result; } /** @@ -69,27 +67,24 @@ function castString(str) { * @param {(string|Object|Array)} item - The item whose type or types will be converted. * @return {*?} The converted value. */ -const cast = module.exports = item => { - let result; +const cast = (module.exports = (item) => { + let result; - if (Array.isArray(item)) { - result = []; - for (let i = 0, l = item.length; i < l; i++) { - result[i] = cast(item[i]); - } - } - else if (typeof item === 'object' && item !== null) { - result = {}; - Object.keys(item).forEach(prop => { - result[prop] = cast(item[prop]); - }); - } - else if (typeof item === 'string') { - result = castString(item); - } - else { - result = item; + if (Array.isArray(item)) { + result = []; + for (let i = 0, l = item.length; i < l; i++) { + result[i] = cast(item[i]); } + } else if (typeof item === 'object' && item !== null) { + result = {}; + Object.keys(item).forEach((prop) => { + result[prop] = cast(item[prop]); + }); + } else if (typeof item === 'string') { + result = castString(item); + } else { + result = item; + } - return result; -}; + return result; +}); diff --git a/packages/jsdoc-util/lib/fs.js b/packages/jsdoc-util/lib/fs.js index db414a02..a1052126 100644 --- a/packages/jsdoc-util/lib/fs.js +++ b/packages/jsdoc-util/lib/fs.js @@ -6,14 +6,14 @@ const _ = require('lodash'); const klawSync = require('klaw-sync'); const path = require('path'); -exports.lsSync = ((dir, opts = {}) => { - const depth = _.has(opts, 'depth') ? opts.depth : -1; +exports.lsSync = (dir, opts = {}) => { + const depth = _.has(opts, 'depth') ? opts.depth : -1; - const files = klawSync(dir, { - depthLimit: depth, - filter: (f => !path.basename(f.path).startsWith('.')), - nodir: true - }); + const files = klawSync(dir, { + depthLimit: depth, + filter: (f) => !path.basename(f.path).startsWith('.'), + nodir: true, + }); - return files.map(f => f.path); -}); + return files.map((f) => f.path); +}; diff --git a/packages/jsdoc-util/lib/log.js b/packages/jsdoc-util/lib/log.js index 914077d1..ba81b45a 100644 --- a/packages/jsdoc-util/lib/log.js +++ b/packages/jsdoc-util/lib/log.js @@ -3,8 +3,8 @@ const EventBus = require('./bus'); const bus = new EventBus('jsdoc'); const loggerFuncs = {}; -['debug', 'error', 'info', 'fatal', 'verbose', 'warn'].forEach(fn => { - loggerFuncs[fn] = (...args) => bus.emit(`logger:${fn}`, ...args); +['debug', 'error', 'info', 'fatal', 'verbose', 'warn'].forEach((fn) => { + loggerFuncs[fn] = (...args) => bus.emit(`logger:${fn}`, ...args); }); module.exports = loggerFuncs; diff --git a/packages/jsdoc-util/package-lock.json b/packages/jsdoc-util/package-lock.json index 5bb0f33f..3e110923 100644 --- a/packages/jsdoc-util/package-lock.json +++ b/packages/jsdoc-util/package-lock.json @@ -1,8 +1,125 @@ { "name": "@jsdoc/util", "version": "0.2.4", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@jsdoc/util", + "version": "0.2.4", + "license": "Apache-2.0", + "dependencies": { + "klaw-sync": "^6.0.0", + "lodash": "^4.17.21", + "ow": "^0.27.0" + }, + "engines": { + "node": ">=v14.17.6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-fest": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.2.2.tgz", + "integrity": "sha512-pfkPYCcuV0TJoo/jlsUeWNV8rk7uMU6ocnYNvca1Vu+pyKi8Rl8Zo2scPt9O72gCsXIm+dMxOOWuA3VFDSdzWA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", + "engines": { + "node": ">=0.10.0" + } + } + }, "dependencies": { "@sindresorhus/is": { "version": "4.0.1", diff --git a/packages/jsdoc-util/test/specs/index.js b/packages/jsdoc-util/test/specs/index.js index 7a7dec0e..fae8bf40 100644 --- a/packages/jsdoc-util/test/specs/index.js +++ b/packages/jsdoc-util/test/specs/index.js @@ -1,31 +1,31 @@ const util = require('../../index'); describe('@jsdoc/util', () => { - it('is an object', () => { - expect(util).toBeObject(); + it('is an object', () => { + expect(util).toBeObject(); + }); + + describe('cast', () => { + it('is lib/cast', () => { + const cast = require('../../lib/cast'); + + expect(util.cast).toBe(cast); }); + }); - describe('cast', () => { - it('is lib/cast', () => { - const cast = require('../../lib/cast'); + describe('EventBus', () => { + it('is lib/bus', () => { + const bus = require('../../lib/bus'); - expect(util.cast).toBe(cast); - }); + expect(util.EventBus).toBe(bus); }); + }); - describe('EventBus', () => { - it('is lib/bus', () => { - const bus = require('../../lib/bus'); + describe('fs', () => { + it('is lib/fs', () => { + const fs = require('../../lib/fs'); - expect(util.EventBus).toBe(bus); - }); - }); - - describe('fs', () => { - it('is lib/fs', () => { - const fs = require('../../lib/fs'); - - expect(util.fs).toBe(fs); - }); + expect(util.fs).toBe(fs); }); + }); }); diff --git a/packages/jsdoc-util/test/specs/lib/bus.js b/packages/jsdoc-util/test/specs/lib/bus.js index ea067bba..5736e8fb 100644 --- a/packages/jsdoc-util/test/specs/lib/bus.js +++ b/packages/jsdoc-util/test/specs/lib/bus.js @@ -1,66 +1,66 @@ describe('@jsdoc/util/lib/bus', () => { - const EventBus = require('../../../lib/bus'); - const EventEmitter = require('events').EventEmitter; + const EventBus = require('../../../lib/bus'); + const EventEmitter = require('events').EventEmitter; - const ignoreCache = { cache: false }; + const ignoreCache = { cache: false }; - it('inherits from EventEmitter', () => { - expect(new EventBus('foo', ignoreCache) instanceof EventEmitter).toBeTrue(); + it('inherits from EventEmitter', () => { + expect(new EventBus('foo', ignoreCache) instanceof EventEmitter).toBeTrue(); + }); + + it('accepts a string for the ID', () => { + function makeBus() { + return new EventBus('foo', ignoreCache); + } + + expect(makeBus).not.toThrow(); + }); + + it('accepts a Symbol for the ID', () => { + function makeBus() { + return new EventBus(Symbol('foo'), ignoreCache); + } + + expect(makeBus).not.toThrow(); + }); + + it('throws on bad IDs', () => { + function crashBus() { + return new EventBus(true, ignoreCache); + } + + expect(crashBus).toThrowError(); + }); + + it('uses a cache by default', () => { + let fired = false; + const id = Symbol('cache-test'); + const bus1 = new EventBus(id); + const bus2 = new EventBus(id); + + bus1.once('foo', () => { + fired = true; }); - it('accepts a string for the ID', () => { - function makeBus() { - return new EventBus('foo', ignoreCache); - } + bus2.emit('foo'); - expect(makeBus).not.toThrow(); + expect(bus1).toBe(bus2); + expect(fired).toBeTrue(); + }); + + it('ignores the cache when asked', () => { + let fired = false; + const id = Symbol('cache-test'); + const bus1 = new EventBus(id, ignoreCache); + const bus2 = new EventBus(id, ignoreCache); + + bus1.once('foo', () => { + fired = true; }); - it('accepts a Symbol for the ID', () => { - function makeBus() { - return new EventBus(Symbol('foo'), ignoreCache); - } + bus2.emit('foo'); - expect(makeBus).not.toThrow(); - }); - - it('throws on bad IDs', () => { - function crashBus() { - return new EventBus(true, ignoreCache); - } - - expect(crashBus).toThrowError(); - }); - - it('uses a cache by default', () => { - let fired = false; - const id = Symbol('cache-test'); - const bus1 = new EventBus(id); - const bus2 = new EventBus(id); - - bus1.once('foo', () => { - fired = true; - }); - - bus2.emit('foo'); - - expect(bus1).toBe(bus2); - expect(fired).toBeTrue(); - }); - - it('ignores the cache when asked', () => { - let fired = false; - const id = Symbol('cache-test'); - const bus1 = new EventBus(id, ignoreCache); - const bus2 = new EventBus(id, ignoreCache); - - bus1.once('foo', () => { - fired = true; - }); - - bus2.emit('foo'); - - expect(bus1).not.toBe(bus2); - expect(fired).toBeFalse(); - }); + expect(bus1).not.toBe(bus2); + expect(fired).toBeFalse(); + }); }); diff --git a/packages/jsdoc-util/test/specs/lib/cast.js b/packages/jsdoc-util/test/specs/lib/cast.js index b0fc8516..83df89c1 100644 --- a/packages/jsdoc-util/test/specs/lib/cast.js +++ b/packages/jsdoc-util/test/specs/lib/cast.js @@ -1,66 +1,66 @@ describe('@jsdoc/util/lib/cast', () => { - const cast = require('../../../lib/cast'); + const cast = require('../../../lib/cast'); - it('is a function', () => { - expect(cast).toBeFunction(); + it('is a function', () => { + expect(cast).toBeFunction(); + }); + + it('does not modify values that are not strings, objects, or arrays', () => { + expect(cast(8)).toBe(8); + }); + + it('does not modify strings that are neither boolean-ish nor number-ish', () => { + expect(cast('hello world')).toBe('hello world'); + }); + + it('casts "true" and "false" to booleans', () => { + expect(cast('true')).toBeTrue(); + expect(cast('false')).toBeFalse(); + }); + + it('casts "null" to null', () => { + expect(cast('null')).toBeNull(); + }); + + it('casts "undefined" to undefined', () => { + expect(cast('undefined')).toBeUndefined(); + }); + + it('casts positive number-ish strings to numbers', () => { + expect(cast('17.35')).toBe(17.35); + }); + + it('casts negative number-ish strings to numbers', () => { + expect(cast('-17.35')).toBe(-17.35); + }); + + it('casts "NaN" to NaN', () => { + expect(cast('NaN')).toBeNaN(); + }); + + it('casts values of object properties', () => { + expect(cast({ foo: 'true' })).toEqual({ foo: true }); + }); + + it('casts values of properties in nested objects', () => { + const result = cast({ + foo: { + bar: 'true', + }, }); - it('does not modify values that are not strings, objects, or arrays', () => { - expect(cast(8)).toBe(8); + expect(result).toEqual({ + foo: { + bar: true, + }, }); + }); - it('does not modify strings that are neither boolean-ish nor number-ish', () => { - expect(cast('hello world')).toBe('hello world'); - }); + it('casts values in an array', () => { + expect(cast(['true', '17.35'])).toEqual([true, 17.35]); + }); - it('casts "true" and "false" to booleans', () => { - expect(cast('true')).toBeTrue(); - expect(cast('false')).toBeFalse(); - }); - - it('casts "null" to null', () => { - expect(cast('null')).toBeNull(); - }); - - it('casts "undefined" to undefined', () => { - expect(cast('undefined')).toBeUndefined(); - }); - - it('casts positive number-ish strings to numbers', () => { - expect(cast('17.35')).toBe(17.35); - }); - - it('casts negative number-ish strings to numbers', () => { - expect(cast('-17.35')).toBe(-17.35); - }); - - it('casts "NaN" to NaN', () => { - expect(cast('NaN')).toBeNaN(); - }); - - it('casts values of object properties', () => { - expect(cast({ foo: 'true' })).toEqual({ foo: true }); - }); - - it('casts values of properties in nested objects', () => { - const result = cast({ - foo: { - bar: 'true' - } - }); - - expect(result).toEqual({ - foo: { - bar: true - } - }); - }); - - it('casts values in an array', () => { - expect(cast(['true', '17.35'])).toEqual([true, 17.35]); - }); - - it('casts values in a nested array', () => { - expect(cast(['true', ['17.35']])).toEqual([true, [17.35]]); - }); + it('casts values in a nested array', () => { + expect(cast(['true', ['17.35']])).toEqual([true, [17.35]]); + }); }); diff --git a/packages/jsdoc-util/test/specs/lib/fs.js b/packages/jsdoc-util/test/specs/lib/fs.js index cc372a63..eb919b2a 100644 --- a/packages/jsdoc-util/test/specs/lib/fs.js +++ b/packages/jsdoc-util/test/specs/lib/fs.js @@ -1,71 +1,66 @@ describe('@jsdoc/util/lib/fs', () => { - const mockFs = require('mock-fs'); - const fsUtil = require('../../../lib/fs'); - const path = require('path'); + const mockFs = require('mock-fs'); + const fsUtil = require('../../../lib/fs'); + const path = require('path'); - afterEach(() => mockFs.restore()); + afterEach(() => mockFs.restore()); - it('has an lsSync method', () => { - expect(fsUtil.lsSync).toBeFunction(); + it('has an lsSync method', () => { + expect(fsUtil.lsSync).toBeFunction(); + }); + + describe('lsSync', () => { + beforeEach(() => { + mockFs({ + head: { + eyes: '', + ears: '', + mouth: '', + nose: '', + shoulders: { + knees: { + meniscus: '', + toes: { + phalanx: '', + '.big-toe-phalanx': '', + }, + }, + }, + }, + }); }); - describe('lsSync', () => { - beforeEach(() => { - mockFs({ - head: { - eyes: '', - ears: '', - mouth: '', - nose: '', - shoulders: { - knees: { - meniscus: '', - toes: { - phalanx: '', - '.big-toe-phalanx': '' - } - } - } - } - }); - }); + const cwd = process.cwd(); - const cwd = process.cwd(); + function resolvePaths(files) { + return files.map((f) => path.join(cwd, f)).sort(); + } - function resolvePaths(files) { - return files.map(f => path.join(cwd, f)).sort(); - } + const allFiles = resolvePaths([ + 'head/eyes', + 'head/ears', + 'head/mouth', + 'head/nose', + 'head/shoulders/knees/meniscus', + 'head/shoulders/knees/toes/phalanx', + ]); - const allFiles = resolvePaths([ - 'head/eyes', - 'head/ears', - 'head/mouth', - 'head/nose', - 'head/shoulders/knees/meniscus', - 'head/shoulders/knees/toes/phalanx' - ]); + it('gets all non-hidden files from all levels by default', () => { + const files = fsUtil.lsSync(cwd).sort(); - it('gets all non-hidden files from all levels by default', () => { - const files = fsUtil.lsSync(cwd).sort(); - - expect(files).toEqual(allFiles); - }); - - it('limits recursion depth when asked', () => { - const files = fsUtil.lsSync(cwd, { depth: 1 }).sort(); - - expect(files).toEqual(resolvePaths([ - 'head/eyes', - 'head/ears', - 'head/mouth', - 'head/nose' - ])); - }); - - it('treats a depth of -1 as infinite', () => { - const files = fsUtil.lsSync('head', { depth: -1 }).sort(); - - expect(files).toEqual(allFiles); - }); + expect(files).toEqual(allFiles); }); + + it('limits recursion depth when asked', () => { + const files = fsUtil.lsSync(cwd, { depth: 1 }).sort(); + + expect(files).toEqual(resolvePaths(['head/eyes', 'head/ears', 'head/mouth', 'head/nose'])); + }); + + it('treats a depth of -1 as infinite', () => { + const files = fsUtil.lsSync('head', { depth: -1 }).sort(); + + expect(files).toEqual(allFiles); + }); + }); }); diff --git a/packages/jsdoc-util/test/specs/lib/log.js b/packages/jsdoc-util/test/specs/lib/log.js index 878b5f90..9052d6e8 100644 --- a/packages/jsdoc-util/test/specs/lib/log.js +++ b/packages/jsdoc-util/test/specs/lib/log.js @@ -1,33 +1,33 @@ describe('@jsdoc/util/lib/log', () => { - const EventBus = require('../../../lib/bus'); - const log = require('../../../lib/log'); + const EventBus = require('../../../lib/bus'); + const log = require('../../../lib/log'); - const fns = ['debug', 'error', 'info', 'fatal', 'verbose', 'warn']; + const fns = ['debug', 'error', 'info', 'fatal', 'verbose', 'warn']; - it('is an object', () => { - expect(log).toBeObject(); + it('is an object', () => { + expect(log).toBeObject(); + }); + + it('provides the expected functions', () => { + fns.forEach((fn) => { + expect(log[fn]).toBeFunction(); }); + }); - it('provides the expected functions', () => { - fns.forEach(fn => { - expect(log[fn]).toBeFunction(); - }); - }); - - describe('functions', () => { - const bus = new EventBus('jsdoc'); - - it('sends events to the event bus', () => { - fns.forEach(fn => { - let event; - - bus.once(`logger:${fn}`, e => { - event = e; - }); - log[fn]('testing'); - - expect(event).toBe('testing'); - }); + describe('functions', () => { + const bus = new EventBus('jsdoc'); + + it('sends events to the event bus', () => { + fns.forEach((fn) => { + let event; + + bus.once(`logger:${fn}`, (e) => { + event = e; }); + log[fn]('testing'); + + expect(event).toBe('testing'); + }); }); + }); }); diff --git a/packages/jsdoc/cli.js b/packages/jsdoc/cli.js index eb3c6ca3..0c926d4f 100644 --- a/packages/jsdoc/cli.js +++ b/packages/jsdoc/cli.js @@ -15,398 +15,383 @@ const Promise = require('bluebird'); * @private */ module.exports = (() => { - const props = { - docs: [], - packageJson: null, - shouldExitWithError: false, - shouldPrintHelp: false, - tmpdir: null + const props = { + docs: [], + packageJson: null, + shouldExitWithError: false, + shouldPrintHelp: false, + tmpdir: null, + }; + + const bus = new EventBus('jsdoc'); + const cli = {}; + const engine = new Engine(); + const FATAL_ERROR_MESSAGE = + 'Exiting JSDoc because an error occurred. See the previous log ' + 'messages for details.'; + const LOG_LEVELS = Engine.LOG_LEVELS; + + // TODO: docs + cli.setVersionInfo = () => { + const fs = require('fs'); + + // allow this to throw--something is really wrong if we can't read our own package file + const info = JSON.parse( + stripBom(fs.readFileSync(path.join(env.dirname, 'package.json'), 'utf8')) + ); + const revision = new Date(parseInt(info.revision, 10)); + + env.version = { + number: info.version, + revision: revision.toUTCString(), }; - const bus = new EventBus('jsdoc'); - const cli = {}; - const engine = new Engine(); - const FATAL_ERROR_MESSAGE = 'Exiting JSDoc because an error occurred. See the previous log ' + - 'messages for details.'; - const LOG_LEVELS = Engine.LOG_LEVELS; - - // TODO: docs - cli.setVersionInfo = () => { - const fs = require('fs'); - - // allow this to throw--something is really wrong if we can't read our own package file - const info = JSON.parse(stripBom(fs.readFileSync(path.join(env.dirname, 'package.json'), - 'utf8'))); - const revision = new Date(parseInt(info.revision, 10)); - - env.version = { - number: info.version, - revision: revision.toUTCString() - }; - - engine.version = env.version.number; - engine.revision = revision; - - return cli; - }; - - // TODO: docs - cli.loadConfig = () => { - const _ = require('lodash'); - let conf; - - try { - env.opts = engine.parseFlags(env.args); - } - catch (e) { - props.shouldPrintHelp = true; - cli.exit( - 1, - `${e.message}\n` - ); - - return cli; - } - - try { - conf = config.loadSync(env.opts.configure); - env.conf = conf.config; - } - catch (e) { - cli.exit( - 1, - `Cannot parse the config file ${conf.filepath}: ${e}\n${FATAL_ERROR_MESSAGE}` - ); - - return cli; - } - - // look for options on the command line, then in the config - env.opts = _.defaults(env.opts, env.conf.opts); - - return cli; - }; - - // TODO: docs - cli.configureLogger = () => { - function recoverableError() { - props.shouldExitWithError = true; - } - - function fatalError() { - cli.exit(1); - } - - if (env.opts.test) { - engine.logLevel = LOG_LEVELS.SILENT; - } else { - if (env.opts.debug) { - engine.logLevel = LOG_LEVELS.DEBUG; - } - else if (env.opts.verbose) { - engine.logLevel = LOG_LEVELS.INFO; - } - - if (env.opts.pedantic) { - bus.once('logger:warn', recoverableError); - bus.once('logger:error', fatalError); - } - else { - bus.once('logger:error', recoverableError); - } - - bus.once('logger:fatal', fatalError); - } - - return cli; - }; - - // TODO: docs - cli.logStart = () => { - log.debug(engine.versionDetails); - log.debug('Environment info: %j', { - env: { - conf: env.conf, - opts: env.opts - } - }); - }; - - // TODO: docs - cli.logFinish = () => { - let delta; - let deltaSeconds; - - if (env.run.finish && env.run.start) { - delta = env.run.finish.getTime() - env.run.start.getTime(); - } - - if (delta !== undefined) { - deltaSeconds = (delta / 1000).toFixed(2); - log.info(`Finished running in ${deltaSeconds} seconds.`); - } - }; - - // TODO: docs - cli.runCommand = () => { - let cmd; - const opts = env.opts; - - // If we already need to exit with an error, don't do any more work. - if (props.shouldExitWithError) { - cmd = () => Promise.resolve(0); - } - else if (opts.help) { - cmd = cli.printHelp; - } - else if (opts.test) { - cmd = cli.runTests; - } - else if (opts.version) { - cmd = cli.printVersion; - } - else { - cmd = cli.main; - } - - return cmd().then(errorCode => { - if (!errorCode && props.shouldExitWithError) { - errorCode = 1; - } - - cli.logFinish(); - cli.exit(errorCode || 0); - }); - }; - - // TODO: docs - cli.printHelp = () => { - cli.printVersion(); - console.log(engine.help({ maxLength: process.stdout.columns })); - - return Promise.resolve(0); - }; - - // TODO: docs - cli.runTests = () => require('./test')(); - - // TODO: docs - cli.printVersion = () => { - console.log(engine.versionDetails); - - return Promise.resolve(0); - }; - - // TODO: docs - cli.main = () => { - cli.scanFiles(); - - if (env.sourceFiles.length === 0) { - console.log('There are no input files to process.'); - - return Promise.resolve(0); - } else { - return cli.createParser() - .parseFiles() - .processParseResults() - .then(() => { - env.run.finish = new Date(); - - return 0; - }); - } - }; - - function readPackageJson(filepath) { - const fs = require('fs'); - - try { - return stripJsonComments( fs.readFileSync(filepath, 'utf8') ); - } - catch (e) { - log.error(`Unable to read the package file ${filepath}`); - - return null; - } - } - - function buildSourceList() { - let packageJson; - let sourceFile; - let sourceFiles = env.opts._ ? env.opts._.slice(0) : []; - - if (env.conf.source && env.conf.source.include) { - sourceFiles = sourceFiles.concat(env.conf.source.include); - } - - // load the user-specified package file, if any - if (env.opts.package) { - packageJson = readPackageJson(env.opts.package); - } - - // source files named `package.json` or `README.md` get special treatment, unless the user - // explicitly specified a package and/or README file - for (let i = 0, l = sourceFiles.length; i < l; i++) { - sourceFile = sourceFiles[i]; - - if ( !env.opts.package && /\bpackage\.json$/i.test(sourceFile) ) { - packageJson = readPackageJson(sourceFile); - sourceFiles.splice(i--, 1); - } - - if ( !env.opts.readme && /(\bREADME|\.md)$/i.test(sourceFile) ) { - env.opts.readme = sourceFile; - sourceFiles.splice(i--, 1); - } - } - - // Resolve the path to the README. - if (env.opts.readme) { - env.opts.readme = path.resolve(env.opts.readme); - } - - props.packageJson = packageJson; - - return sourceFiles; - } - - // TODO: docs - cli.scanFiles = () => { - const { Filter } = require('jsdoc/src/filter'); - const { Scanner } = require('jsdoc/src/scanner'); - - let filter; - let scanner; - - env.opts._ = buildSourceList(); - - // are there any files to scan and parse? - if (env.conf.source && env.opts._.length) { - filter = new Filter(env.conf.source); - scanner = new Scanner(); - - env.sourceFiles = scanner.scan(env.opts._, - (env.opts.recurse ? env.conf.recurseDepth : undefined), filter); - } - - return cli; - }; - - cli.createParser = () => { - const handlers = require('jsdoc/src/handlers'); - const parser = require('jsdoc/src/parser'); - const plugins = require('jsdoc/plugins'); - - props.parser = parser.createParser(env.conf.parser, env.conf); - - if (env.conf.plugins) { - plugins.installPlugins(env.conf.plugins, props.parser); - } - - handlers.attachTo(props.parser); - - return cli; - }; - - cli.parseFiles = () => { - const augment = require('jsdoc/augment'); - const borrow = require('jsdoc/borrow'); - const Package = require('jsdoc/package').Package; - - let docs; - let packageDocs; - - props.docs = docs = props.parser.parse(env.sourceFiles, env.opts.encoding); - - // If there is no package.json, just create an empty package - packageDocs = new Package(props.packageJson); - packageDocs.files = env.sourceFiles || []; - docs.push(packageDocs); - - log.debug('Adding inherited symbols, mixins, and interface implementations...'); - augment.augmentAll(docs); - log.debug('Adding borrowed doclets...'); - borrow.resolveBorrows(docs); - log.debug('Post-processing complete.'); - - props.parser.fireProcessingComplete(docs); - - return cli; - }; - - cli.processParseResults = () => { - if (env.opts.explain) { - cli.dumpParseResults(); - - return Promise.resolve(); - } - else { - return cli.generateDocs(); - } - }; - - cli.dumpParseResults = () => { - console.log(JSON.stringify(props.docs, null, 4)); - - return cli; - }; - - cli.generateDocs = () => { - let message; - const taffy = require('taffydb').taffy; - - let template; - - env.opts.template = env.opts.template || path.join(__dirname, 'templates', 'default'); - - try { - // TODO: Just look for a `publish` function in the specified module, not a `publish.js` - // file _and_ a `publish` function. - template = require(`${env.opts.template}/publish`); - } - catch (e) { - log.fatal(`Unable to load template: ${e.message}` || e); - } - - // templates should include a publish.js file that exports a "publish" function - if (template.publish && typeof template.publish === 'function') { - let publishPromise; - - log.info('Generating output files...'); - publishPromise = template.publish( - taffy(props.docs), - env.opts - ); - - return Promise.resolve(publishPromise); - } - else { - message = `${env.opts.template} does not export a "publish" function. ` + - 'Global "publish" functions are no longer supported.'; - log.fatal(message); - - return Promise.reject(new Error(message)); - } - }; - - // TODO: docs - cli.exit = (exitCode, message) => { - if (exitCode > 0) { - props.shouldExitWithError = true; - - if (message) { - console.error(message); - } - } - - process.on('exit', () => { - if (props.shouldPrintHelp) { - cli.printHelp(); - } - - process.exit(exitCode); - }); - }; + engine.version = env.version.number; + engine.revision = revision; return cli; + }; + + // TODO: docs + cli.loadConfig = () => { + const _ = require('lodash'); + let conf; + + try { + env.opts = engine.parseFlags(env.args); + } catch (e) { + props.shouldPrintHelp = true; + cli.exit(1, `${e.message}\n`); + + return cli; + } + + try { + conf = config.loadSync(env.opts.configure); + env.conf = conf.config; + } catch (e) { + cli.exit(1, `Cannot parse the config file ${conf.filepath}: ${e}\n${FATAL_ERROR_MESSAGE}`); + + return cli; + } + + // look for options on the command line, then in the config + env.opts = _.defaults(env.opts, env.conf.opts); + + return cli; + }; + + // TODO: docs + cli.configureLogger = () => { + function recoverableError() { + props.shouldExitWithError = true; + } + + function fatalError() { + cli.exit(1); + } + + if (env.opts.test) { + engine.logLevel = LOG_LEVELS.SILENT; + } else { + if (env.opts.debug) { + engine.logLevel = LOG_LEVELS.DEBUG; + } else if (env.opts.verbose) { + engine.logLevel = LOG_LEVELS.INFO; + } + + if (env.opts.pedantic) { + bus.once('logger:warn', recoverableError); + bus.once('logger:error', fatalError); + } else { + bus.once('logger:error', recoverableError); + } + + bus.once('logger:fatal', fatalError); + } + + return cli; + }; + + // TODO: docs + cli.logStart = () => { + log.debug(engine.versionDetails); + log.debug('Environment info: %j', { + env: { + conf: env.conf, + opts: env.opts, + }, + }); + }; + + // TODO: docs + cli.logFinish = () => { + let delta; + let deltaSeconds; + + if (env.run.finish && env.run.start) { + delta = env.run.finish.getTime() - env.run.start.getTime(); + } + + if (delta !== undefined) { + deltaSeconds = (delta / 1000).toFixed(2); + log.info(`Finished running in ${deltaSeconds} seconds.`); + } + }; + + // TODO: docs + cli.runCommand = () => { + let cmd; + const opts = env.opts; + + // If we already need to exit with an error, don't do any more work. + if (props.shouldExitWithError) { + cmd = () => Promise.resolve(0); + } else if (opts.help) { + cmd = cli.printHelp; + } else if (opts.test) { + cmd = cli.runTests; + } else if (opts.version) { + cmd = cli.printVersion; + } else { + cmd = cli.main; + } + + return cmd().then((errorCode) => { + if (!errorCode && props.shouldExitWithError) { + errorCode = 1; + } + + cli.logFinish(); + cli.exit(errorCode || 0); + }); + }; + + // TODO: docs + cli.printHelp = () => { + cli.printVersion(); + console.log(engine.help({ maxLength: process.stdout.columns })); + + return Promise.resolve(0); + }; + + // TODO: docs + cli.runTests = () => require('./test')(); + + // TODO: docs + cli.printVersion = () => { + console.log(engine.versionDetails); + + return Promise.resolve(0); + }; + + // TODO: docs + cli.main = () => { + cli.scanFiles(); + + if (env.sourceFiles.length === 0) { + console.log('There are no input files to process.'); + + return Promise.resolve(0); + } else { + return cli + .createParser() + .parseFiles() + .processParseResults() + .then(() => { + env.run.finish = new Date(); + + return 0; + }); + } + }; + + function readPackageJson(filepath) { + const fs = require('fs'); + + try { + return stripJsonComments(fs.readFileSync(filepath, 'utf8')); + } catch (e) { + log.error(`Unable to read the package file ${filepath}`); + + return null; + } + } + + function buildSourceList() { + let packageJson; + let sourceFile; + let sourceFiles = env.opts._ ? env.opts._.slice(0) : []; + + if (env.conf.source && env.conf.source.include) { + sourceFiles = sourceFiles.concat(env.conf.source.include); + } + + // load the user-specified package file, if any + if (env.opts.package) { + packageJson = readPackageJson(env.opts.package); + } + + // source files named `package.json` or `README.md` get special treatment, unless the user + // explicitly specified a package and/or README file + for (let i = 0, l = sourceFiles.length; i < l; i++) { + sourceFile = sourceFiles[i]; + + if (!env.opts.package && /\bpackage\.json$/i.test(sourceFile)) { + packageJson = readPackageJson(sourceFile); + sourceFiles.splice(i--, 1); + } + + if (!env.opts.readme && /(\bREADME|\.md)$/i.test(sourceFile)) { + env.opts.readme = sourceFile; + sourceFiles.splice(i--, 1); + } + } + + // Resolve the path to the README. + if (env.opts.readme) { + env.opts.readme = path.resolve(env.opts.readme); + } + + props.packageJson = packageJson; + + return sourceFiles; + } + + // TODO: docs + cli.scanFiles = () => { + const { Filter } = require('jsdoc/src/filter'); + const { Scanner } = require('jsdoc/src/scanner'); + + let filter; + let scanner; + + env.opts._ = buildSourceList(); + + // are there any files to scan and parse? + if (env.conf.source && env.opts._.length) { + filter = new Filter(env.conf.source); + scanner = new Scanner(); + + env.sourceFiles = scanner.scan( + env.opts._, + env.opts.recurse ? env.conf.recurseDepth : undefined, + filter + ); + } + + return cli; + }; + + cli.createParser = () => { + const handlers = require('jsdoc/src/handlers'); + const parser = require('jsdoc/src/parser'); + const plugins = require('jsdoc/plugins'); + + props.parser = parser.createParser(env.conf.parser, env.conf); + + if (env.conf.plugins) { + plugins.installPlugins(env.conf.plugins, props.parser); + } + + handlers.attachTo(props.parser); + + return cli; + }; + + cli.parseFiles = () => { + const augment = require('jsdoc/augment'); + const borrow = require('jsdoc/borrow'); + const Package = require('jsdoc/package').Package; + + let docs; + let packageDocs; + + props.docs = docs = props.parser.parse(env.sourceFiles, env.opts.encoding); + + // If there is no package.json, just create an empty package + packageDocs = new Package(props.packageJson); + packageDocs.files = env.sourceFiles || []; + docs.push(packageDocs); + + log.debug('Adding inherited symbols, mixins, and interface implementations...'); + augment.augmentAll(docs); + log.debug('Adding borrowed doclets...'); + borrow.resolveBorrows(docs); + log.debug('Post-processing complete.'); + + props.parser.fireProcessingComplete(docs); + + return cli; + }; + + cli.processParseResults = () => { + if (env.opts.explain) { + cli.dumpParseResults(); + + return Promise.resolve(); + } else { + return cli.generateDocs(); + } + }; + + cli.dumpParseResults = () => { + console.log(JSON.stringify(props.docs, null, 4)); + + return cli; + }; + + cli.generateDocs = () => { + let message; + const taffy = require('taffydb').taffy; + + let template; + + env.opts.template = env.opts.template || path.join(__dirname, 'templates', 'default'); + + try { + // TODO: Just look for a `publish` function in the specified module, not a `publish.js` + // file _and_ a `publish` function. + template = require(`${env.opts.template}/publish`); + } catch (e) { + log.fatal(`Unable to load template: ${e.message}` || e); + } + + // templates should include a publish.js file that exports a "publish" function + if (template.publish && typeof template.publish === 'function') { + let publishPromise; + + log.info('Generating output files...'); + publishPromise = template.publish(taffy(props.docs), env.opts); + + return Promise.resolve(publishPromise); + } else { + message = + `${env.opts.template} does not export a "publish" function. ` + + 'Global "publish" functions are no longer supported.'; + log.fatal(message); + + return Promise.reject(new Error(message)); + } + }; + + // TODO: docs + cli.exit = (exitCode, message) => { + if (exitCode > 0) { + props.shouldExitWithError = true; + + if (message) { + console.error(message); + } + } + + process.on('exit', () => { + if (props.shouldPrintHelp) { + cli.printHelp(); + } + + process.exit(exitCode); + }); + }; + + return cli; })(); diff --git a/packages/jsdoc/jsdoc.js b/packages/jsdoc/jsdoc.js index d0cd7bb4..3c3cee26 100755 --- a/packages/jsdoc/jsdoc.js +++ b/packages/jsdoc/jsdoc.js @@ -2,34 +2,34 @@ // initialize the environment for Node.js (() => { - const fs = require('fs'); - const path = require('path'); + const fs = require('fs'); + const path = require('path'); - let env; - let jsdocPath = __dirname; + let env; + let jsdocPath = __dirname; - // Create a custom require method that adds `lib/jsdoc` and `node_modules` to the module - // lookup path. This makes it possible to `require('jsdoc/foo')` from external templates and - // plugins, and within JSDoc itself. It also allows external templates and plugins to - // require JSDoc's module dependencies without installing them locally. - /* eslint-disable no-global-assign, no-redeclare */ - require = require('requizzle')({ - requirePaths: { - before: [path.join(__dirname, 'lib')], - after: [path.join(__dirname, 'node_modules')] - }, - infect: true - }); - /* eslint-enable no-global-assign, no-redeclare */ + // Create a custom require method that adds `lib/jsdoc` and `node_modules` to the module + // lookup path. This makes it possible to `require('jsdoc/foo')` from external templates and + // plugins, and within JSDoc itself. It also allows external templates and plugins to + // require JSDoc's module dependencies without installing them locally. + /* eslint-disable no-global-assign, no-redeclare */ + require = require('requizzle')({ + requirePaths: { + before: [path.join(__dirname, 'lib')], + after: [path.join(__dirname, 'node_modules')], + }, + infect: true, + }); + /* eslint-enable no-global-assign, no-redeclare */ - // resolve the path if it's a symlink - if ( fs.statSync(jsdocPath).isSymbolicLink() ) { - jsdocPath = path.resolve( path.dirname(jsdocPath), fs.readlinkSync(jsdocPath) ); - } + // resolve the path if it's a symlink + if (fs.statSync(jsdocPath).isSymbolicLink()) { + jsdocPath = path.resolve(path.dirname(jsdocPath), fs.readlinkSync(jsdocPath)); + } - env = require('./lib/jsdoc/env'); - env.dirname = jsdocPath; - env.args = process.argv.slice(2); + env = require('./lib/jsdoc/env'); + env.dirname = jsdocPath; + env.args = process.argv.slice(2); })(); /** @@ -44,12 +44,9 @@ global.env = (() => require('./lib/jsdoc/env'))(); (async () => { - const cli = require('./cli'); + const cli = require('./cli'); - cli.setVersionInfo() - .loadConfig() - .configureLogger() - .logStart(); + cli.setVersionInfo().loadConfig().configureLogger().logStart(); - await cli.runCommand(); + await cli.runCommand(); })(); diff --git a/packages/jsdoc/lib/jsdoc/augment.js b/packages/jsdoc/lib/jsdoc/augment.js index daaa50f6..b03ec7b6 100644 --- a/packages/jsdoc/lib/jsdoc/augment.js +++ b/packages/jsdoc/lib/jsdoc/augment.js @@ -6,116 +6,116 @@ const _ = require('lodash'); const { fromParts, SCOPE, toParts } = require('@jsdoc/core').name; const jsdoc = { - doclet: require('jsdoc/doclet') + doclet: require('jsdoc/doclet'), }; const hasOwnProp = Object.prototype.hasOwnProperty; function mapDependencies(index, propertyName) { - const dependencies = {}; - let doc; - let doclets; - const kinds = ['class', 'external', 'interface', 'mixin']; - let len = 0; + const dependencies = {}; + let doc; + let doclets; + const kinds = ['class', 'external', 'interface', 'mixin']; + let len = 0; - Object.keys(index).forEach(indexName => { - doclets = index[indexName]; - for (let i = 0, ii = doclets.length; i < ii; i++) { - doc = doclets[i]; - if (kinds.includes(doc.kind)) { - dependencies[indexName] = {}; - if (hasOwnProp.call(doc, propertyName)) { - len = doc[propertyName].length; - for (let j = 0; j < len; j++) { - dependencies[indexName][doc[propertyName][j]] = true; - } - } - } + Object.keys(index).forEach((indexName) => { + doclets = index[indexName]; + for (let i = 0, ii = doclets.length; i < ii; i++) { + doc = doclets[i]; + if (kinds.includes(doc.kind)) { + dependencies[indexName] = {}; + if (hasOwnProp.call(doc, propertyName)) { + len = doc[propertyName].length; + for (let j = 0; j < len; j++) { + dependencies[indexName][doc[propertyName][j]] = true; + } } - }); + } + } + }); - return dependencies; + return dependencies; } class Sorter { - constructor(dependencies) { - this.dependencies = dependencies; - this.visited = {}; - this.sorted = []; - } + constructor(dependencies) { + this.dependencies = dependencies; + this.visited = {}; + this.sorted = []; + } - visit(key) { - if (!(key in this.visited)) { - this.visited[key] = true; + visit(key) { + if (!(key in this.visited)) { + this.visited[key] = true; - if (this.dependencies[key]) { - Object.keys(this.dependencies[key]).forEach(path => { - this.visit(path); - }); - } - - this.sorted.push(key); - } - } - - sort() { - Object.keys(this.dependencies).forEach(key => { - this.visit(key); + if (this.dependencies[key]) { + Object.keys(this.dependencies[key]).forEach((path) => { + this.visit(path); }); + } - return this.sorted; + this.sorted.push(key); } + } + + sort() { + Object.keys(this.dependencies).forEach((key) => { + this.visit(key); + }); + + return this.sorted; + } } function sort(dependencies) { - const sorter = new Sorter(dependencies); + const sorter = new Sorter(dependencies); - return sorter.sort(); + return sorter.sort(); } -function getMembers(longname, {index}, scopes) { - const memberof = index.memberof[longname] || []; - const members = []; +function getMembers(longname, { index }, scopes) { + const memberof = index.memberof[longname] || []; + const members = []; - memberof.forEach(candidate => { - if (scopes.includes(candidate.scope)) { - members.push(candidate); - } - }); + memberof.forEach((candidate) => { + if (scopes.includes(candidate.scope)) { + members.push(candidate); + } + }); - return members; + return members; } -function getDocumentedLongname(longname, {index}) { - const doclets = index.documented[longname] || []; +function getDocumentedLongname(longname, { index }) { + const doclets = index.documented[longname] || []; - return doclets[doclets.length - 1]; + return doclets[doclets.length - 1]; } function addDocletProperty(doclets, propName, value) { - for (let i = 0, l = doclets.length; i < l; i++) { - doclets[i][propName] = value; - } + for (let i = 0, l = doclets.length; i < l; i++) { + doclets[i][propName] = value; + } } -function reparentDoclet({longname}, child) { - const parts = toParts(child.longname); +function reparentDoclet({ longname }, child) { + const parts = toParts(child.longname); - parts.memberof = longname; - child.memberof = longname; - child.longname = fromParts(parts); + parts.memberof = longname; + child.memberof = longname; + child.longname = fromParts(parts); } -function parentIsClass({kind}) { - return kind === 'class'; +function parentIsClass({ kind }) { + return kind === 'class'; } function staticToInstance(doclet) { - const parts = toParts(doclet.longname); + const parts = toParts(doclet.longname); - parts.scope = SCOPE.PUNC.INSTANCE; - doclet.longname = fromParts(parts); - doclet.scope = SCOPE.NAMES.INSTANCE; + parts.scope = SCOPE.PUNC.INSTANCE; + doclet.longname = fromParts(parts); + doclet.scope = SCOPE.NAMES.INSTANCE; } /** @@ -137,15 +137,14 @@ function staticToInstance(doclet) { * @return {void} */ function updateAddedDoclets(doclet, additions, indexes) { - if (typeof indexes[doclet.longname] !== 'undefined') { - // replace the existing doclet - additions[indexes[doclet.longname]] = doclet; - } - else { - // add the doclet to the array, and track its index - additions.push(doclet); - indexes[doclet.longname] = additions.length - 1; - } + if (typeof indexes[doclet.longname] !== 'undefined') { + // replace the existing doclet + additions[indexes[doclet.longname]] = doclet; + } else { + // add the doclet to the array, and track its index + additions.push(doclet); + indexes[doclet.longname] = additions.length - 1; + } } /** @@ -158,11 +157,11 @@ function updateAddedDoclets(doclet, additions, indexes) { * @return {void} */ function updateDocumentedDoclets(doclet, documented) { - if ( !hasOwnProp.call(documented, doclet.longname) ) { - documented[doclet.longname] = []; - } + if (!hasOwnProp.call(documented, doclet.longname)) { + documented[doclet.longname] = []; + } - documented[doclet.longname].push(doclet); + documented[doclet.longname].push(doclet); } /** @@ -175,363 +174,360 @@ function updateDocumentedDoclets(doclet, documented) { * @return {void} */ function updateMemberofDoclets(doclet, memberof) { - if (doclet.memberof) { - if ( !hasOwnProp.call(memberof, doclet.memberof) ) { - memberof[doclet.memberof] = []; - } - - memberof[doclet.memberof].push(doclet); + if (doclet.memberof) { + if (!hasOwnProp.call(memberof, doclet.memberof)) { + memberof[doclet.memberof] = []; } + + memberof[doclet.memberof].push(doclet); + } } function explicitlyInherits(doclets) { - let doclet; - let inherits = false; + let doclet; + let inherits = false; - for (let i = 0, l = doclets.length; i < l; i++) { - doclet = doclets[i]; - if (typeof doclet.inheritdoc !== 'undefined' || typeof doclet.override !== 'undefined') { - inherits = true; - break; - } + for (let i = 0, l = doclets.length; i < l; i++) { + doclet = doclets[i]; + if (typeof doclet.inheritdoc !== 'undefined' || typeof doclet.override !== 'undefined') { + inherits = true; + break; } + } - return inherits; + return inherits; } function changeMemberof(longname, newMemberof) { - const atoms = toParts(longname); + const atoms = toParts(longname); - atoms.memberof = newMemberof; + atoms.memberof = newMemberof; - return fromParts(atoms); + return fromParts(atoms); } // TODO: try to reduce overlap with similar methods -function getInheritedAdditions(doclets, docs, {documented, memberof}) { - let additionIndexes; - const additions = []; - let childDoclet; - let childLongname; - let doc; - let parentDoclet; - let parentMembers; - let parents; - let member; - let parts; +function getInheritedAdditions(doclets, docs, { documented, memberof }) { + let additionIndexes; + const additions = []; + let childDoclet; + let childLongname; + let doc; + let parentDoclet; + let parentMembers; + let parents; + let member; + let parts; - // doclets will be undefined if the inherited symbol isn't documented - doclets = doclets || []; + // doclets will be undefined if the inherited symbol isn't documented + doclets = doclets || []; - for (let i = 0, ii = doclets.length; i < ii; i++) { - doc = doclets[i]; - parents = doc.augments; + for (let i = 0, ii = doclets.length; i < ii; i++) { + doc = doclets[i]; + parents = doc.augments; - if ( parents && (doc.kind === 'class' || doc.kind === 'interface') ) { - // reset the lookup table of added doclet indexes by longname - additionIndexes = {}; + if (parents && (doc.kind === 'class' || doc.kind === 'interface')) { + // reset the lookup table of added doclet indexes by longname + additionIndexes = {}; - for (let j = 0, jj = parents.length; j < jj; j++) { - parentMembers = getMembers(parents[j], docs, ['instance']); + for (let j = 0, jj = parents.length; j < jj; j++) { + parentMembers = getMembers(parents[j], docs, ['instance']); - for (let k = 0, kk = parentMembers.length; k < kk; k++) { - parentDoclet = parentMembers[k]; + for (let k = 0, kk = parentMembers.length; k < kk; k++) { + parentDoclet = parentMembers[k]; - // We only care about symbols that are documented. - if (parentDoclet.undocumented) { - continue; - } + // We only care about symbols that are documented. + if (parentDoclet.undocumented) { + continue; + } - childLongname = changeMemberof(parentDoclet.longname, doc.longname); - childDoclet = getDocumentedLongname(childLongname, docs) || {}; + childLongname = changeMemberof(parentDoclet.longname, doc.longname); + childDoclet = getDocumentedLongname(childLongname, docs) || {}; - // We don't want to fold in properties from the child doclet if it had an - // `@inheritdoc` tag. - if (hasOwnProp.call(childDoclet, 'inheritdoc')) { - childDoclet = {}; - } + // We don't want to fold in properties from the child doclet if it had an + // `@inheritdoc` tag. + if (hasOwnProp.call(childDoclet, 'inheritdoc')) { + childDoclet = {}; + } - member = jsdoc.doclet.combine(childDoclet, parentDoclet); + member = jsdoc.doclet.combine(childDoclet, parentDoclet); - if (!member.inherited) { - member.inherits = member.longname; - } - member.inherited = true; + if (!member.inherited) { + member.inherits = member.longname; + } + member.inherited = true; - member.memberof = doc.longname; - parts = toParts(member.longname); - parts.memberof = doc.longname; - member.longname = fromParts(parts); + member.memberof = doc.longname; + parts = toParts(member.longname); + parts.memberof = doc.longname; + member.longname = fromParts(parts); - // Indicate what the descendant is overriding. (We only care about the closest - // ancestor. For classes A > B > C, if B#a overrides A#a, and C#a inherits B#a, - // we don't want the doclet for C#a to say that it overrides A#a.) - if ( hasOwnProp.call(docs.index.longname, member.longname) ) { - member.overrides = parentDoclet.longname; - } - else { - delete member.overrides; - } + // Indicate what the descendant is overriding. (We only care about the closest + // ancestor. For classes A > B > C, if B#a overrides A#a, and C#a inherits B#a, + // we don't want the doclet for C#a to say that it overrides A#a.) + if (hasOwnProp.call(docs.index.longname, member.longname)) { + member.overrides = parentDoclet.longname; + } else { + delete member.overrides; + } - // Add the ancestor's docs unless the descendant overrides the ancestor AND - // documents the override. - if ( !hasOwnProp.call(documented, member.longname) ) { - updateAddedDoclets(member, additions, additionIndexes); - updateDocumentedDoclets(member, documented); - updateMemberofDoclets(member, memberof); - } - // If the descendant used an @inheritdoc or @override tag, add the ancestor's - // docs, and ignore the existing doclets. - else if ( explicitlyInherits(documented[member.longname]) ) { - // Ignore any existing doclets. (This is safe because we only get here if - // `member.longname` is an own property of `documented`.) - addDocletProperty(documented[member.longname], 'ignore', true); + // Add the ancestor's docs unless the descendant overrides the ancestor AND + // documents the override. + if (!hasOwnProp.call(documented, member.longname)) { + updateAddedDoclets(member, additions, additionIndexes); + updateDocumentedDoclets(member, documented); + updateMemberofDoclets(member, memberof); + } + // If the descendant used an @inheritdoc or @override tag, add the ancestor's + // docs, and ignore the existing doclets. + else if (explicitlyInherits(documented[member.longname])) { + // Ignore any existing doclets. (This is safe because we only get here if + // `member.longname` is an own property of `documented`.) + addDocletProperty(documented[member.longname], 'ignore', true); - updateAddedDoclets(member, additions, additionIndexes); - updateDocumentedDoclets(member, documented); - updateMemberofDoclets(member, memberof); + updateAddedDoclets(member, additions, additionIndexes); + updateDocumentedDoclets(member, documented); + updateMemberofDoclets(member, memberof); - // Remove property that's no longer accurate. - if (member.virtual) { - delete member.virtual; - } - // Remove properties that we no longer need. - if (member.inheritdoc) { - delete member.inheritdoc; - } - if (member.override) { - delete member.override; - } - } - // If the descendant overrides the ancestor and documents the override, - // update the doclets to indicate what the descendant is overriding. - else { - addDocletProperty(documented[member.longname], 'overrides', - parentDoclet.longname); - } - } + // Remove property that's no longer accurate. + if (member.virtual) { + delete member.virtual; } + // Remove properties that we no longer need. + if (member.inheritdoc) { + delete member.inheritdoc; + } + if (member.override) { + delete member.override; + } + } + // If the descendant overrides the ancestor and documents the override, + // update the doclets to indicate what the descendant is overriding. + else { + addDocletProperty(documented[member.longname], 'overrides', parentDoclet.longname); + } } + } } + } - return additions; + return additions; } function updateMixes(mixedDoclet, mixedLongname) { - let idx; - let mixedName; - let names; + let idx; + let mixedName; + let names; - // take the fast path if there's no array of mixed-in longnames - if (!mixedDoclet.mixes) { - mixedDoclet.mixes = [mixedLongname]; + // take the fast path if there's no array of mixed-in longnames + if (!mixedDoclet.mixes) { + mixedDoclet.mixes = [mixedLongname]; + } else { + // find the short name of the longname we're mixing in + mixedName = toParts(mixedLongname).name; + // find the short name of each previously mixed-in symbol + // TODO: why do we run a map if we always shorten the same value? this looks like a bug... + names = mixedDoclet.mixes.map(() => toParts(mixedDoclet.longname).name); + + // if we're mixing `myMethod` into `MixinC` from `MixinB`, and `MixinB` had the method mixed + // in from `MixinA`, don't show `MixinA.myMethod` in the `mixes` list + idx = names.indexOf(mixedName); + if (idx !== -1) { + mixedDoclet.mixes.splice(idx, 1); } - else { - // find the short name of the longname we're mixing in - mixedName = toParts(mixedLongname).name; - // find the short name of each previously mixed-in symbol - // TODO: why do we run a map if we always shorten the same value? this looks like a bug... - names = mixedDoclet.mixes.map(() => toParts(mixedDoclet.longname).name); - // if we're mixing `myMethod` into `MixinC` from `MixinB`, and `MixinB` had the method mixed - // in from `MixinA`, don't show `MixinA.myMethod` in the `mixes` list - idx = names.indexOf(mixedName); - if (idx !== -1) { - mixedDoclet.mixes.splice(idx, 1); - } - - mixedDoclet.mixes.push(mixedLongname); - } + mixedDoclet.mixes.push(mixedLongname); + } } // TODO: try to reduce overlap with similar methods -function getMixedInAdditions(mixinDoclets, allDoclets, {documented, memberof}) { - let additionIndexes; - const additions = []; - const commentedDoclets = documented; - let doclet; - let mixedDoclet; - let mixedDoclets; - let mixes; +function getMixedInAdditions(mixinDoclets, allDoclets, { documented, memberof }) { + let additionIndexes; + const additions = []; + const commentedDoclets = documented; + let doclet; + let mixedDoclet; + let mixedDoclets; + let mixes; - // mixinDoclets will be undefined if the mixed-in symbol isn't documented - mixinDoclets = mixinDoclets || []; + // mixinDoclets will be undefined if the mixed-in symbol isn't documented + mixinDoclets = mixinDoclets || []; - for (let i = 0, ii = mixinDoclets.length; i < ii; i++) { - doclet = mixinDoclets[i]; - mixes = doclet.mixes; + for (let i = 0, ii = mixinDoclets.length; i < ii; i++) { + doclet = mixinDoclets[i]; + mixes = doclet.mixes; - if (mixes) { - // reset the lookup table of added doclet indexes by longname - additionIndexes = {}; + if (mixes) { + // reset the lookup table of added doclet indexes by longname + additionIndexes = {}; - for (let j = 0, jj = mixes.length; j < jj; j++) { - mixedDoclets = getMembers(mixes[j], allDoclets, ['static']); + for (let j = 0, jj = mixes.length; j < jj; j++) { + mixedDoclets = getMembers(mixes[j], allDoclets, ['static']); - for (let k = 0, kk = mixedDoclets.length; k < kk; k++) { - // We only care about symbols that are documented. - if (mixedDoclets[k].undocumented) { - continue; - } + for (let k = 0, kk = mixedDoclets.length; k < kk; k++) { + // We only care about symbols that are documented. + if (mixedDoclets[k].undocumented) { + continue; + } - mixedDoclet = _.cloneDeep(mixedDoclets[k]); + mixedDoclet = _.cloneDeep(mixedDoclets[k]); - updateMixes(mixedDoclet, mixedDoclet.longname); - mixedDoclet.mixed = true; + updateMixes(mixedDoclet, mixedDoclet.longname); + mixedDoclet.mixed = true; - reparentDoclet(doclet, mixedDoclet); + reparentDoclet(doclet, mixedDoclet); - // if we're mixing into a class, treat the mixed-in symbol as an instance member - if (parentIsClass(doclet)) { - staticToInstance(mixedDoclet); - } + // if we're mixing into a class, treat the mixed-in symbol as an instance member + if (parentIsClass(doclet)) { + staticToInstance(mixedDoclet); + } - updateAddedDoclets(mixedDoclet, additions, additionIndexes); - updateDocumentedDoclets(mixedDoclet, commentedDoclets); - updateMemberofDoclets(mixedDoclet, memberof); - } - } + updateAddedDoclets(mixedDoclet, additions, additionIndexes); + updateDocumentedDoclets(mixedDoclet, commentedDoclets); + updateMemberofDoclets(mixedDoclet, memberof); } + } } + } - return additions; + return additions; } function updateImplements(implDoclets, implementedLongname) { - if ( !Array.isArray(implDoclets) ) { - implDoclets = [implDoclets]; + if (!Array.isArray(implDoclets)) { + implDoclets = [implDoclets]; + } + + implDoclets.forEach((implDoclet) => { + if (!hasOwnProp.call(implDoclet, 'implements')) { + implDoclet.implements = []; } - implDoclets.forEach(implDoclet => { - if ( !hasOwnProp.call(implDoclet, 'implements') ) { - implDoclet.implements = []; - } - - if (!implDoclet.implements.includes(implementedLongname)) { - implDoclet.implements.push(implementedLongname); - } - }); + if (!implDoclet.implements.includes(implementedLongname)) { + implDoclet.implements.push(implementedLongname); + } + }); } // TODO: try to reduce overlap with similar methods -function getImplementedAdditions(implDoclets, allDoclets, {documented, memberof}) { - let additionIndexes; - const additions = []; - let childDoclet; - let childLongname; - const commentedDoclets = documented; - let doclet; - let implementations; - let implExists; - let implementationDoclet; - let interfaceDoclets; - let parentDoclet; +function getImplementedAdditions(implDoclets, allDoclets, { documented, memberof }) { + let additionIndexes; + const additions = []; + let childDoclet; + let childLongname; + const commentedDoclets = documented; + let doclet; + let implementations; + let implExists; + let implementationDoclet; + let interfaceDoclets; + let parentDoclet; - // interfaceDoclets will be undefined if the implemented symbol isn't documented - implDoclets = implDoclets || []; + // interfaceDoclets will be undefined if the implemented symbol isn't documented + implDoclets = implDoclets || []; - for (let i = 0, ii = implDoclets.length; i < ii; i++) { - doclet = implDoclets[i]; - implementations = doclet.implements; + for (let i = 0, ii = implDoclets.length; i < ii; i++) { + doclet = implDoclets[i]; + implementations = doclet.implements; - if (implementations) { - // reset the lookup table of added doclet indexes by longname - additionIndexes = {}; + if (implementations) { + // reset the lookup table of added doclet indexes by longname + additionIndexes = {}; - for (let j = 0, jj = implementations.length; j < jj; j++) { - interfaceDoclets = getMembers(implementations[j], allDoclets, ['instance']); + for (let j = 0, jj = implementations.length; j < jj; j++) { + interfaceDoclets = getMembers(implementations[j], allDoclets, ['instance']); - for (let k = 0, kk = interfaceDoclets.length; k < kk; k++) { - parentDoclet = interfaceDoclets[k]; + for (let k = 0, kk = interfaceDoclets.length; k < kk; k++) { + parentDoclet = interfaceDoclets[k]; - // We only care about symbols that are documented. - if (parentDoclet.undocumented) { - continue; - } + // We only care about symbols that are documented. + if (parentDoclet.undocumented) { + continue; + } - childLongname = changeMemberof(parentDoclet.longname, doclet.longname); - childDoclet = getDocumentedLongname(childLongname, allDoclets) || {}; + childLongname = changeMemberof(parentDoclet.longname, doclet.longname); + childDoclet = getDocumentedLongname(childLongname, allDoclets) || {}; - // We don't want to fold in properties from the child doclet if it had an - // `@inheritdoc` tag. - if (hasOwnProp.call(childDoclet, 'inheritdoc')) { - childDoclet = {}; - } + // We don't want to fold in properties from the child doclet if it had an + // `@inheritdoc` tag. + if (hasOwnProp.call(childDoclet, 'inheritdoc')) { + childDoclet = {}; + } - implementationDoclet = jsdoc.doclet.combine(childDoclet, parentDoclet); + implementationDoclet = jsdoc.doclet.combine(childDoclet, parentDoclet); - reparentDoclet(doclet, implementationDoclet); - updateImplements(implementationDoclet, parentDoclet.longname); + reparentDoclet(doclet, implementationDoclet); + updateImplements(implementationDoclet, parentDoclet.longname); - // If there's no implementation, move along. - implExists = hasOwnProp.call(allDoclets.index.longname, - implementationDoclet.longname); - if (!implExists) { - continue; - } + // If there's no implementation, move along. + implExists = hasOwnProp.call(allDoclets.index.longname, implementationDoclet.longname); + if (!implExists) { + continue; + } - // Add the interface's docs unless the implementation is already documented. - if ( !hasOwnProp.call(commentedDoclets, implementationDoclet.longname) ) { - updateAddedDoclets(implementationDoclet, additions, additionIndexes); - updateDocumentedDoclets(implementationDoclet, commentedDoclets); - updateMemberofDoclets(implementationDoclet, memberof); - } - // If the implementation used an @inheritdoc or @override tag, add the - // interface's docs, and ignore the existing doclets. - else if ( explicitlyInherits(commentedDoclets[implementationDoclet.longname]) ) { - // Ignore any existing doclets. (This is safe because we only get here if - // `implementationDoclet.longname` is an own property of - // `commentedDoclets`.) - addDocletProperty(commentedDoclets[implementationDoclet.longname], 'ignore', - true); + // Add the interface's docs unless the implementation is already documented. + if (!hasOwnProp.call(commentedDoclets, implementationDoclet.longname)) { + updateAddedDoclets(implementationDoclet, additions, additionIndexes); + updateDocumentedDoclets(implementationDoclet, commentedDoclets); + updateMemberofDoclets(implementationDoclet, memberof); + } + // If the implementation used an @inheritdoc or @override tag, add the + // interface's docs, and ignore the existing doclets. + else if (explicitlyInherits(commentedDoclets[implementationDoclet.longname])) { + // Ignore any existing doclets. (This is safe because we only get here if + // `implementationDoclet.longname` is an own property of + // `commentedDoclets`.) + addDocletProperty(commentedDoclets[implementationDoclet.longname], 'ignore', true); - updateAddedDoclets(implementationDoclet, additions, additionIndexes); - updateDocumentedDoclets(implementationDoclet, commentedDoclets); - updateMemberofDoclets(implementationDoclet, memberof); + updateAddedDoclets(implementationDoclet, additions, additionIndexes); + updateDocumentedDoclets(implementationDoclet, commentedDoclets); + updateMemberofDoclets(implementationDoclet, memberof); - // Remove property that's no longer accurate. - if (implementationDoclet.virtual) { - delete implementationDoclet.virtual; - } - // Remove properties that we no longer need. - if (implementationDoclet.inheritdoc) { - delete implementationDoclet.inheritdoc; - } - if (implementationDoclet.override) { - delete implementationDoclet.override; - } - } - // If there's an implementation, and it's documented, update the doclets to - // indicate what the implementation is implementing. - else { - updateImplements(commentedDoclets[implementationDoclet.longname], - parentDoclet.longname); - } - } + // Remove property that's no longer accurate. + if (implementationDoclet.virtual) { + delete implementationDoclet.virtual; } + // Remove properties that we no longer need. + if (implementationDoclet.inheritdoc) { + delete implementationDoclet.inheritdoc; + } + if (implementationDoclet.override) { + delete implementationDoclet.override; + } + } + // If there's an implementation, and it's documented, update the doclets to + // indicate what the implementation is implementing. + else { + updateImplements( + commentedDoclets[implementationDoclet.longname], + parentDoclet.longname + ); + } } + } } + } - return additions; + return additions; } function augment(doclets, propertyName, docletFinder) { - const index = doclets.index.longname; - const dependencies = sort( mapDependencies(index, propertyName) ); + const index = doclets.index.longname; + const dependencies = sort(mapDependencies(index, propertyName)); - dependencies.forEach(depName => { - const additions = docletFinder(index[depName], doclets, doclets.index); + dependencies.forEach((depName) => { + const additions = docletFinder(index[depName], doclets, doclets.index); - additions.forEach(addition => { - const longname = addition.longname; + additions.forEach((addition) => { + const longname = addition.longname; - if ( !hasOwnProp.call(index, longname) ) { - index[longname] = []; - } - index[longname].push(addition); - doclets.push(addition); - }); + if (!hasOwnProp.call(index, longname)) { + index[longname] = []; + } + index[longname].push(addition); + doclets.push(addition); }); + }); } /** @@ -544,8 +540,8 @@ function augment(doclets, propertyName, docletFinder) { * @param {!Object} doclets.index - The doclet index. * @return {void} */ -exports.addInherited = doclets => { - augment(doclets, 'augments', getInheritedAdditions); +exports.addInherited = (doclets) => { + augment(doclets, 'augments', getInheritedAdditions); }; /** @@ -563,8 +559,8 @@ exports.addInherited = doclets => { * @param {!Object} doclets.index - The doclet index. * @return {void} */ -exports.addMixedIn = doclets => { - augment(doclets, 'mixes', getMixedInAdditions); +exports.addMixedIn = (doclets) => { + augment(doclets, 'mixes', getMixedInAdditions); }; /** @@ -584,8 +580,8 @@ exports.addMixedIn = doclets => { * @param {!Object} doclets.index - The doclet index. * @return {void} */ -exports.addImplemented = doclets => { - augment(doclets, 'implements', getImplementedAdditions); +exports.addImplemented = (doclets) => { + augment(doclets, 'implements', getImplementedAdditions); }; /** @@ -599,10 +595,10 @@ exports.addImplemented = doclets => { * * @return {void} */ -exports.augmentAll = doclets => { - exports.addMixedIn(doclets); - exports.addImplemented(doclets); - exports.addInherited(doclets); - // look for implemented doclets again, in case we inherited an interface - exports.addImplemented(doclets); +exports.augmentAll = (doclets) => { + exports.addMixedIn(doclets); + exports.addImplemented(doclets); + exports.addInherited(doclets); + // look for implemented doclets again, in case we inherited an interface + exports.addImplemented(doclets); }; diff --git a/packages/jsdoc/lib/jsdoc/borrow.js b/packages/jsdoc/lib/jsdoc/borrow.js index 9f6eb637..a2943356 100644 --- a/packages/jsdoc/lib/jsdoc/borrow.js +++ b/packages/jsdoc/lib/jsdoc/borrow.js @@ -5,35 +5,34 @@ const _ = require('lodash'); const { SCOPE } = require('@jsdoc/core').name; -function cloneBorrowedDoclets({borrowed, longname}, doclets) { - borrowed.forEach(({from, as}) => { - const borrowedDoclets = doclets.index.longname[from]; - let borrowedAs = as || from; - let parts; - let scopePunc; +function cloneBorrowedDoclets({ borrowed, longname }, doclets) { + borrowed.forEach(({ from, as }) => { + const borrowedDoclets = doclets.index.longname[from]; + let borrowedAs = as || from; + let parts; + let scopePunc; - if (borrowedDoclets) { - borrowedAs = borrowedAs.replace(/^prototype\./, SCOPE.PUNC.INSTANCE); - _.cloneDeep(borrowedDoclets).forEach(clone => { - // TODO: this will fail on longnames like '"Foo#bar".baz' - parts = borrowedAs.split(SCOPE.PUNC.INSTANCE); + if (borrowedDoclets) { + borrowedAs = borrowedAs.replace(/^prototype\./, SCOPE.PUNC.INSTANCE); + _.cloneDeep(borrowedDoclets).forEach((clone) => { + // TODO: this will fail on longnames like '"Foo#bar".baz' + parts = borrowedAs.split(SCOPE.PUNC.INSTANCE); - if (parts.length === 2) { - clone.scope = SCOPE.NAMES.INSTANCE; - scopePunc = SCOPE.PUNC.INSTANCE; - } - else { - clone.scope = SCOPE.NAMES.STATIC; - scopePunc = SCOPE.PUNC.STATIC; - } - - clone.name = parts.pop(); - clone.memberof = longname; - clone.longname = clone.memberof + scopePunc + clone.name; - doclets.push(clone); - }); + if (parts.length === 2) { + clone.scope = SCOPE.NAMES.INSTANCE; + scopePunc = SCOPE.PUNC.INSTANCE; + } else { + clone.scope = SCOPE.NAMES.STATIC; + scopePunc = SCOPE.PUNC.STATIC; } - }); + + clone.name = parts.pop(); + clone.memberof = longname; + clone.longname = clone.memberof + scopePunc + clone.name; + doclets.push(clone); + }); + } + }); } /** @@ -42,11 +41,11 @@ function cloneBorrowedDoclets({borrowed, longname}, doclets) { moving docs from the "borrowed" array and into the general docs, then deleting the "borrowed" array. */ -exports.resolveBorrows = doclets => { - for (let doclet of doclets.index.borrowed) { - cloneBorrowedDoclets(doclet, doclets); - delete doclet.borrowed; - } +exports.resolveBorrows = (doclets) => { + for (let doclet of doclets.index.borrowed) { + cloneBorrowedDoclets(doclet, doclets); + delete doclet.borrowed; + } - doclets.index.borrowed = []; + doclets.index.borrowed = []; }; diff --git a/packages/jsdoc/lib/jsdoc/doclet.js b/packages/jsdoc/lib/jsdoc/doclet.js index de4edf22..4b28f7a2 100644 --- a/packages/jsdoc/lib/jsdoc/doclet.js +++ b/packages/jsdoc/lib/jsdoc/doclet.js @@ -5,17 +5,17 @@ const _ = require('lodash'); let dictionary = require('jsdoc/tag/dictionary'); const { isFunction } = require('@jsdoc/parse').astNode; const { - applyNamespace, - hasLeadingScope, - hasTrailingScope, - LONGNAMES, - MODULE_NAMESPACE, - nameIsLongname, - prototypeToPunc, - PUNC_TO_SCOPE, - SCOPE, - SCOPE_TO_PUNC, - toParts + applyNamespace, + hasLeadingScope, + hasTrailingScope, + LONGNAMES, + MODULE_NAMESPACE, + nameIsLongname, + prototypeToPunc, + PUNC_TO_SCOPE, + SCOPE, + SCOPE_TO_PUNC, + toParts, } = require('@jsdoc/core').name; const helper = require('jsdoc/util/templateHelper'); const path = require('path'); @@ -26,71 +26,67 @@ const Tag = tag.Tag; const DEFAULT_SCOPE = SCOPE.NAMES.STATIC; function fakeMeta(node) { - return { - type: node ? node.type : null, - node: node - }; + return { + type: node ? node.type : null, + node: node, + }; } // use the meta info about the source code to guess what the doclet kind should be // TODO: set this elsewhere (maybe @jsdoc/parse.astNode.getInfo) function codeToKind(code) { - let kind = 'member'; - const node = code.node; + let kind = 'member'; + const node = code.node; - if (isFunction(code.type) && code.type !== Syntax.MethodDefinition) { - kind = 'function'; - } - else if (code.type === Syntax.MethodDefinition && node) { - if (node.kind === 'constructor') { - kind = 'class'; - } - else if (node.kind !== 'get' && node.kind !== 'set') { - kind = 'function'; - } - } - else if (code.type === Syntax.ClassDeclaration || code.type === Syntax.ClassExpression) { - kind = 'class'; - } - else if (code.type === Syntax.ExportAllDeclaration) { - // this value will often be an Identifier for a variable, which isn't very useful - kind = codeToKind(fakeMeta(node.source)); - } - else if (code.type === Syntax.ExportDefaultDeclaration || - code.type === Syntax.ExportNamedDeclaration) { - kind = codeToKind(fakeMeta(node.declaration)); - } - else if (code.type === Syntax.ExportSpecifier) { - // this value will often be an Identifier for a variable, which isn't very useful - kind = codeToKind(fakeMeta(node.local)); - } - else if (node && node.parent && isFunction(node.parent)) { - kind = 'param'; + if (isFunction(code.type) && code.type !== Syntax.MethodDefinition) { + kind = 'function'; + } else if (code.type === Syntax.MethodDefinition && node) { + if (node.kind === 'constructor') { + kind = 'class'; + } else if (node.kind !== 'get' && node.kind !== 'set') { + kind = 'function'; } + } else if (code.type === Syntax.ClassDeclaration || code.type === Syntax.ClassExpression) { + kind = 'class'; + } else if (code.type === Syntax.ExportAllDeclaration) { + // this value will often be an Identifier for a variable, which isn't very useful + kind = codeToKind(fakeMeta(node.source)); + } else if ( + code.type === Syntax.ExportDefaultDeclaration || + code.type === Syntax.ExportNamedDeclaration + ) { + kind = codeToKind(fakeMeta(node.declaration)); + } else if (code.type === Syntax.ExportSpecifier) { + // this value will often be an Identifier for a variable, which isn't very useful + kind = codeToKind(fakeMeta(node.local)); + } else if (node && node.parent && isFunction(node.parent)) { + kind = 'param'; + } - return kind; + return kind; } function unwrap(docletSrc) { - if (!docletSrc) { - return ''; - } + if (!docletSrc) { + return ''; + } - // note: keep trailing whitespace for @examples - // extra opening/closing stars are ignored - // left margin is considered a star and a space - // use the /m flag on regex to avoid having to guess what this platform's newline is - docletSrc = - // remove opening slash+stars - docletSrc.replace(/^\/\*\*+/, '') - // replace closing star slash with end-marker - .replace(/\**\*\/$/, '\\Z') - // remove left margin like: spaces+star or spaces+end-marker - .replace(/^\s*(\* ?|\\Z)/gm, '') - // remove end-marker - .replace(/\s*\\Z$/g, ''); + // note: keep trailing whitespace for @examples + // extra opening/closing stars are ignored + // left margin is considered a star and a space + // use the /m flag on regex to avoid having to guess what this platform's newline is + docletSrc = + // remove opening slash+stars + docletSrc + .replace(/^\/\*\*+/, '') + // replace closing star slash with end-marker + .replace(/\**\*\/$/, '\\Z') + // remove left margin like: spaces+star or spaces+end-marker + .replace(/^\s*(\* ?|\\Z)/gm, '') + // remove end-marker + .replace(/\s*\\Z$/g, ''); - return docletSrc; + return docletSrc; } /** @@ -98,51 +94,50 @@ function unwrap(docletSrc) { * @private */ function toTags(docletSrc) { - let parsedTag; - const tagData = []; - let tagText; - let tagTitle; + let parsedTag; + const tagData = []; + let tagText; + let tagTitle; - // split out the basic tags, keep surrounding whitespace - // like: @tagTitle tagBody - docletSrc - // replace splitter ats with an arbitrary sequence - .replace(/^(\s*)@(\S)/gm, '$1\\@$2') - // then split on that arbitrary sequence - .split('\\@') - .forEach($ => { - if ($) { - parsedTag = $.match(/^(\S+)(?:\s+(\S[\s\S]*))?/); + // split out the basic tags, keep surrounding whitespace + // like: @tagTitle tagBody + docletSrc + // replace splitter ats with an arbitrary sequence + .replace(/^(\s*)@(\S)/gm, '$1\\@$2') + // then split on that arbitrary sequence + .split('\\@') + .forEach(($) => { + if ($) { + parsedTag = $.match(/^(\S+)(?:\s+(\S[\s\S]*))?/); - if (parsedTag) { - tagTitle = parsedTag[1]; - tagText = parsedTag[2]; + if (parsedTag) { + tagTitle = parsedTag[1]; + tagText = parsedTag[2]; - if (tagTitle) { - tagData.push({ - title: tagTitle, - text: tagText - }); - } - } - } - }); + if (tagTitle) { + tagData.push({ + title: tagTitle, + text: tagText, + }); + } + } + } + }); - return tagData; + return tagData; } -function fixDescription(docletSrc, {code}) { - let isClass; +function fixDescription(docletSrc, { code }) { + let isClass; - if (!/^\s*@/.test(docletSrc) && docletSrc.replace(/\s/g, '').length) { - isClass = code && - (code.type === Syntax.ClassDeclaration || - code.type === Syntax.ClassExpression); + if (!/^\s*@/.test(docletSrc) && docletSrc.replace(/\s/g, '').length) { + isClass = + code && (code.type === Syntax.ClassDeclaration || code.type === Syntax.ClassExpression); - docletSrc = `${isClass ? '@classdesc' : '@description'} ${docletSrc}`; - } + docletSrc = `${isClass ? '@classdesc' : '@description'} ${docletSrc}`; + } - return docletSrc; + return docletSrc; } /** @@ -156,122 +151,119 @@ function fixDescription(docletSrc, {code}) { * @private */ function resolve(doclet) { - let about = {}; - let memberof = doclet.memberof || ''; - let metaName; - let name = doclet.name ? String(doclet.name) : ''; - let puncAndName; - let puncAndNameIndex; + let about = {}; + let memberof = doclet.memberof || ''; + let metaName; + let name = doclet.name ? String(doclet.name) : ''; + let puncAndName; + let puncAndNameIndex; - // Change `MyClass.prototype.instanceMethod` to `MyClass#instanceMethod` - // (but not in function params, which lack `doclet.kind`). - // TODO: Check for specific `doclet.kind` values (probably `function`, `class`, and `module`). - if (name && doclet.kind) { - name = prototypeToPunc(name); - } - doclet.name = name; + // Change `MyClass.prototype.instanceMethod` to `MyClass#instanceMethod` + // (but not in function params, which lack `doclet.kind`). + // TODO: Check for specific `doclet.kind` values (probably `function`, `class`, and `module`). + if (name && doclet.kind) { + name = prototypeToPunc(name); + } + doclet.name = name; - // Does the doclet have an alias that identifies the memberof? If so, use it - if (doclet.alias) { - about = toParts(name); - - if (about.memberof) { - memberof = about.memberof; - } - } - // Member of a var in an outer scope? - else if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) { - name = doclet.longname = doclet.meta.code.funcscope + SCOPE.PUNC.INNER + name; - } - - if (memberof || doclet.forceMemberof) { // @memberof tag given - memberof = prototypeToPunc(memberof); - - // The name is a complete longname, like `@name foo.bar` with `@memberof foo`. - if (name && nameIsLongname(name, memberof) && name !== memberof) { - about = toParts(name, (doclet.forceMemberof ? memberof : undefined)); - } - // The name and memberof are identical and refer to a module, like `@name module:foo` with - // `@memberof module:foo`. - else if (name && name === memberof && name.indexOf(MODULE_NAMESPACE) === 0) { - about = toParts(name, (doclet.forceMemberof ? memberof : undefined)); - } - // The name and memberof are identical, like `@name foo` with `@memberof foo`. - else if (name && name === memberof) { - doclet.scope = doclet.scope || DEFAULT_SCOPE; - name = memberof + SCOPE_TO_PUNC[doclet.scope] + name; - about = toParts(name, (doclet.forceMemberof ? memberof : undefined)); - } - // Like `@memberof foo#` or `@memberof foo~`. - else if (name && hasTrailingScope(memberof) ) { - about = toParts(memberof + name, (doclet.forceMemberof ? memberof : undefined)); - } - else if (name && doclet.scope) { - about = toParts(memberof + (SCOPE_TO_PUNC[doclet.scope] || '') + name, - (doclet.forceMemberof ? memberof : undefined)); - } - } else { - // No memberof. - about = toParts(name); - } - - if (about.name) { - doclet.name = about.name; - } + // Does the doclet have an alias that identifies the memberof? If so, use it + if (doclet.alias) { + about = toParts(name); if (about.memberof) { - doclet.setMemberof(about.memberof); + memberof = about.memberof; + } + } + // Member of a var in an outer scope? + else if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) { + name = doclet.longname = doclet.meta.code.funcscope + SCOPE.PUNC.INNER + name; + } + + if (memberof || doclet.forceMemberof) { + // @memberof tag given + memberof = prototypeToPunc(memberof); + + // The name is a complete longname, like `@name foo.bar` with `@memberof foo`. + if (name && nameIsLongname(name, memberof) && name !== memberof) { + about = toParts(name, doclet.forceMemberof ? memberof : undefined); + } + // The name and memberof are identical and refer to a module, like `@name module:foo` with + // `@memberof module:foo`. + else if (name && name === memberof && name.indexOf(MODULE_NAMESPACE) === 0) { + about = toParts(name, doclet.forceMemberof ? memberof : undefined); + } + // The name and memberof are identical, like `@name foo` with `@memberof foo`. + else if (name && name === memberof) { + doclet.scope = doclet.scope || DEFAULT_SCOPE; + name = memberof + SCOPE_TO_PUNC[doclet.scope] + name; + about = toParts(name, doclet.forceMemberof ? memberof : undefined); + } + // Like `@memberof foo#` or `@memberof foo~`. + else if (name && hasTrailingScope(memberof)) { + about = toParts(memberof + name, doclet.forceMemberof ? memberof : undefined); + } else if (name && doclet.scope) { + about = toParts( + memberof + (SCOPE_TO_PUNC[doclet.scope] || '') + name, + doclet.forceMemberof ? memberof : undefined + ); + } + } else { + // No memberof. + about = toParts(name); + } + + if (about.name) { + doclet.name = about.name; + } + + if (about.memberof) { + doclet.setMemberof(about.memberof); + } + + if (about.longname && (!doclet.longname || doclet.longname === doclet.name)) { + doclet.setLongname(about.longname); + } + + if (doclet.scope === SCOPE.NAMES.GLOBAL) { + // via @global tag? + doclet.setLongname(doclet.name); + delete doclet.memberof; + } else if (about.scope) { + if (about.memberof === LONGNAMES.GLOBAL) { + // via @memberof ? + doclet.scope = SCOPE.NAMES.GLOBAL; + } else { + doclet.scope = PUNC_TO_SCOPE[about.scope]; + } + } else if (doclet.name && doclet.memberof && !doclet.longname) { + if (hasLeadingScope(doclet.name)) { + doclet.scope = PUNC_TO_SCOPE[RegExp.$1]; + doclet.name = doclet.name.substr(1); + } else if (doclet.meta.code && doclet.meta.code.name) { + // HACK: Handle cases where an ES 2015 class is a static memberof something else, and + // the class has instance members. In these cases, we have to detect the instance + // members' scope by looking at the meta info. There's almost certainly a better way to + // do this... + metaName = String(doclet.meta.code.name); + puncAndName = SCOPE.PUNC.INSTANCE + doclet.name; + puncAndNameIndex = metaName.indexOf(puncAndName); + if (puncAndNameIndex !== -1 && puncAndNameIndex === metaName.length - puncAndName.length) { + doclet.scope = SCOPE.NAMES.INSTANCE; + } } - if (about.longname && (!doclet.longname || doclet.longname === doclet.name)) { - doclet.setLongname(about.longname); - } + doclet.scope = doclet.scope || DEFAULT_SCOPE; + doclet.setLongname(doclet.memberof + SCOPE_TO_PUNC[doclet.scope] + doclet.name); + } - if (doclet.scope === SCOPE.NAMES.GLOBAL) { // via @global tag? - doclet.setLongname(doclet.name); - delete doclet.memberof; - } - else if (about.scope) { - if (about.memberof === LONGNAMES.GLOBAL) { // via @memberof ? - doclet.scope = SCOPE.NAMES.GLOBAL; - } - else { - doclet.scope = PUNC_TO_SCOPE[about.scope]; - } - } - else if (doclet.name && doclet.memberof && !doclet.longname) { - if (hasLeadingScope(doclet.name)) { - doclet.scope = PUNC_TO_SCOPE[RegExp.$1]; - doclet.name = doclet.name.substr(1); - } - else if (doclet.meta.code && doclet.meta.code.name) { - // HACK: Handle cases where an ES 2015 class is a static memberof something else, and - // the class has instance members. In these cases, we have to detect the instance - // members' scope by looking at the meta info. There's almost certainly a better way to - // do this... - metaName = String(doclet.meta.code.name); - puncAndName = SCOPE.PUNC.INSTANCE + doclet.name; - puncAndNameIndex = metaName.indexOf(puncAndName); - if ( - puncAndNameIndex !== -1 && - (puncAndNameIndex === metaName.length - puncAndName.length) - ) { - doclet.scope = SCOPE.NAMES.INSTANCE; - } - } + if (about.variation) { + doclet.variation = about.variation; + } - doclet.scope = doclet.scope || DEFAULT_SCOPE; - doclet.setLongname(doclet.memberof + SCOPE_TO_PUNC[doclet.scope] + doclet.name); - } - - if (about.variation) { - doclet.variation = about.variation; - } - - // If we never found a longname, just use an empty string. - if (!doclet.longname) { - doclet.longname = ''; - } + // If we never found a longname, just use an empty string. + if (!doclet.longname) { + doclet.longname = ''; + } } /** @@ -283,15 +275,15 @@ function resolve(doclet) { * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. */ exports._replaceDictionary = function _replaceDictionary(dict) { - dictionary = dict; - tag._replaceDictionary(dict); - helper._replaceDictionary(dict); + dictionary = dict; + tag._replaceDictionary(dict); + helper._replaceDictionary(dict); }; function removeGlobal(longname) { - const globalRegexp = new RegExp(`^${LONGNAMES.GLOBAL}\\.?`); + const globalRegexp = new RegExp(`^${LONGNAMES.GLOBAL}\\.?`); - return longname.replace(globalRegexp, ''); + return longname.replace(globalRegexp, ''); } /** @@ -303,29 +295,29 @@ function removeGlobal(longname) { * available. */ function getFilepath(doclet) { - if (!doclet || !doclet.meta || !doclet.meta.filename) { - return ''; - } + if (!doclet || !doclet.meta || !doclet.meta.filename) { + return ''; + } - return path.join(doclet.meta.path || '', doclet.meta.filename); + return path.join(doclet.meta.path || '', doclet.meta.filename); } function clone(source, target, properties) { - properties.forEach(property => { - switch (typeof source[property]) { - case 'function': - // do nothing - break; + properties.forEach((property) => { + switch (typeof source[property]) { + case 'function': + // do nothing + break; - case 'object': - target[property] = _.cloneDeep(source[property]); + case 'object': + target[property] = _.cloneDeep(source[property]); - break; + break; - default: - target[property] = source[property]; - } - }); + default: + target[property] = source[property]; + } + }); } /** @@ -339,12 +331,14 @@ function clone(source, target, properties) { * @param {Array.} exclude - The names of properties to exclude from copying. */ function copyMostProperties(primary, secondary, target, exclude) { - const primaryProperties = _.difference(Object.getOwnPropertyNames(primary), exclude); - const secondaryProperties = _.difference(Object.getOwnPropertyNames(secondary), - exclude.concat(primaryProperties)); + const primaryProperties = _.difference(Object.getOwnPropertyNames(primary), exclude); + const secondaryProperties = _.difference( + Object.getOwnPropertyNames(secondary), + exclude.concat(primaryProperties) + ); - clone(primary, target, primaryProperties); - clone(secondary, target, secondaryProperties); + clone(primary, target, primaryProperties); + clone(secondary, target, secondaryProperties); } /** @@ -359,16 +353,21 @@ function copyMostProperties(primary, secondary, target, exclude) { * @param {Array.} include - The names of properties to copy. */ function copySpecificProperties(primary, secondary, target, include) { - include.forEach(property => { - if ({}.hasOwnProperty.call(primary, property) && primary[property] && - primary[property].length) { - target[property] = _.cloneDeep(primary[property]); - } - else if ({}.hasOwnProperty.call(secondary, property) && secondary[property] && - secondary[property].length) { - target[property] = _.cloneDeep(secondary[property]); - } - }); + include.forEach((property) => { + if ( + {}.hasOwnProperty.call(primary, property) && + primary[property] && + primary[property].length + ) { + target[property] = _.cloneDeep(primary[property]); + } else if ( + {}.hasOwnProperty.call(secondary, property) && + secondary[property] && + secondary[property].length + ) { + target[property] = _.cloneDeep(secondary[property]); + } + }); } /** @@ -377,275 +376,278 @@ function copySpecificProperties(primary, secondary, target, include) { * @alias module:jsdoc/doclet.Doclet */ class Doclet { - /** - * Create a doclet. - * - * @param {string} docletSrc - The raw source code of the jsdoc comment. - * @param {object=} meta - Properties describing the code related to this comment. - */ - constructor(docletSrc, meta = {}) { - let newTags = []; + /** + * Create a doclet. + * + * @param {string} docletSrc - The raw source code of the jsdoc comment. + * @param {object=} meta - Properties describing the code related to this comment. + */ + constructor(docletSrc, meta = {}) { + let newTags = []; - /** The original text of the comment from the source code. */ - this.comment = docletSrc; - this.setMeta(meta); + /** The original text of the comment from the source code. */ + this.comment = docletSrc; + this.setMeta(meta); - docletSrc = unwrap(docletSrc); - docletSrc = fixDescription(docletSrc, meta); + docletSrc = unwrap(docletSrc); + docletSrc = fixDescription(docletSrc, meta); - newTags = toTags.call(this, docletSrc); + newTags = toTags.call(this, docletSrc); - for (let i = 0, l = newTags.length; i < l; i++) { - this.addTag(newTags[i].title, newTags[i].text); - } - - this.postProcess(); + for (let i = 0, l = newTags.length; i < l; i++) { + this.addTag(newTags[i].title, newTags[i].text); } - // TODO: We call this method in the constructor _and_ in `jsdoc/src/handlers`. It appears that - // if we don't call the method twice, various doclet properties can be incorrect, including name - // and memberof. - /** Called once after all tags have been added. */ - postProcess() { - if (!this.preserveName) { - resolve(this); - } - if (this.name && !this.longname) { - this.setLongname(this.name); - } - if (this.memberof === '') { - delete this.memberof; - } + this.postProcess(); + } - if (!this.kind && this.meta && this.meta.code) { - this.addTag( 'kind', codeToKind(this.meta.code) ); - } + // TODO: We call this method in the constructor _and_ in `jsdoc/src/handlers`. It appears that + // if we don't call the method twice, various doclet properties can be incorrect, including name + // and memberof. + /** Called once after all tags have been added. */ + postProcess() { + if (!this.preserveName) { + resolve(this); + } + if (this.name && !this.longname) { + this.setLongname(this.name); + } + if (this.memberof === '') { + delete this.memberof; + } - if (this.variation && this.longname && !/\)$/.test(this.longname) ) { - this.longname += `(${this.variation})`; - } + if (!this.kind && this.meta && this.meta.code) { + this.addTag('kind', codeToKind(this.meta.code)); + } - // add in any missing param names - if (this.params && this.meta && this.meta.code && this.meta.code.paramnames) { - for (let i = 0, l = this.params.length; i < l; i++) { - if (!this.params[i].name) { - this.params[i].name = this.meta.code.paramnames[i] || ''; - } - } + if (this.variation && this.longname && !/\)$/.test(this.longname)) { + this.longname += `(${this.variation})`; + } + + // add in any missing param names + if (this.params && this.meta && this.meta.code && this.meta.code.paramnames) { + for (let i = 0, l = this.params.length; i < l; i++) { + if (!this.params[i].name) { + this.params[i].name = this.meta.code.paramnames[i] || ''; } + } + } + } + + /** + * Add a tag to the doclet. + * + * @param {string} title - The title of the tag being added. + * @param {string} [text] - The text of the tag being added. + */ + addTag(title, text) { + const tagDef = dictionary.lookUp(title); + const newTag = new Tag(title, text, this.meta); + + if (tagDef && tagDef.onTagged) { + tagDef.onTagged(this, newTag); + } + + if (!tagDef) { + this.tags = this.tags || []; + this.tags.push(newTag); + } + } + + /** + * Set the doclet's `memberof` property. + * + * @param {string} sid - The longname of the doclet's parent symbol. + */ + setMemberof(sid) { + /** + * The longname of the symbol that contains this one, if any. + * @type {string} + */ + this.memberof = removeGlobal(sid) + // TODO: Use `prototypeToPunc` instead? + .replace(/\.prototype/g, SCOPE.PUNC.INSTANCE); + } + + /** + * Set the doclet's `longname` property. + * + * @param {string} longname - The longname for the doclet. + */ + setLongname(longname) { + /** + * The fully resolved symbol name. + * @type {string} + */ + this.longname = removeGlobal(longname); + if (dictionary.isNamespace(this.kind)) { + this.longname = applyNamespace(this.longname, this.kind); + } + } + + /** + * Set the doclet's `scope` property. Must correspond to a scope name that is defined in + * {@link module:@jsdoc/core.name.SCOPE.NAMES}. + * + * @param {string} scope - The scope for the doclet relative to the symbol's parent. + * @throws {Error} If the scope name is not recognized. + */ + setScope(scope) { + let errorMessage; + let filepath; + const scopeNames = _.values(SCOPE.NAMES); + + if (!scopeNames.includes(scope)) { + filepath = getFilepath(this); + + errorMessage = + `The scope name "${scope}" is not recognized. Use one of the ` + + `following values: ${scopeNames}`; + if (filepath) { + errorMessage += ` (Source file: ${filepath})`; + } + + throw new Error(errorMessage); + } + + this.scope = scope; + } + + /** + * Add a symbol to this doclet's `borrowed` array. + * + * @param {string} source - The longname of the symbol that is the source. + * @param {string} target - The name the symbol is being assigned to. + */ + borrow(source, target) { + const about = { from: source }; + + if (target) { + about.as = target; + } + + if (!this.borrowed) { + /** + * A list of symbols that are borrowed by this one, if any. + * @type {Array.} + */ + this.borrowed = []; + } + this.borrowed.push(about); + } + + mix(source) { + /** + * A list of symbols that are mixed into this one, if any. + * @type Array. + */ + this.mixes = this.mixes || []; + this.mixes.push(source); + } + + /** + * Add a symbol to the doclet's `augments` array. + * + * @param {string} base - The longname of the base symbol. + */ + augment(base) { + /** + * A list of symbols that are augmented by this one, if any. + * @type Array. + */ + this.augments = this.augments || []; + this.augments.push(base); + } + + /** + * Set the `meta` property of this doclet. + * + * @param {object} meta + */ + setMeta(meta) { + let pathname; + + /** + * Information about the source code associated with this doclet. + * @namespace + */ + this.meta = this.meta || {}; + + if (meta.range) { + /** + * The positions of the first and last characters of the code associated with this doclet. + * @type Array. + */ + this.meta.range = meta.range.slice(0); + } + + if (meta.lineno) { + /** + * The name of the file containing the code associated with this doclet. + * @type string + */ + this.meta.filename = path.basename(meta.filename); + /** + * The line number of the code associated with this doclet. + * @type number + */ + this.meta.lineno = meta.lineno; + /** + * The column number of the code associated with this doclet. + * @type number + */ + this.meta.columnno = meta.columnno; + + pathname = path.dirname(meta.filename); + if (pathname && pathname !== '.') { + this.meta.path = pathname; + } } /** - * Add a tag to the doclet. - * - * @param {string} title - The title of the tag being added. - * @param {string} [text] - The text of the tag being added. + * Information about the code symbol. + * @namespace */ - addTag(title, text) { - const tagDef = dictionary.lookUp(title); - const newTag = new Tag(title, text, this.meta); - - if (tagDef && tagDef.onTagged) { - tagDef.onTagged(this, newTag); - } - - if (!tagDef) { - this.tags = this.tags || []; - this.tags.push(newTag); - } + this.meta.code = this.meta.code || {}; + if (meta.id) { + this.meta.code.id = meta.id; } - - /** - * Set the doclet's `memberof` property. - * - * @param {string} sid - The longname of the doclet's parent symbol. - */ - setMemberof(sid) { + if (meta.code) { + if (meta.code.name) { /** - * The longname of the symbol that contains this one, if any. + * The name of the symbol in the source code. * @type {string} */ - this.memberof = removeGlobal(sid) - // TODO: Use `prototypeToPunc` instead? - .replace(/\.prototype/g, SCOPE.PUNC.INSTANCE); - } - - /** - * Set the doclet's `longname` property. - * - * @param {string} longname - The longname for the doclet. - */ - setLongname(longname) { + this.meta.code.name = meta.code.name; + } + if (meta.code.type) { /** - * The fully resolved symbol name. + * The type of the symbol in the source code. * @type {string} */ - this.longname = removeGlobal(longname); - if (dictionary.isNamespace(this.kind)) { - this.longname = applyNamespace(this.longname, this.kind); - } - } - - /** - * Set the doclet's `scope` property. Must correspond to a scope name that is defined in - * {@link module:@jsdoc/core.name.SCOPE.NAMES}. - * - * @param {string} scope - The scope for the doclet relative to the symbol's parent. - * @throws {Error} If the scope name is not recognized. - */ - setScope(scope) { - let errorMessage; - let filepath; - const scopeNames = _.values(SCOPE.NAMES); - - if (!scopeNames.includes(scope)) { - filepath = getFilepath(this); - - errorMessage = `The scope name "${scope}" is not recognized. Use one of the ` + - `following values: ${scopeNames}`; - if (filepath) { - errorMessage += ` (Source file: ${filepath})`; - } - - throw new Error(errorMessage); - } - - this.scope = scope; - } - - /** - * Add a symbol to this doclet's `borrowed` array. - * - * @param {string} source - The longname of the symbol that is the source. - * @param {string} target - The name the symbol is being assigned to. - */ - borrow(source, target) { - const about = { from: source }; - - if (target) { - about.as = target; - } - - if (!this.borrowed) { - /** - * A list of symbols that are borrowed by this one, if any. - * @type {Array.} - */ - this.borrowed = []; - } - this.borrowed.push(about); - } - - mix(source) { + this.meta.code.type = meta.code.type; + } + if (meta.code.node) { + Object.defineProperty(this.meta.code, 'node', { + value: meta.code.node, + enumerable: false, + }); + } + if (meta.code.funcscope) { + this.meta.code.funcscope = meta.code.funcscope; + } + if (typeof meta.code.value !== 'undefined') { /** - * A list of symbols that are mixed into this one, if any. - * @type Array. + * The value of the symbol in the source code. + * @type {*} */ - this.mixes = this.mixes || []; - this.mixes.push(source); - } - - /** - * Add a symbol to the doclet's `augments` array. - * - * @param {string} base - The longname of the base symbol. - */ - augment(base) { - /** - * A list of symbols that are augmented by this one, if any. - * @type Array. - */ - this.augments = this.augments || []; - this.augments.push(base); - } - - /** - * Set the `meta` property of this doclet. - * - * @param {object} meta - */ - setMeta(meta) { - let pathname; - - /** - * Information about the source code associated with this doclet. - * @namespace - */ - this.meta = this.meta || {}; - - if (meta.range) { - /** - * The positions of the first and last characters of the code associated with this doclet. - * @type Array. - */ - this.meta.range = meta.range.slice(0); - } - - if (meta.lineno) { - /** - * The name of the file containing the code associated with this doclet. - * @type string - */ - this.meta.filename = path.basename(meta.filename); - /** - * The line number of the code associated with this doclet. - * @type number - */ - this.meta.lineno = meta.lineno; - /** - * The column number of the code associated with this doclet. - * @type number - */ - this.meta.columnno = meta.columnno; - - pathname = path.dirname(meta.filename); - if (pathname && pathname !== '.') { - this.meta.path = pathname; - } - } - - /** - * Information about the code symbol. - * @namespace - */ - this.meta.code = this.meta.code || {}; - if (meta.id) { this.meta.code.id = meta.id; } - if (meta.code) { - if (meta.code.name) { - /** - * The name of the symbol in the source code. - * @type {string} - */ - this.meta.code.name = meta.code.name; - } - if (meta.code.type) { - /** - * The type of the symbol in the source code. - * @type {string} - */ - this.meta.code.type = meta.code.type; - } - if (meta.code.node) { - Object.defineProperty(this.meta.code, 'node', { - value: meta.code.node, - enumerable: false - }); - } - if (meta.code.funcscope) { - this.meta.code.funcscope = meta.code.funcscope; - } - if (typeof meta.code.value !== 'undefined') { - /** - * The value of the symbol in the source code. - * @type {*} - */ - this.meta.code.value = meta.code.value; - } - if (meta.code.paramnames) { - this.meta.code.paramnames = meta.code.paramnames.slice(0); - } - } + this.meta.code.value = meta.code.value; + } + if (meta.code.paramnames) { + this.meta.code.paramnames = meta.code.paramnames.slice(0); + } } + } } exports.Doclet = Doclet; @@ -659,22 +661,15 @@ exports.Doclet = Doclet; * doclets. */ exports.combine = (primary, secondary) => { - const copyMostPropertiesExclude = [ - 'params', - 'properties', - 'undocumented' - ]; - const copySpecificPropertiesInclude = [ - 'params', - 'properties' - ]; - const target = new Doclet(''); + const copyMostPropertiesExclude = ['params', 'properties', 'undocumented']; + const copySpecificPropertiesInclude = ['params', 'properties']; + const target = new Doclet(''); - // First, copy most properties to the target doclet. - copyMostProperties(primary, secondary, target, copyMostPropertiesExclude); - // Then copy a few specific properties to the target doclet, as long as they're not falsy and - // have a length greater than 0. - copySpecificProperties(primary, secondary, target, copySpecificPropertiesInclude); + // First, copy most properties to the target doclet. + copyMostProperties(primary, secondary, target, copyMostPropertiesExclude); + // Then copy a few specific properties to the target doclet, as long as they're not falsy and + // have a length greater than 0. + copySpecificProperties(primary, secondary, target, copySpecificPropertiesInclude); - return target; + return target; }; diff --git a/packages/jsdoc/lib/jsdoc/env.js b/packages/jsdoc/lib/jsdoc/env.js index b228c306..5df4b79f 100644 --- a/packages/jsdoc/lib/jsdoc/env.js +++ b/packages/jsdoc/lib/jsdoc/env.js @@ -5,73 +5,73 @@ * @module jsdoc/env */ module.exports = { - /** - * The times at which JSDoc started and finished. - * - * @type {Object} - * @property {Date} start - The time at which JSDoc started running. - * @property {Date} finish - The time at which JSDoc finished running. - */ - run: { - start: new Date(), - finish: null - }, + /** + * The times at which JSDoc started and finished. + * + * @type {Object} + * @property {Date} start - The time at which JSDoc started running. + * @property {Date} finish - The time at which JSDoc finished running. + */ + run: { + start: new Date(), + finish: null, + }, - /** - * The command-line arguments passed to JSDoc. - * - * @type {Array<*>} - */ - args: [], + /** + * The command-line arguments passed to JSDoc. + * + * @type {Array<*>} + */ + args: [], - /** - * The data parsed from JSDoc's configuration file. - * - * @type Object - */ - conf: {}, + /** + * The data parsed from JSDoc's configuration file. + * + * @type Object + */ + conf: {}, - /** - * The absolute path to the base directory in which JSDoc is located. Set at startup. - * - * @private - * @type {string} - */ - dirname: null, + /** + * The absolute path to the base directory in which JSDoc is located. Set at startup. + * + * @private + * @type {string} + */ + dirname: null, - /** - * The user's working directory at the time when JSDoc started running. - * - * @private - * @type {string} - */ - pwd: null, + /** + * The user's working directory at the time when JSDoc started running. + * + * @private + * @type {string} + */ + pwd: null, - /** - * The command-line arguments, parsed into a key/value hash. - * - * @type {Object} - * @example if (global.env.opts.help) { console.log('Helpful message.'); } - */ - opts: {}, + /** + * The command-line arguments, parsed into a key/value hash. + * + * @type {Object} + * @example if (global.env.opts.help) { console.log('Helpful message.'); } + */ + opts: {}, - /** - * The source files that JSDoc will parse. - * - * @type {Array} - * @memberof env - */ - sourceFiles: [], + /** + * The source files that JSDoc will parse. + * + * @type {Array} + * @memberof env + */ + sourceFiles: [], - /** - * The JSDoc version number and revision date. - * - * @type {Object} - * @property {string} number - The JSDoc version number. - * @property {string} revision - The JSDoc revision number, expressed as a UTC date string. - */ - version: { - number: null, - revision: null - } + /** + * The JSDoc version number and revision date. + * + * @type {Object} + * @property {string} number - The JSDoc version number. + * @property {string} revision - The JSDoc revision number, expressed as a UTC date string. + */ + version: { + number: null, + revision: null, + }, }; diff --git a/packages/jsdoc/lib/jsdoc/package.js b/packages/jsdoc/lib/jsdoc/package.js index fb3e8da3..64f9770c 100644 --- a/packages/jsdoc/lib/jsdoc/package.js +++ b/packages/jsdoc/lib/jsdoc/package.js @@ -10,13 +10,13 @@ const stripBom = require('strip-bom'); // Collect all of the license information from a `package.json` file. function getLicenses(packageInfo) { - const licenses = packageInfo.licenses ? packageInfo.licenses.slice(0) : []; + const licenses = packageInfo.licenses ? packageInfo.licenses.slice(0) : []; - if (packageInfo.license) { - licenses.push({ type: packageInfo.license }); - } + if (packageInfo.license) { + licenses.push({ type: packageInfo.license }); + } - return licenses; + return licenses; } /** @@ -63,195 +63,194 @@ function getLicenses(packageInfo) { * object may not use the format documented here. */ class Package { + /** + * @param {string} json - The contents of the `package.json` file. + */ + constructor(json) { + let packageInfo; + /** - * @param {string} json - The contents of the `package.json` file. + * The string identifier that is shared by all `Package` objects. + * + * @readonly + * @default + * @type {string} */ - constructor(json) { - let packageInfo; + this.kind = 'package'; - /** - * The string identifier that is shared by all `Package` objects. - * - * @readonly - * @default - * @type {string} - */ - this.kind = 'package'; - - try { - packageInfo = JSON.parse(json ? stripBom(json) : '{}'); - } - catch (e) { - log.error(`Unable to parse the package file: ${e.message}`); - packageInfo = {}; - } - - if (packageInfo.name) { - /** - * The package name. - * - * @type {string} - */ - this.name = packageInfo.name; - } - - /** - * The unique longname for this `Package` object. - * - * @type {string} - */ - this.longname = `${this.kind}:${this.name}`; - - if (packageInfo.author) { - /** - * The author of this package. Contains either a - * {@link module:jsdoc/package.Package~PersonInfo PersonInfo} object or a string with - * information about the author. - * - * @type {(module:jsdoc/package.Package~PersonInfo|string)} - * @since 3.3.0 - */ - this.author = packageInfo.author; - } - - if (packageInfo.bugs) { - /** - * Information about where to report bugs in the project. May contain a URL, a string, or an - * object with more detailed information. - * - * @type {(string|module:jsdoc/package.Package~BugInfo)} - * @since 3.3.0 - */ - this.bugs = packageInfo.bugs; - } - - if (packageInfo.contributors) { - /** - * The contributors to this package. - * - * @type {Array.<(module:jsdoc/package.Package~PersonInfo|string)>} - * @since 3.3.0 - */ - this.contributors = packageInfo.contributors; - } - - if (packageInfo.dependencies) { - /** - * The dependencies for this package. - * - * @type {Object} - * @since 3.3.0 - */ - this.dependencies = packageInfo.dependencies; - } - - if (packageInfo.description) { - /** - * A brief description of the package. - * - * @type {string} - */ - this.description = packageInfo.description; - } - - if (packageInfo.devDependencies) { - /** - * The development dependencies for this package. - * - * @type {Object} - * @since 3.3.0 - */ - this.devDependencies = packageInfo.devDependencies; - } - - if (packageInfo.engines) { - /** - * The JavaScript engines that this package supports. Each key is a string that identifies - * the engine (for example, `node`). Each value is a - * [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number for the - * engine. - * - * @type {Object} - * @since 3.3.0 - */ - this.engines = packageInfo.engines; - } - - /** - * The source files associated with the package. - * - * New `Package` objects always contain an empty array, regardless of whether the `package.json` - * file includes a `files` property. - * - * After JSDoc parses your input files, it sets this property to a list of paths to your input - * files. - * - * @type {Array.} - */ - this.files = []; - - if (packageInfo.homepage) { - /** - * The URL for the package's homepage. - * - * @type {string} - * @since 3.3.0 - */ - this.homepage = packageInfo.homepage; - } - - if (packageInfo.keywords) { - /** - * Keywords to help users find the package. - * - * @type {Array.} - * @since 3.3.0 - */ - this.keywords = packageInfo.keywords; - } - - if (packageInfo.license || packageInfo.licenses) { - /** - * The licenses used by this package. Combines information from the `package.json` file's - * `license` property and the deprecated `licenses` property. - * - * @type {Array.} - */ - this.licenses = getLicenses(packageInfo); - } - - if (packageInfo.main) { - /** - * The module ID that provides the primary entry point to the package. For example, if your - * package is a CommonJS module, and the value of this property is `foo`, users should be - * able to load your module with `require('foo')`. - * - * @type {string} - * @since 3.3.0 - */ - this.main = packageInfo.main; - } - - if (packageInfo.repository) { - /** - * The version-control repository for the package. - * - * @type {module:jsdoc/package.Package~RepositoryInfo} - * @since 3.3.0 - */ - this.repository = packageInfo.repository; - } - - if (packageInfo.version) { - /** - * The [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number of the - * package. - * - * @type {string} - * @since 3.2.0 - */ - this.version = packageInfo.version; - } + try { + packageInfo = JSON.parse(json ? stripBom(json) : '{}'); + } catch (e) { + log.error(`Unable to parse the package file: ${e.message}`); + packageInfo = {}; } + + if (packageInfo.name) { + /** + * The package name. + * + * @type {string} + */ + this.name = packageInfo.name; + } + + /** + * The unique longname for this `Package` object. + * + * @type {string} + */ + this.longname = `${this.kind}:${this.name}`; + + if (packageInfo.author) { + /** + * The author of this package. Contains either a + * {@link module:jsdoc/package.Package~PersonInfo PersonInfo} object or a string with + * information about the author. + * + * @type {(module:jsdoc/package.Package~PersonInfo|string)} + * @since 3.3.0 + */ + this.author = packageInfo.author; + } + + if (packageInfo.bugs) { + /** + * Information about where to report bugs in the project. May contain a URL, a string, or an + * object with more detailed information. + * + * @type {(string|module:jsdoc/package.Package~BugInfo)} + * @since 3.3.0 + */ + this.bugs = packageInfo.bugs; + } + + if (packageInfo.contributors) { + /** + * The contributors to this package. + * + * @type {Array.<(module:jsdoc/package.Package~PersonInfo|string)>} + * @since 3.3.0 + */ + this.contributors = packageInfo.contributors; + } + + if (packageInfo.dependencies) { + /** + * The dependencies for this package. + * + * @type {Object} + * @since 3.3.0 + */ + this.dependencies = packageInfo.dependencies; + } + + if (packageInfo.description) { + /** + * A brief description of the package. + * + * @type {string} + */ + this.description = packageInfo.description; + } + + if (packageInfo.devDependencies) { + /** + * The development dependencies for this package. + * + * @type {Object} + * @since 3.3.0 + */ + this.devDependencies = packageInfo.devDependencies; + } + + if (packageInfo.engines) { + /** + * The JavaScript engines that this package supports. Each key is a string that identifies + * the engine (for example, `node`). Each value is a + * [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number for the + * engine. + * + * @type {Object} + * @since 3.3.0 + */ + this.engines = packageInfo.engines; + } + + /** + * The source files associated with the package. + * + * New `Package` objects always contain an empty array, regardless of whether the `package.json` + * file includes a `files` property. + * + * After JSDoc parses your input files, it sets this property to a list of paths to your input + * files. + * + * @type {Array.} + */ + this.files = []; + + if (packageInfo.homepage) { + /** + * The URL for the package's homepage. + * + * @type {string} + * @since 3.3.0 + */ + this.homepage = packageInfo.homepage; + } + + if (packageInfo.keywords) { + /** + * Keywords to help users find the package. + * + * @type {Array.} + * @since 3.3.0 + */ + this.keywords = packageInfo.keywords; + } + + if (packageInfo.license || packageInfo.licenses) { + /** + * The licenses used by this package. Combines information from the `package.json` file's + * `license` property and the deprecated `licenses` property. + * + * @type {Array.} + */ + this.licenses = getLicenses(packageInfo); + } + + if (packageInfo.main) { + /** + * The module ID that provides the primary entry point to the package. For example, if your + * package is a CommonJS module, and the value of this property is `foo`, users should be + * able to load your module with `require('foo')`. + * + * @type {string} + * @since 3.3.0 + */ + this.main = packageInfo.main; + } + + if (packageInfo.repository) { + /** + * The version-control repository for the package. + * + * @type {module:jsdoc/package.Package~RepositoryInfo} + * @since 3.3.0 + */ + this.repository = packageInfo.repository; + } + + if (packageInfo.version) { + /** + * The [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number of the + * package. + * + * @type {string} + * @since 3.2.0 + */ + this.version = packageInfo.version; + } + } } exports.Package = Package; diff --git a/packages/jsdoc/lib/jsdoc/plugins.js b/packages/jsdoc/lib/jsdoc/plugins.js index d1c45111..693c0662 100644 --- a/packages/jsdoc/lib/jsdoc/plugins.js +++ b/packages/jsdoc/lib/jsdoc/plugins.js @@ -5,31 +5,31 @@ const dictionary = require('jsdoc/tag/dictionary'); function addHandlers(handlers, parser) { - Object.keys(handlers).forEach(eventName => { - parser.on(eventName, handlers[eventName]); - }); + Object.keys(handlers).forEach((eventName) => { + parser.on(eventName, handlers[eventName]); + }); } exports.installPlugins = (plugins, parser) => { - let plugin; + let plugin; - for (let pluginModule of plugins) { - plugin = require(pluginModule); + for (let pluginModule of plugins) { + plugin = require(pluginModule); - // allow user-defined plugins to... - // ...register event handlers - if (plugin.handlers) { - addHandlers(plugin.handlers, parser); - } - - // ...define tags - if (plugin.defineTags) { - plugin.defineTags(dictionary); - } - - // ...add an ESTree node visitor - if (plugin.astNodeVisitor) { - parser.addAstNodeVisitor(plugin.astNodeVisitor); - } + // allow user-defined plugins to... + // ...register event handlers + if (plugin.handlers) { + addHandlers(plugin.handlers, parser); } + + // ...define tags + if (plugin.defineTags) { + plugin.defineTags(dictionary); + } + + // ...add an ESTree node visitor + if (plugin.astNodeVisitor) { + parser.addAstNodeVisitor(plugin.astNodeVisitor); + } + } }; diff --git a/packages/jsdoc/lib/jsdoc/schema.js b/packages/jsdoc/lib/jsdoc/schema.js index d4fc246b..4cdc9846 100644 --- a/packages/jsdoc/lib/jsdoc/schema.js +++ b/packages/jsdoc/lib/jsdoc/schema.js @@ -18,639 +18,630 @@ const EVENT_REGEXP = 'event:[\\S]+'; const PACKAGE_REGEXP = 'package:[\\S]+'; const STRING_SCHEMA = { - type: STRING + type: STRING, }; // information about the code associated with a doclet -const META_SCHEMA = exports.META_SCHEMA = { - type: OBJECT, - additionalProperties: false, - properties: { - code: { - type: OBJECT, - additionalProperties: false, - properties: { - funcscope: { - type: STRING - }, - id: { - type: STRING - }, - name: {}, - node: { - type: OBJECT - }, - paramnames: { - type: ARRAY, - uniqueItems: true, - items: { - type: STRING - } - }, - type: { - type: STRING - }, - value: {} - } +const META_SCHEMA = (exports.META_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + code: { + type: OBJECT, + additionalProperties: false, + properties: { + funcscope: { + type: STRING, }, - columnno: { - title: 'The column number of the code associated with this doclet.', - type: NUMBER + id: { + type: STRING, }, - filename: { - title: 'The name of the file that contains the code associated with this doclet.', - type: STRING + name: {}, + node: { + type: OBJECT, }, - lineno: { - title: 'The line number of the code associated with this doclet.', - type: NUMBER + paramnames: { + type: ARRAY, + uniqueItems: true, + items: { + type: STRING, + }, }, - path: { - title: 'The path in which the code associated with this doclet is located.', - type: STRING + type: { + type: STRING, }, - range: { - title: 'The positions of the first and last characters of the code associated with ' + - 'this doclet.', - type: ARRAY, - minItems: 2, - maxItems: 2, - items: { - type: NUMBER - } - }, - vars: { - type: OBJECT - } - } -}; + value: {}, + }, + }, + columnno: { + title: 'The column number of the code associated with this doclet.', + type: NUMBER, + }, + filename: { + title: 'The name of the file that contains the code associated with this doclet.', + type: STRING, + }, + lineno: { + title: 'The line number of the code associated with this doclet.', + type: NUMBER, + }, + path: { + title: 'The path in which the code associated with this doclet is located.', + type: STRING, + }, + range: { + title: + 'The positions of the first and last characters of the code associated with ' + + 'this doclet.', + type: ARRAY, + minItems: 2, + maxItems: 2, + items: { + type: NUMBER, + }, + }, + vars: { + type: OBJECT, + }, + }, +}); // type property containing type names -const TYPE_PROPERTY_SCHEMA = exports.TYPE_PROPERTY_SCHEMA = { - type: OBJECT, - additionalProperties: false, - properties: { - names: { - type: ARRAY, - minItems: 1, - items: { - type: STRING - } - }, - // type parser output - parsedType: { - type: OBJECT, - additionalProperties: true - } - } -}; +const TYPE_PROPERTY_SCHEMA = (exports.TYPE_PROPERTY_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + names: { + type: ARRAY, + minItems: 1, + items: { + type: STRING, + }, + }, + // type parser output + parsedType: { + type: OBJECT, + additionalProperties: true, + }, + }, +}); // enumeration properties -const ENUM_PROPERTY_SCHEMA = exports.ENUM_PROPERTY_SCHEMA = { - type: OBJECT, - additionalProperties: false, - properties: { - comment: { - type: STRING - }, - defaultvalue: {}, - description: { - type: STRING_OPTIONAL - }, - kind: { - type: STRING, - enum: ['member'] - }, - longname: { - type: STRING - }, - memberof: { - type: STRING - }, - meta: META_SCHEMA, - name: { - type: STRING - }, - // is this member nullable? (derived from the type expression) - nullable: { - type: BOOLEAN_OPTIONAL - }, - // is this member optional? (derived from the type expression) - optional: { - type: BOOLEAN_OPTIONAL - }, - scope: { - type: STRING, - enum: ['static'] - }, - type: TYPE_PROPERTY_SCHEMA, - // can this member be provided more than once? (derived from the type expression) - variable: { - type: BOOLEAN_OPTIONAL - } - } -}; +const ENUM_PROPERTY_SCHEMA = (exports.ENUM_PROPERTY_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + comment: { + type: STRING, + }, + defaultvalue: {}, + description: { + type: STRING_OPTIONAL, + }, + kind: { + type: STRING, + enum: ['member'], + }, + longname: { + type: STRING, + }, + memberof: { + type: STRING, + }, + meta: META_SCHEMA, + name: { + type: STRING, + }, + // is this member nullable? (derived from the type expression) + nullable: { + type: BOOLEAN_OPTIONAL, + }, + // is this member optional? (derived from the type expression) + optional: { + type: BOOLEAN_OPTIONAL, + }, + scope: { + type: STRING, + enum: ['static'], + }, + type: TYPE_PROPERTY_SCHEMA, + // can this member be provided more than once? (derived from the type expression) + variable: { + type: BOOLEAN_OPTIONAL, + }, + }, +}); // function parameter, or object property defined with @property tag -const PARAM_SCHEMA = exports.PARAM_SCHEMA = { - type: OBJECT, - additionalProperties: false, - properties: { - // what is the default value for this parameter? - defaultvalue: {}, - // a description of the parameter - description: { - type: STRING_OPTIONAL - }, - // what name does this parameter have within the function? - name: { - type: STRING - }, - // can the value for this parameter be null? - nullable: { - type: BOOLEAN_OPTIONAL - }, - // is a value for this parameter optional? - optional: { - type: BOOLEAN_OPTIONAL - }, - // what are the types of value expected for this parameter? - type: TYPE_PROPERTY_SCHEMA, - // can this parameter be repeated? - variable: { - type: BOOLEAN_OPTIONAL - } - } -}; +const PARAM_SCHEMA = (exports.PARAM_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + // what is the default value for this parameter? + defaultvalue: {}, + // a description of the parameter + description: { + type: STRING_OPTIONAL, + }, + // what name does this parameter have within the function? + name: { + type: STRING, + }, + // can the value for this parameter be null? + nullable: { + type: BOOLEAN_OPTIONAL, + }, + // is a value for this parameter optional? + optional: { + type: BOOLEAN_OPTIONAL, + }, + // what are the types of value expected for this parameter? + type: TYPE_PROPERTY_SCHEMA, + // can this parameter be repeated? + variable: { + type: BOOLEAN_OPTIONAL, + }, + }, +}); -const DOCLET_SCHEMA = exports.DOCLET_SCHEMA = { - type: OBJECT, - additionalProperties: false, - properties: { - // what access privileges are allowed - access: { - type: STRING, - enum: [ - 'package', - 'private', - 'protected', - 'public' - ] - }, - alias: { - type: STRING - }, - async: { - type: BOOLEAN - }, - augments: { - type: ARRAY, - uniqueItems: true, - items: { - type: STRING - } - }, - author: { - type: ARRAY, - items: { - type: STRING - } - }, - borrowed: { - type: ARRAY, - uniqueItems: true, - items: { - type: OBJECT, - additionalProperties: false, - properties: { - // name of the target - as: { - type: STRING - }, - // name of the source - from: { - type: STRING - } - } - } - }, - // a description of the class that this constructor belongs to - classdesc: { - type: STRING - }, - comment: { - type: STRING - }, - copyright: { - type: STRING - }, - defaultvalue: {}, - defaultvaluetype: { - type: STRING, - enum: [OBJECT, ARRAY] - }, - // is usage of this symbol deprecated? - deprecated: { - type: [STRING, BOOLEAN] - }, - // a description - description: { - type: STRING_OPTIONAL - }, - // something else to consider - examples: { - type: ARRAY, - items: { - type: STRING - } - }, - exceptions: { - type: ARRAY, - items: PARAM_SCHEMA - }, - // the path to another constructor - extends: { - type: ARRAY, - uniqueItems: true, - items: { - type: STRING - } - }, - // the path to another doc object - fires: { - type: ARRAY, - uniqueItems: true, - items: { - type: STRING, - pattern: EVENT_REGEXP - } - }, - forceMemberof: { - type: BOOLEAN_OPTIONAL - }, - generator: { - type: BOOLEAN - }, - hideconstructor: { - type: BOOLEAN - }, - ignore: { - type: BOOLEAN - }, - implementations: { - type: ARRAY, - items: { - type: STRING - } - }, - implements: { - type: ARRAY, - items: { - type: STRING - } - }, - inheritdoc: { - type: STRING - }, - inherited: { - type: BOOLEAN - }, - inherits: { - type: STRING, - dependency: { - inherited: true - } - }, - isEnum: { - type: BOOLEAN - }, - // what kind of symbol is this? - kind: { - type: STRING, - enum: [ - 'class', - 'constant', - 'event', - 'external', - 'file', - 'function', - 'interface', - 'member', - 'mixin', - 'module', - 'namespace', - 'package', - 'param', - 'typedef' - ] - }, - license: { - type: STRING - }, - listens: { - type: ARRAY, - uniqueItems: true, - items: { - type: STRING, - pattern: EVENT_REGEXP - } - }, - longname: { - type: STRING - }, - // probably a leading substring of the path - memberof: { - type: STRING - }, - // information about this doc - meta: META_SCHEMA, - // was this doclet mixed in? - mixed: { - type: BOOLEAN - }, - mixes: { - type: ARRAY, - uniqueItems: true, - items: { - type: STRING - } - }, - modifies: { - type: ARRAY, - uniqueItems: true, - items: PARAM_SCHEMA - }, - // probably a trailing substring of the path - name: { - type: STRING - }, - // is this member nullable? (derived from the type expression) - nullable: { - type: BOOLEAN_OPTIONAL - }, - // is this member optional? (derived from the type expression) - optional: { - type: BOOLEAN_OPTIONAL - }, - // does this member explicitly override the parent? - override: { - type: BOOLEAN - }, - overrides: { - type: STRING - }, - // are there function parameters associated with this doc? - params: { - type: ARRAY, - uniqueItems: true, - items: PARAM_SCHEMA - }, - preserveName: { - type: BOOLEAN - }, +const DOCLET_SCHEMA = (exports.DOCLET_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + // what access privileges are allowed + access: { + type: STRING, + enum: ['package', 'private', 'protected', 'public'], + }, + alias: { + type: STRING, + }, + async: { + type: BOOLEAN, + }, + augments: { + type: ARRAY, + uniqueItems: true, + items: { + type: STRING, + }, + }, + author: { + type: ARRAY, + items: { + type: STRING, + }, + }, + borrowed: { + type: ARRAY, + uniqueItems: true, + items: { + type: OBJECT, + additionalProperties: false, properties: { - type: ARRAY, - uniqueItems: true, - minItems: 1, - items: { - anyOf: [ENUM_PROPERTY_SCHEMA, PARAM_SCHEMA] - } - }, - readonly: { - type: BOOLEAN - }, - // the symbol being documented requires another symbol - requires: { - type: ARRAY, - uniqueItems: true, - minItems: 1, - items: { - type: STRING - } - }, - returns: { - type: ARRAY, - minItems: 1, - items: PARAM_SCHEMA - }, - // what sort of parent scope does this symbol have? - scope: { + // name of the target + as: { type: STRING, - enum: [ - 'global', - 'inner', - 'instance', - 'static' - ] + }, + // name of the source + from: { + type: STRING, + }, }, - // something else to consider - see: { - type: ARRAY, - minItems: 1, - items: { - type: STRING - } - }, - // at what previous version was this doc added? - since: { - type: STRING - }, - summary: { - type: STRING - }, - // arbitrary tags associated with this doc - tags: { - type: ARRAY, - minItems: 1, - items: { - type: OBJECT, - additionalProperties: false, - properties: { - originalTitle: { - type: STRING - }, - text: { - type: STRING - }, - title: { - type: STRING - }, - value: { - oneOf: [STRING_SCHEMA, PARAM_SCHEMA] - } - } - } - }, - 'this': { - type: STRING - }, - todo: { - type: ARRAY, - minItems: 1, - items: { - type: STRING - } - }, - // what type is the value that this doc is associated with, like `number` - type: TYPE_PROPERTY_SCHEMA, - undocumented: { - type: BOOLEAN - }, - // can this member be provided more than once? (derived from the type expression) - variable: { - type: BOOLEAN_OPTIONAL - }, - variation: { - type: STRING - }, - // what is the version of this doc - version: { - type: STRING - }, - // is a member left to be implemented during inheritance? - virtual: { - type: BOOLEAN - }, - yields: { - type: ARRAY, - minItems: 1, - items: PARAM_SCHEMA - } - } -}; - -const CONTACT_INFO_SCHEMA = exports.CONTACT_INFO_SCHEMA = { - type: OBJECT, - additionalProperties: false, + }, + }, + // a description of the class that this constructor belongs to + classdesc: { + type: STRING, + }, + comment: { + type: STRING, + }, + copyright: { + type: STRING, + }, + defaultvalue: {}, + defaultvaluetype: { + type: STRING, + enum: [OBJECT, ARRAY], + }, + // is usage of this symbol deprecated? + deprecated: { + type: [STRING, BOOLEAN], + }, + // a description + description: { + type: STRING_OPTIONAL, + }, + // something else to consider + examples: { + type: ARRAY, + items: { + type: STRING, + }, + }, + exceptions: { + type: ARRAY, + items: PARAM_SCHEMA, + }, + // the path to another constructor + extends: { + type: ARRAY, + uniqueItems: true, + items: { + type: STRING, + }, + }, + // the path to another doc object + fires: { + type: ARRAY, + uniqueItems: true, + items: { + type: STRING, + pattern: EVENT_REGEXP, + }, + }, + forceMemberof: { + type: BOOLEAN_OPTIONAL, + }, + generator: { + type: BOOLEAN, + }, + hideconstructor: { + type: BOOLEAN, + }, + ignore: { + type: BOOLEAN, + }, + implementations: { + type: ARRAY, + items: { + type: STRING, + }, + }, + implements: { + type: ARRAY, + items: { + type: STRING, + }, + }, + inheritdoc: { + type: STRING, + }, + inherited: { + type: BOOLEAN, + }, + inherits: { + type: STRING, + dependency: { + inherited: true, + }, + }, + isEnum: { + type: BOOLEAN, + }, + // what kind of symbol is this? + kind: { + type: STRING, + enum: [ + 'class', + 'constant', + 'event', + 'external', + 'file', + 'function', + 'interface', + 'member', + 'mixin', + 'module', + 'namespace', + 'package', + 'param', + 'typedef', + ], + }, + license: { + type: STRING, + }, + listens: { + type: ARRAY, + uniqueItems: true, + items: { + type: STRING, + pattern: EVENT_REGEXP, + }, + }, + longname: { + type: STRING, + }, + // probably a leading substring of the path + memberof: { + type: STRING, + }, + // information about this doc + meta: META_SCHEMA, + // was this doclet mixed in? + mixed: { + type: BOOLEAN, + }, + mixes: { + type: ARRAY, + uniqueItems: true, + items: { + type: STRING, + }, + }, + modifies: { + type: ARRAY, + uniqueItems: true, + items: PARAM_SCHEMA, + }, + // probably a trailing substring of the path + name: { + type: STRING, + }, + // is this member nullable? (derived from the type expression) + nullable: { + type: BOOLEAN_OPTIONAL, + }, + // is this member optional? (derived from the type expression) + optional: { + type: BOOLEAN_OPTIONAL, + }, + // does this member explicitly override the parent? + override: { + type: BOOLEAN, + }, + overrides: { + type: STRING, + }, + // are there function parameters associated with this doc? + params: { + type: ARRAY, + uniqueItems: true, + items: PARAM_SCHEMA, + }, + preserveName: { + type: BOOLEAN, + }, properties: { - email: { - type: STRING + type: ARRAY, + uniqueItems: true, + minItems: 1, + items: { + anyOf: [ENUM_PROPERTY_SCHEMA, PARAM_SCHEMA], + }, + }, + readonly: { + type: BOOLEAN, + }, + // the symbol being documented requires another symbol + requires: { + type: ARRAY, + uniqueItems: true, + minItems: 1, + items: { + type: STRING, + }, + }, + returns: { + type: ARRAY, + minItems: 1, + items: PARAM_SCHEMA, + }, + // what sort of parent scope does this symbol have? + scope: { + type: STRING, + enum: ['global', 'inner', 'instance', 'static'], + }, + // something else to consider + see: { + type: ARRAY, + minItems: 1, + items: { + type: STRING, + }, + }, + // at what previous version was this doc added? + since: { + type: STRING, + }, + summary: { + type: STRING, + }, + // arbitrary tags associated with this doc + tags: { + type: ARRAY, + minItems: 1, + items: { + type: OBJECT, + additionalProperties: false, + properties: { + originalTitle: { + type: STRING, + }, + text: { + type: STRING, + }, + title: { + type: STRING, + }, + value: { + oneOf: [STRING_SCHEMA, PARAM_SCHEMA], + }, }, - name: { - type: STRING + }, + }, + this: { + type: STRING, + }, + todo: { + type: ARRAY, + minItems: 1, + items: { + type: STRING, + }, + }, + // what type is the value that this doc is associated with, like `number` + type: TYPE_PROPERTY_SCHEMA, + undocumented: { + type: BOOLEAN, + }, + // can this member be provided more than once? (derived from the type expression) + variable: { + type: BOOLEAN_OPTIONAL, + }, + variation: { + type: STRING, + }, + // what is the version of this doc + version: { + type: STRING, + }, + // is a member left to be implemented during inheritance? + virtual: { + type: BOOLEAN, + }, + yields: { + type: ARRAY, + minItems: 1, + items: PARAM_SCHEMA, + }, + }, +}); + +const CONTACT_INFO_SCHEMA = (exports.CONTACT_INFO_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + email: { + type: STRING, + }, + name: { + type: STRING, + }, + url: { + type: STRING, + format: 'uri', + }, + }, +}); + +const BUGS_SCHEMA = (exports.BUGS_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + email: { + type: STRING, + }, + url: { + type: STRING, + format: 'uri', + }, + }, +}); + +const PACKAGE_SCHEMA = (exports.PACKAGE_SCHEMA = { + type: OBJECT, + additionalProperties: false, + properties: { + author: { + anyOf: [STRING_SCHEMA, CONTACT_INFO_SCHEMA], + }, + bugs: { + anyOf: [STRING_SCHEMA, BUGS_SCHEMA], + }, + contributors: { + type: ARRAY, + minItems: 0, + items: { + anyOf: [STRING_SCHEMA, CONTACT_INFO_SCHEMA], + }, + }, + dependencies: { + type: OBJECT, + }, + description: { + type: STRING, + }, + devDependencies: { + type: OBJECT, + }, + engines: { + type: OBJECT, + }, + files: { + type: ARRAY, + uniqueItems: true, + minItems: 0, + items: { + type: STRING, + }, + }, + homepage: { + type: STRING, + format: 'uri', + }, + keywords: { + type: ARRAY, + minItems: 0, + items: { + type: STRING, + }, + }, + kind: { + type: STRING, + enum: ['package'], + }, + licenses: { + type: ARRAY, + minItems: 1, + items: { + type: OBJECT, + additionalProperties: false, + properties: { + type: { + type: STRING, + }, + url: { + type: STRING, + format: 'uri', + }, }, + }, + }, + longname: { + type: STRING, + pattern: PACKAGE_REGEXP, + }, + main: { + type: STRING, + }, + name: { + type: STRING, + }, + repository: { + type: OBJECT, + additionalProperties: false, + properties: { + type: { + type: STRING, + }, + // we don't use `format: 'uri'` here because repo URLs are atypical url: { - type: STRING, - format: 'uri' - } - } -}; - -const BUGS_SCHEMA = exports.BUGS_SCHEMA = { - type: OBJECT, - additionalProperties: false, - properties: { - email: { - type: STRING + type: STRING, }, - url: { - type: STRING, - format: 'uri' - } - } -}; - -const PACKAGE_SCHEMA = exports.PACKAGE_SCHEMA = { - type: OBJECT, - additionalProperties: false, - properties: { - author: { - anyOf: [STRING_SCHEMA, CONTACT_INFO_SCHEMA] - }, - bugs: { - anyOf: [STRING_SCHEMA, BUGS_SCHEMA] - }, - contributors: { - type: ARRAY, - minItems: 0, - items: { - anyOf: [STRING_SCHEMA, CONTACT_INFO_SCHEMA] - } - }, - dependencies: { - type: OBJECT - }, - description: { - type: STRING - }, - devDependencies: { - type: OBJECT - }, - engines: { - type: OBJECT - }, - files: { - type: ARRAY, - uniqueItems: true, - minItems: 0, - items: { - type: STRING - } - }, - homepage: { - type: STRING, - format: 'uri' - }, - keywords: { - type: ARRAY, - minItems: 0, - items: { - type: STRING - } - }, - kind: { - type: STRING, - enum: ['package'] - }, - licenses: { - type: ARRAY, - minItems: 1, - items: { - type: OBJECT, - additionalProperties: false, - properties: { - type: { - type: STRING - }, - url: { - type: STRING, - format: 'uri' - } - } - } - }, - longname: { - type: STRING, - pattern: PACKAGE_REGEXP - }, - main: { - type: STRING - }, - name: { - type: STRING - }, - repository: { - type: OBJECT, - additionalProperties: false, - properties: { - type: { - type: STRING - }, - // we don't use `format: 'uri'` here because repo URLs are atypical - url: { - type: STRING - } - } - }, - version: { - type: STRING - } - } -}; + }, + }, + version: { + type: STRING, + }, + }, +}); exports.DOCLETS_SCHEMA = { - type: ARRAY, - items: { - anyOf: [DOCLET_SCHEMA, PACKAGE_SCHEMA] - } + type: ARRAY, + items: { + anyOf: [DOCLET_SCHEMA, PACKAGE_SCHEMA], + }, }; diff --git a/packages/jsdoc/lib/jsdoc/src/filter.js b/packages/jsdoc/lib/jsdoc/src/filter.js index 4507e00e..f071eb70 100644 --- a/packages/jsdoc/lib/jsdoc/src/filter.js +++ b/packages/jsdoc/lib/jsdoc/src/filter.js @@ -4,60 +4,59 @@ const path = require('path'); function makeRegExp(config) { - let regExp = null; + let regExp = null; - if (config) { - regExp = (typeof config === 'string') ? new RegExp(config) : config; - } + if (config) { + regExp = typeof config === 'string' ? new RegExp(config) : config; + } - return regExp; + return regExp; } /** * @alias module:jsdoc/src/filter.Filter */ class Filter { - /** - * @param {Object} opts - * @param {string[]} opts.exclude - Specific files to exclude. - * @param {(string|RegExp)} opts.includePattern - * @param {(string|RegExp)} opts.excludePattern - */ - constructor({exclude, includePattern, excludePattern}) { - this._cwd = process.cwd(); - this.exclude = exclude && Array.isArray(exclude) ? - exclude.map($ => path.resolve(this._cwd, $)) : - null; - this.includePattern = makeRegExp(includePattern); - this.excludePattern = makeRegExp(excludePattern); + /** + * @param {Object} opts + * @param {string[]} opts.exclude - Specific files to exclude. + * @param {(string|RegExp)} opts.includePattern + * @param {(string|RegExp)} opts.excludePattern + */ + constructor({ exclude, includePattern, excludePattern }) { + this._cwd = process.cwd(); + this.exclude = + exclude && Array.isArray(exclude) ? exclude.map(($) => path.resolve(this._cwd, $)) : null; + this.includePattern = makeRegExp(includePattern); + this.excludePattern = makeRegExp(excludePattern); + } + + /** + * @param {string} filepath - The filepath to check. + * @returns {boolean} Should the given file be included? + */ + isIncluded(filepath) { + let included = true; + + filepath = path.resolve(this._cwd, filepath); + + if (this.includePattern && !this.includePattern.test(filepath)) { + included = false; } - /** - * @param {string} filepath - The filepath to check. - * @returns {boolean} Should the given file be included? - */ - isIncluded(filepath) { - let included = true; - - filepath = path.resolve(this._cwd, filepath); - - if ( this.includePattern && !this.includePattern.test(filepath) ) { - included = false; - } - - if ( this.excludePattern && this.excludePattern.test(filepath) ) { - included = false; - } - - if (this.exclude) { - this.exclude.forEach(exclude => { - if ( filepath.indexOf(exclude) === 0 ) { - included = false; - } - }); - } - - return included; + if (this.excludePattern && this.excludePattern.test(filepath)) { + included = false; } + + if (this.exclude) { + this.exclude.forEach((exclude) => { + if (filepath.indexOf(exclude) === 0) { + included = false; + } + }); + } + + return included; + } } exports.Filter = Filter; diff --git a/packages/jsdoc/lib/jsdoc/src/handlers.js b/packages/jsdoc/lib/jsdoc/src/handlers.js index d597a4d3..ce0567e1 100644 --- a/packages/jsdoc/lib/jsdoc/src/handlers.js +++ b/packages/jsdoc/lib/jsdoc/src/handlers.js @@ -10,37 +10,36 @@ const { Syntax } = require('@jsdoc/parse'); let currentModule = null; class CurrentModule { - constructor(doclet) { - this.doclet = doclet; - this.longname = doclet.longname; - this.originalName = doclet.meta.code.name || ''; - } + constructor(doclet) { + this.doclet = doclet; + this.longname = doclet.longname; + this.originalName = doclet.meta.code.name || ''; + } } -function filterByLongname({longname}) { - // you can't document prototypes - if ( /#$/.test(longname) ) { - return true; - } +function filterByLongname({ longname }) { + // you can't document prototypes + if (/#$/.test(longname)) { + return true; + } - return false; + return false; } function createDoclet(comment, e) { - let doclet; - let flatComment; - let msg; + let doclet; + let flatComment; + let msg; - try { - doclet = new Doclet(comment, e); - } - catch (error) { - flatComment = comment.replace(/[\r\n]/g, ''); - msg = `cannot create a doclet for the comment "${flatComment}": ${error.message}`; - log.error(msg); - doclet = new Doclet('', e); - } + try { + doclet = new Doclet(comment, e); + } catch (error) { + flatComment = comment.replace(/[\r\n]/g, ''); + msg = `cannot create a doclet for the comment "${flatComment}": ${error.message}`; + log.error(msg); + doclet = new Doclet('', e); + } - return doclet; + return doclet; } /** @@ -63,301 +62,301 @@ function createDoclet(comment, e) { * @private */ function createSymbolDoclet(comment, e) { - let doclet = createDoclet(comment, e); + let doclet = createDoclet(comment, e); - if (doclet.name) { - // try again, without the comment - e.comment = '@undocumented'; - doclet = createDoclet(e.comment, e); - } + if (doclet.name) { + // try again, without the comment + e.comment = '@undocumented'; + doclet = createDoclet(e.comment, e); + } - return doclet; + return doclet; } function setCurrentModule(doclet) { - if (doclet.kind === 'module') { - currentModule = new CurrentModule(doclet); - } + if (doclet.kind === 'module') { + currentModule = new CurrentModule(doclet); + } } function setModuleScopeMemberOf(parser, doclet) { - let parentDoclet; - let skipMemberof; + let parentDoclet; + let skipMemberof; - // handle module symbols that are _not_ assigned to module.exports - if (currentModule && currentModule.longname !== doclet.name) { - if (!doclet.scope) { - // is this a method definition? if so, we usually get the scope from the node directly - if (doclet.meta && doclet.meta.code && doclet.meta.code.node && - doclet.meta.code.node.type === Syntax.MethodDefinition) { - // special case for constructors of classes that have @alias tags - if (doclet.meta.code.node.kind === 'constructor') { - parentDoclet = parser._getDocletById( - doclet.meta.code.node.parent.parent.nodeId - ); + // handle module symbols that are _not_ assigned to module.exports + if (currentModule && currentModule.longname !== doclet.name) { + if (!doclet.scope) { + // is this a method definition? if so, we usually get the scope from the node directly + if ( + doclet.meta && + doclet.meta.code && + doclet.meta.code.node && + doclet.meta.code.node.type === Syntax.MethodDefinition + ) { + // special case for constructors of classes that have @alias tags + if (doclet.meta.code.node.kind === 'constructor') { + parentDoclet = parser._getDocletById(doclet.meta.code.node.parent.parent.nodeId); - if (parentDoclet && parentDoclet.alias) { - // the constructor should use the same name as the class - doclet.addTag('alias', parentDoclet.alias); - doclet.addTag('name', parentDoclet.alias); + if (parentDoclet && parentDoclet.alias) { + // the constructor should use the same name as the class + doclet.addTag('alias', parentDoclet.alias); + doclet.addTag('name', parentDoclet.alias); - // and we shouldn't try to set a memberof value - skipMemberof = true; - } - } - else if (doclet.meta.code.node.static) { - doclet.addTag('static'); - } - else { - doclet.addTag('instance'); - } - } - // is this something that the module exports? if so, it's a static member - else if (doclet.meta && doclet.meta.code && doclet.meta.code.node && - doclet.meta.code.node.parent && - doclet.meta.code.node.parent.type === Syntax.ExportNamedDeclaration) { - doclet.addTag('static'); - } - // otherwise, it must be an inner member - else { - doclet.addTag('inner'); - } - } - - // if the doclet isn't a memberof anything yet, and it's not a global, it must be a memberof - // the current module (unless we were told to skip adding memberof) - if (!doclet.memberof && doclet.scope !== SCOPE.NAMES.GLOBAL && !skipMemberof) { - doclet.addTag('memberof', currentModule.longname); + // and we shouldn't try to set a memberof value + skipMemberof = true; + } + } else if (doclet.meta.code.node.static) { + doclet.addTag('static'); + } else { + doclet.addTag('instance'); } + } + // is this something that the module exports? if so, it's a static member + else if ( + doclet.meta && + doclet.meta.code && + doclet.meta.code.node && + doclet.meta.code.node.parent && + doclet.meta.code.node.parent.type === Syntax.ExportNamedDeclaration + ) { + doclet.addTag('static'); + } + // otherwise, it must be an inner member + else { + doclet.addTag('inner'); + } } + + // if the doclet isn't a memberof anything yet, and it's not a global, it must be a memberof + // the current module (unless we were told to skip adding memberof) + if (!doclet.memberof && doclet.scope !== SCOPE.NAMES.GLOBAL && !skipMemberof) { + doclet.addTag('memberof', currentModule.longname); + } + } } function setDefaultScope(doclet) { - // module doclets don't get a default scope - if (!doclet.scope && doclet.kind !== 'module') { - doclet.setScope(SCOPE.NAMES.GLOBAL); - } + // module doclets don't get a default scope + if (!doclet.scope && doclet.kind !== 'module') { + doclet.setScope(SCOPE.NAMES.GLOBAL); + } } function addDoclet(parser, newDoclet) { - let e; + let e; - if (newDoclet) { - setCurrentModule(newDoclet); - e = { doclet: newDoclet }; - parser.emit('newDoclet', e); + if (newDoclet) { + setCurrentModule(newDoclet); + e = { doclet: newDoclet }; + parser.emit('newDoclet', e); - if ( !e.defaultPrevented && !filterByLongname(e.doclet) ) { - parser.addResult(e.doclet); - } + if (!e.defaultPrevented && !filterByLongname(e.doclet)) { + parser.addResult(e.doclet); } + } } function processAlias(parser, doclet, astNode) { - let memberofName; + let memberofName; - if (doclet.alias === '{@thisClass}') { - memberofName = parser.resolveThis(astNode); + if (doclet.alias === '{@thisClass}') { + memberofName = parser.resolveThis(astNode); - // "class" refers to the owner of the prototype, not the prototype itself - if ( /^(.+?)(\.prototype|#)$/.test(memberofName) ) { - memberofName = RegExp.$1; - } - doclet.alias = memberofName; + // "class" refers to the owner of the prototype, not the prototype itself + if (/^(.+?)(\.prototype|#)$/.test(memberofName)) { + memberofName = RegExp.$1; } + doclet.alias = memberofName; + } - doclet.addTag('name', doclet.alias); - doclet.postProcess(); + doclet.addTag('name', doclet.alias); + doclet.postProcess(); } // TODO: separate code that resolves `this` from code that resolves the module object function findSymbolMemberof(parser, doclet, astNode, nameStartsWith, trailingPunc) { - let memberof = ''; - let nameAndPunc; - let scopePunc = ''; + let memberof = ''; + let nameAndPunc; + let scopePunc = ''; - // handle computed properties like foo['bar'] - if (trailingPunc === '[') { - // we don't know yet whether the symbol is a static or instance member - trailingPunc = null; + // handle computed properties like foo['bar'] + if (trailingPunc === '[') { + // we don't know yet whether the symbol is a static or instance member + trailingPunc = null; + } + + nameAndPunc = nameStartsWith + (trailingPunc || ''); + + // remove stuff that indicates module membership (but don't touch the name `module.exports`, + // which identifies the module object itself) + if (doclet.name !== 'module.exports') { + doclet.name = doclet.name.replace(nameAndPunc, ''); + } + + // like `bar` in: + // exports.bar = 1; + // module.exports.bar = 1; + // module.exports = MyModuleObject; MyModuleObject.bar = 1; + if (nameStartsWith !== 'this' && currentModule && doclet.name !== 'module.exports') { + memberof = currentModule.longname; + scopePunc = SCOPE.PUNC.STATIC; + } + // like: module.exports = 1; + else if (doclet.name === 'module.exports' && currentModule) { + doclet.addTag('name', currentModule.longname); + doclet.postProcess(); + } else { + memberof = parser.resolveThis(astNode); + + // like the following at the top level of a module: + // this.foo = 1; + if (nameStartsWith === 'this' && currentModule && !memberof) { + memberof = currentModule.longname; + scopePunc = SCOPE.PUNC.STATIC; + } else { + scopePunc = SCOPE.PUNC.INSTANCE; } + } - nameAndPunc = nameStartsWith + (trailingPunc || ''); - - // remove stuff that indicates module membership (but don't touch the name `module.exports`, - // which identifies the module object itself) - if (doclet.name !== 'module.exports') { - doclet.name = doclet.name.replace(nameAndPunc, ''); - } - - // like `bar` in: - // exports.bar = 1; - // module.exports.bar = 1; - // module.exports = MyModuleObject; MyModuleObject.bar = 1; - if (nameStartsWith !== 'this' && currentModule && doclet.name !== 'module.exports') { - memberof = currentModule.longname; - scopePunc = SCOPE.PUNC.STATIC; - } - // like: module.exports = 1; - else if (doclet.name === 'module.exports' && currentModule) { - doclet.addTag('name', currentModule.longname); - doclet.postProcess(); - } - else { - memberof = parser.resolveThis(astNode); - - // like the following at the top level of a module: - // this.foo = 1; - if (nameStartsWith === 'this' && currentModule && !memberof) { - memberof = currentModule.longname; - scopePunc = SCOPE.PUNC.STATIC; - } - else { - scopePunc = SCOPE.PUNC.INSTANCE; - } - } - - return { - memberof: memberof, - scopePunc: scopePunc - }; + return { + memberof: memberof, + scopePunc: scopePunc, + }; } function addSymbolMemberof(parser, doclet, astNode) { - let basename; - let memberof; - let memberofInfo; - let moduleOriginalName = ''; - let resolveTargetRegExp; - let scopePunc; - let unresolved; + let basename; + let memberof; + let memberofInfo; + let moduleOriginalName = ''; + let resolveTargetRegExp; + let scopePunc; + let unresolved; - if (!astNode) { - return; - } + if (!astNode) { + return; + } - // check to see if the doclet name is an unresolved reference to the module object, or to `this` - // TODO: handle cases where the module object is shadowed in the current scope - if (currentModule) { - moduleOriginalName = `|${currentModule.originalName}`; - } - resolveTargetRegExp = new RegExp(`^((?:module.)?exports|this${moduleOriginalName})(\\.|\\[|$)`); - unresolved = resolveTargetRegExp.exec(doclet.name); + // check to see if the doclet name is an unresolved reference to the module object, or to `this` + // TODO: handle cases where the module object is shadowed in the current scope + if (currentModule) { + moduleOriginalName = `|${currentModule.originalName}`; + } + resolveTargetRegExp = new RegExp(`^((?:module.)?exports|this${moduleOriginalName})(\\.|\\[|$)`); + unresolved = resolveTargetRegExp.exec(doclet.name); - if (unresolved) { - memberofInfo = findSymbolMemberof(parser, doclet, astNode, unresolved[1], unresolved[2]); - memberof = memberofInfo.memberof; - scopePunc = memberofInfo.scopePunc; + if (unresolved) { + memberofInfo = findSymbolMemberof(parser, doclet, astNode, unresolved[1], unresolved[2]); + memberof = memberofInfo.memberof; + scopePunc = memberofInfo.scopePunc; - if (memberof) { - doclet.name = doclet.name ? - memberof + scopePunc + doclet.name : - memberof; - } - } - else { - memberofInfo = parser.astnodeToMemberof(astNode); - basename = memberofInfo.basename; - memberof = memberofInfo.memberof; - } - - // if we found a memberof name, apply it to the doclet if (memberof) { - doclet.addTag('memberof', memberof); - if (basename) { - doclet.name = (doclet.name || '') - .replace(new RegExp(`^${escape(basename)}.`), ''); - } + doclet.name = doclet.name ? memberof + scopePunc + doclet.name : memberof; } - // otherwise, add the defaults for a module (if we're currently in a module) - else { - setModuleScopeMemberOf(parser, doclet); + } else { + memberofInfo = parser.astnodeToMemberof(astNode); + basename = memberofInfo.basename; + memberof = memberofInfo.memberof; + } + + // if we found a memberof name, apply it to the doclet + if (memberof) { + doclet.addTag('memberof', memberof); + if (basename) { + doclet.name = (doclet.name || '').replace(new RegExp(`^${escape(basename)}.`), ''); } + } + // otherwise, add the defaults for a module (if we're currently in a module) + else { + setModuleScopeMemberOf(parser, doclet); + } } function newSymbolDoclet(parser, docletSrc, e) { - const newDoclet = createSymbolDoclet(docletSrc, e); + const newDoclet = createSymbolDoclet(docletSrc, e); - // if there's an alias, use that as the symbol name - if (newDoclet.alias) { - processAlias(parser, newDoclet, e.astnode); - } - // otherwise, get the symbol name from the code - else if (e.code && typeof e.code.name !== 'undefined' && e.code.name !== '') { - newDoclet.addTag('name', e.code.name); - if (!newDoclet.memberof) { - addSymbolMemberof(parser, newDoclet, e.astnode); - } - - newDoclet.postProcess(); - } - else { - return false; + // if there's an alias, use that as the symbol name + if (newDoclet.alias) { + processAlias(parser, newDoclet, e.astnode); + } + // otherwise, get the symbol name from the code + else if (e.code && typeof e.code.name !== 'undefined' && e.code.name !== '') { + newDoclet.addTag('name', e.code.name); + if (!newDoclet.memberof) { + addSymbolMemberof(parser, newDoclet, e.astnode); } - // set the scope to global unless any of the following are true: - // a) the doclet is a memberof something - // b) the doclet represents a module - // c) we're in a module that exports only this symbol - if ( !newDoclet.memberof && newDoclet.kind !== 'module' && - (!currentModule || currentModule.longname !== newDoclet.name) ) { - newDoclet.scope = SCOPE.NAMES.GLOBAL; - } + newDoclet.postProcess(); + } else { + return false; + } - // handle cases where the doclet kind is auto-detected from the node type - if (e.code.kind && newDoclet.kind === 'member') { - newDoclet.kind = e.code.kind; - } + // set the scope to global unless any of the following are true: + // a) the doclet is a memberof something + // b) the doclet represents a module + // c) we're in a module that exports only this symbol + if ( + !newDoclet.memberof && + newDoclet.kind !== 'module' && + (!currentModule || currentModule.longname !== newDoclet.name) + ) { + newDoclet.scope = SCOPE.NAMES.GLOBAL; + } - addDoclet(parser, newDoclet); - e.doclet = newDoclet; + // handle cases where the doclet kind is auto-detected from the node type + if (e.code.kind && newDoclet.kind === 'member') { + newDoclet.kind = e.code.kind; + } - return true; + addDoclet(parser, newDoclet); + e.doclet = newDoclet; + + return true; } /** * Attach these event handlers to a particular instance of a parser. * @param parser */ -exports.attachTo = parser => { - // Handle JSDoc "virtual comments" that include one of the following: - // + A `@name` tag - // + Another tag that accepts a name, such as `@function` - parser.on('jsdocCommentFound', e => { - const comments = e.comment.split(/@also\b/g); - let newDoclet; +exports.attachTo = (parser) => { + // Handle JSDoc "virtual comments" that include one of the following: + // + A `@name` tag + // + Another tag that accepts a name, such as `@function` + parser.on('jsdocCommentFound', (e) => { + const comments = e.comment.split(/@also\b/g); + let newDoclet; - for (let i = 0, l = comments.length; i < l; i++) { - newDoclet = createDoclet(comments[i], e); + for (let i = 0, l = comments.length; i < l; i++) { + newDoclet = createDoclet(comments[i], e); - // we're only interested in virtual comments here - if (!newDoclet.name) { - continue; - } + // we're only interested in virtual comments here + if (!newDoclet.name) { + continue; + } - // add the default scope/memberof for a module (if we're in a module) - setModuleScopeMemberOf(parser, newDoclet); - newDoclet.postProcess(); + // add the default scope/memberof for a module (if we're in a module) + setModuleScopeMemberOf(parser, newDoclet); + newDoclet.postProcess(); - // if we _still_ don't have a scope, use the default - setDefaultScope(newDoclet); + // if we _still_ don't have a scope, use the default + setDefaultScope(newDoclet); - addDoclet(parser, newDoclet); + addDoclet(parser, newDoclet); - e.doclet = newDoclet; - } - }); + e.doclet = newDoclet; + } + }); - // Handle named symbols in the code. May or may not have a JSDoc comment attached. - parser.on('symbolFound', e => { - const comments = e.comment.split(/@also\b/g); + // Handle named symbols in the code. May or may not have a JSDoc comment attached. + parser.on('symbolFound', (e) => { + const comments = e.comment.split(/@also\b/g); - for (let i = 0, l = comments.length; i < l; i++) { - newSymbolDoclet(parser, comments[i], e); - } - }); + for (let i = 0, l = comments.length; i < l; i++) { + newSymbolDoclet(parser, comments[i], e); + } + }); - parser.on('fileComplete', () => { - currentModule = null; - }); + parser.on('fileComplete', () => { + currentModule = null; + }); }; diff --git a/packages/jsdoc/lib/jsdoc/src/parser.js b/packages/jsdoc/lib/jsdoc/src/parser.js index f3c0bea2..aeb04ed3 100644 --- a/packages/jsdoc/lib/jsdoc/src/parser.js +++ b/packages/jsdoc/lib/jsdoc/src/parser.js @@ -13,74 +13,80 @@ const { Walker } = require('jsdoc/src/walker'); const hasOwnProp = Object.prototype.hasOwnProperty; // TODO: docs -const PARSERS = exports.PARSERS = { - js: 'jsdoc/src/parser' -}; +const PARSERS = (exports.PARSERS = { + js: 'jsdoc/src/parser', +}); /* eslint-disable no-script-url */ // Prefix for JavaScript strings that were provided in lieu of a filename. const SCHEMA = 'javascript:'; /* eslint-enable no-script-url */ class DocletCache { - constructor() { - this._doclets = {}; + constructor() { + this._doclets = {}; + } + + get(itemName) { + if (!hasOwnProp.call(this._doclets, itemName)) { + return null; } - get(itemName) { - if ( !hasOwnProp.call(this._doclets, itemName) ) { - return null; - } + // always return the most recent doclet + return this._doclets[itemName][this._doclets[itemName].length - 1]; + } - // always return the most recent doclet - return this._doclets[itemName][this._doclets[itemName].length - 1]; + put(itemName, value) { + if (!hasOwnProp.call(this._doclets, itemName)) { + this._doclets[itemName] = []; } - put(itemName, value) { - if ( !hasOwnProp.call(this._doclets, itemName) ) { - this._doclets[itemName] = []; - } - - this._doclets[itemName].push(value); - } + this._doclets[itemName].push(value); + } } // TODO: docs exports.createParser = (type, conf) => { - let modulePath; + let modulePath; - if (!type) { - /* istanbul ignore next */ - type = 'js'; - } + if (!type) { + /* istanbul ignore next */ + type = 'js'; + } - if (hasOwnProp.call(PARSERS, type)) { - modulePath = PARSERS[type]; - } - else { - log.fatal(`The parser type "${type}" is not recognized.`); + if (hasOwnProp.call(PARSERS, type)) { + modulePath = PARSERS[type]; + } else { + log.fatal(`The parser type "${type}" is not recognized.`); - return null; - } + return null; + } - return new (require(modulePath).Parser)(conf); + return new (require(modulePath).Parser)(conf); }; // TODO: docs function pretreat(code) { - return code - // comment out hashbang at the top of the file, like: #!/usr/bin/env node - .replace(/^(#![\S \t]+\r?\n)/, '// $1') + return ( + code + // comment out hashbang at the top of the file, like: #!/usr/bin/env node + .replace(/^(#![\S \t]+\r?\n)/, '// $1') - // to support code minifiers that preserve /*! comments, treat /*!* as equivalent to /** - .replace(/\/\*!\*/g, '/**') - // merge adjacent doclets - .replace(/\*\/\/\*\*+/g, '@also'); + // to support code minifiers that preserve /*! comments, treat /*!* as equivalent to /** + .replace(/\/\*!\*/g, '/**') + // merge adjacent doclets + .replace(/\*\/\/\*\*+/g, '@also') + ); } // TODO: docs function definedInScope(doclet, basename) { - return Boolean(doclet) && Boolean(doclet.meta) && Boolean(doclet.meta.vars) && - Boolean(basename) && hasOwnProp.call(doclet.meta.vars, basename); + return ( + Boolean(doclet) && + Boolean(doclet.meta) && + Boolean(doclet.meta.vars) && + Boolean(basename) && + hasOwnProp.call(doclet.meta.vars, basename) + ); } // TODO: docs @@ -89,564 +95,557 @@ function definedInScope(doclet, basename) { * @extends module:events.EventEmitter */ class Parser extends EventEmitter { - // TODO: docs - constructor(conf) { - super(); + // TODO: docs + constructor(conf) { + super(); - this.clear(); + this.clear(); - this._conf = conf || {}; - this._visitor = new Visitor(); - this._walker = new Walker(); + this._conf = conf || {}; + this._visitor = new Visitor(); + this._walker = new Walker(); - this._visitor.setParser(this); + this._visitor.setParser(this); - Object.defineProperties(this, { - visitor: { - get() { - return this._visitor; - } - }, - walker: { - get() { - return this._walker; - } - } - }); + Object.defineProperties(this, { + visitor: { + get() { + return this._visitor; + }, + }, + walker: { + get() { + return this._walker; + }, + }, + }); + } + + // TODO: docs + clear() { + this._resultBuffer = []; + this._resultBuffer.index = { + borrowed: [], + documented: {}, + longname: {}, + memberof: {}, + }; + this._byNodeId = new DocletCache(); + this._byLongname = new DocletCache(); + this._byLongname.put(LONGNAMES.GLOBAL, { + meta: {}, + }); + } + + // TODO: update docs + /** + * Parse the given source files for JSDoc comments. + * @param {Array.} sourceFiles An array of filepaths to the JavaScript sources. + * @param {string} [encoding] + * + * @fires module:jsdoc/src/parser.Parser.parseBegin + * @fires module:jsdoc/src/parser.Parser.fileBegin + * @fires module:jsdoc/src/parser.Parser.jsdocCommentFound + * @fires module:jsdoc/src/parser.Parser.symbolFound + * @fires module:jsdoc/src/parser.Parser.newDoclet + * @fires module:jsdoc/src/parser.Parser.fileComplete + * @fires module:jsdoc/src/parser.Parser.parseComplete + * + * @example Parse two source files. + * var myFiles = ['file1.js', 'file2.js']; + * var docs = jsdocParser.parse(myFiles); + */ + parse(sourceFiles, encoding) { + encoding = encoding || this._conf.encoding || 'utf8'; + + let filename = ''; + let sourceCode = ''; + let sourceFile; + const parsedFiles = []; + const e = {}; + + if (typeof sourceFiles === 'string') { + sourceFiles = [sourceFiles]; } - // TODO: docs - clear() { - this._resultBuffer = []; - this._resultBuffer.index = { - borrowed: [], - documented: {}, - longname: {}, - memberof: {} + e.sourcefiles = sourceFiles; + log.debug('Parsing source files: %j', sourceFiles); + + this.emit('parseBegin', e); + + for (let i = 0, l = sourceFiles.length; i < l; i++) { + sourceCode = ''; + sourceFile = sourceFiles[i]; + + if (sourceFile.indexOf(SCHEMA) === 0) { + sourceCode = sourceFile.substr(SCHEMA.length); + filename = `[[string${i}]]`; + } else { + filename = sourceFile; + try { + sourceCode = fs.readFileSync(filename, encoding); + } catch (err) { + log.error(`Unable to read and parse the source file ${filename}: ${err}`); + } + } + + if (sourceCode.length) { + this._parseSourceCode(sourceCode, filename); + parsedFiles.push(filename); + } + } + + this.emit('parseComplete', { + sourcefiles: parsedFiles, + doclets: this._resultBuffer, + }); + log.debug('Finished parsing source files.'); + + return this._resultBuffer; + } + + // TODO: docs + fireProcessingComplete(doclets) { + this.emit('processingComplete', { doclets: doclets }); + } + + // TODO: docs + results() { + return this._resultBuffer; + } + + // TODO: update docs + /** + * @param {module:jsdoc/doclet.Doclet} doclet The parse result to add to the result buffer. + */ + addResult(doclet) { + const index = this._resultBuffer.index; + + this._resultBuffer.push(doclet); + + // track all doclets by longname + if (!hasOwnProp.call(index.longname, doclet.longname)) { + index.longname[doclet.longname] = []; + } + index.longname[doclet.longname].push(doclet); + + // track all doclets that have a memberof by memberof + if (doclet.memberof) { + if (!hasOwnProp.call(index.memberof, doclet.memberof)) { + index.memberof[doclet.memberof] = []; + } + index.memberof[doclet.memberof].push(doclet); + } + + // track longnames of documented symbols + if (!doclet.undocumented) { + if (!hasOwnProp.call(index.documented, doclet.longname)) { + index.documented[doclet.longname] = []; + } + index.documented[doclet.longname].push(doclet); + } + + // track doclets with a `borrowed` property + if (hasOwnProp.call(doclet, 'borrowed')) { + index.borrowed.push(doclet); + } + } + + // TODO: docs + addAstNodeVisitor(visitor) { + this._visitor.addAstNodeVisitor(visitor); + } + + // TODO: docs + getAstNodeVisitors() { + return this._visitor.getAstNodeVisitors(); + } + + /** @private */ + _parseSourceCode(sourceCode, sourceName) { + let ast; + let e = { + filename: sourceName, + }; + let sourceType; + + this.emit('fileBegin', e); + log.info(`Parsing ${sourceName} ...`); + + if (!e.defaultPrevented) { + e = { + filename: sourceName, + source: sourceCode, + }; + this.emit('beforeParse', e); + sourceCode = e.source; + sourceName = e.filename; + + sourceCode = pretreat(e.source); + sourceType = this._conf.source ? this._conf.source.type : undefined; + + ast = AstBuilder.build(sourceCode, sourceName, sourceType); + if (ast) { + this._walkAst(ast, this._visitor, sourceName); + } + } + + this.emit('fileComplete', e); + } + + /** @private */ + _walkAst(ast, visitor, sourceName) { + this._walker.recurse(ast, visitor, sourceName); + } + + // TODO: docs + addDocletRef(e) { + let fakeDoclet; + let node; + + if (e && e.code && e.code.node) { + node = e.code.node; + if (e.doclet) { + // allow lookup from node ID => doclet + this._byNodeId.put(node.nodeId, e.doclet); + this._byLongname.put(e.doclet.longname, e.doclet); + } + // keep references to undocumented anonymous functions, too, as they might have scoped vars + else if ( + (node.type === Syntax.FunctionDeclaration || + node.type === Syntax.FunctionExpression || + node.type === Syntax.ArrowFunctionExpression) && + !this._getDocletById(node.nodeId) + ) { + fakeDoclet = { + longname: LONGNAMES.ANONYMOUS, + meta: { + code: e.code, + }, }; - this._byNodeId = new DocletCache(); - this._byLongname = new DocletCache(); - this._byLongname.put(LONGNAMES.GLOBAL, { - meta: {} - }); + this._byNodeId.put(node.nodeId, fakeDoclet); + this._byLongname.put(fakeDoclet.longname, fakeDoclet); + } + } + } + + // TODO: docs + _getDocletById(id) { + return this._byNodeId.get(id); + } + + /** + * Retrieve the most recently seen doclet that has the given longname. + * + * @param {string} longname - The longname to search for. + * @return {module:jsdoc/doclet.Doclet?} The most recent doclet for the longname. + */ + _getDocletByLongname(longname) { + return this._byLongname.get(longname); + } + + // TODO: docs + /** + * Given a node, determine what the node is a member of. + * @param {node} node + * @returns {string} The long name of the node that this is a member of. + */ + astnodeToMemberof(node) { + let basename; + let doclet; + let scope; + + const result = {}; + const type = node.type; + + if ( + (type === Syntax.FunctionDeclaration || + type === Syntax.FunctionExpression || + type === Syntax.ArrowFunctionExpression || + type === Syntax.VariableDeclarator) && + node.enclosingScope + ) { + doclet = this._getDocletById(node.enclosingScope.nodeId); + + if (!doclet) { + result.memberof = LONGNAMES.ANONYMOUS + SCOPE.PUNC.INNER; + } else { + result.memberof = doclet.longname + SCOPE.PUNC.INNER; + } + } else if (type === Syntax.ClassPrivateProperty || type === Syntax.ClassProperty) { + doclet = this._getDocletById(node.enclosingScope.nodeId); + + if (!doclet) { + result.memberof = LONGNAMES.ANONYMOUS + SCOPE.PUNC.INSTANCE; + } else { + result.memberof = doclet.longname + SCOPE.PUNC.INSTANCE; + } + } else if (type === Syntax.MethodDefinition && node.kind === 'constructor') { + doclet = this._getDocletById(node.enclosingScope.nodeId); + + // global classes aren't a member of anything + if (doclet.memberof) { + result.memberof = doclet.memberof + SCOPE.PUNC.INNER; + } + } + // special case for methods in classes that are returned by arrow function expressions; for + // other method definitions, we get the memberof from the node name elsewhere. yes, this is + // confusing... + else if ( + type === Syntax.MethodDefinition && + node.parent.parent.parent && + node.parent.parent.parent.type === Syntax.ArrowFunctionExpression + ) { + doclet = this._getDocletById(node.enclosingScope.nodeId); + + if (doclet) { + result.memberof = + doclet.longname + (node.static === true ? SCOPE.PUNC.STATIC : SCOPE.PUNC.INSTANCE); + } + } else { + // check local references for aliases + scope = node; + basename = getBasename(astNode.nodeToValue(node)); + + // walk up the scope chain until we find the scope in which the node is defined + while (scope.enclosingScope) { + doclet = this._getDocletById(scope.enclosingScope.nodeId); + if (doclet && definedInScope(doclet, basename)) { + result.memberof = doclet.meta.vars[basename]; + result.basename = basename; + break; + } else { + // move up + scope = scope.enclosingScope; + } + } + + // do we know that it's a global? + doclet = this._getDocletByLongname(LONGNAMES.GLOBAL); + if (doclet && definedInScope(doclet, basename)) { + result.memberof = doclet.meta.vars[basename]; + result.basename = basename; + } else { + doclet = this._getDocletById(node.parent.nodeId); + + // set the result if we found a doclet. (if we didn't, the AST node may describe a + // global symbol.) + if (doclet) { + result.memberof = doclet.longname || doclet.name; + } + } } - // TODO: update docs - /** - * Parse the given source files for JSDoc comments. - * @param {Array.} sourceFiles An array of filepaths to the JavaScript sources. - * @param {string} [encoding] - * - * @fires module:jsdoc/src/parser.Parser.parseBegin - * @fires module:jsdoc/src/parser.Parser.fileBegin - * @fires module:jsdoc/src/parser.Parser.jsdocCommentFound - * @fires module:jsdoc/src/parser.Parser.symbolFound - * @fires module:jsdoc/src/parser.Parser.newDoclet - * @fires module:jsdoc/src/parser.Parser.fileComplete - * @fires module:jsdoc/src/parser.Parser.parseComplete - * - * @example Parse two source files. - * var myFiles = ['file1.js', 'file2.js']; - * var docs = jsdocParser.parse(myFiles); - */ - parse(sourceFiles, encoding) { - encoding = encoding || this._conf.encoding || 'utf8'; + return result; + } - let filename = ''; - let sourceCode = ''; - let sourceFile; - const parsedFiles = []; - const e = {}; + /** + * Get the doclet for the lowest-level class, if any, that is in the scope chain for a given node. + * + * @param {Object} node - The node whose scope chain will be searched. + * @return {module:jsdoc/doclet.Doclet?} The doclet for the lowest-level class in the node's scope + * chain. + */ + _getParentClass({ enclosingScope }) { + let doclet; + let parts; + let scope = enclosingScope; - if (typeof sourceFiles === 'string') { - sourceFiles = [sourceFiles]; - } - - e.sourcefiles = sourceFiles; - log.debug('Parsing source files: %j', sourceFiles); - - this.emit('parseBegin', e); - - for (let i = 0, l = sourceFiles.length; i < l; i++) { - sourceCode = ''; - sourceFile = sourceFiles[i]; - - if (sourceFile.indexOf(SCHEMA) === 0) { - sourceCode = sourceFile.substr(SCHEMA.length); - filename = `[[string${i}]]`; - } - else { - filename = sourceFile; - try { - sourceCode = fs.readFileSync(filename, encoding); - } - catch (err) { - log.error(`Unable to read and parse the source file ${filename}: ${err}`); - } - } - - if (sourceCode.length) { - this._parseSourceCode(sourceCode, filename); - parsedFiles.push(filename); - } - } - - this.emit('parseComplete', { - sourcefiles: parsedFiles, - doclets: this._resultBuffer - }); - log.debug('Finished parsing source files.'); - - return this._resultBuffer; + function isClass(d) { + return d && d.kind === 'class'; } - // TODO: docs - fireProcessingComplete(doclets) { - this.emit('processingComplete', { doclets: doclets }); - } + while (scope) { + // get the doclet, if any, for the parent scope + doclet = this._getDocletById(scope.nodeId); - // TODO: docs - results() { - return this._resultBuffer; - } - - // TODO: update docs - /** - * @param {module:jsdoc/doclet.Doclet} doclet The parse result to add to the result buffer. - */ - addResult(doclet) { - const index = this._resultBuffer.index; - - this._resultBuffer.push(doclet); - - // track all doclets by longname - if ( !hasOwnProp.call(index.longname, doclet.longname) ) { - index.longname[doclet.longname] = []; - } - index.longname[doclet.longname].push(doclet); - - // track all doclets that have a memberof by memberof - if (doclet.memberof) { - if ( !hasOwnProp.call(index.memberof, doclet.memberof) ) { - index.memberof[doclet.memberof] = []; - } - index.memberof[doclet.memberof].push(doclet); + if (doclet) { + // is the doclet for a class? if so, we're done + if (isClass(doclet)) { + break; } - // track longnames of documented symbols - if (!doclet.undocumented) { - if ( !hasOwnProp.call(index.documented, doclet.longname) ) { - index.documented[doclet.longname] = []; - } - index.documented[doclet.longname].push(doclet); + // is the doclet for an instance member of a class? if so, try to get the doclet for the + // owning class + parts = toParts(doclet.longname); + if (parts.scope === SCOPE.PUNC.INSTANCE) { + doclet = this._getDocletByLongname(parts.memberof); + if (isClass(doclet)) { + break; + } } + } - // track doclets with a `borrowed` property - if ( hasOwnProp.call(doclet, 'borrowed') ) { - index.borrowed.push(doclet); - } + // move up to the next parent scope + scope = scope.enclosingScope; } - // TODO: docs - addAstNodeVisitor(visitor) { - this._visitor.addAstNodeVisitor(visitor); - } + return isClass(doclet) ? doclet : null; + } - // TODO: docs - getAstNodeVisitors() { - return this._visitor.getAstNodeVisitors(); - } + // TODO: docs + /** + * Resolve what "this" refers to relative to a node. + * @param {node} node - The "this" node + * @returns {string} The longname of the enclosing node. + */ + resolveThis(node) { + let doclet; + let parentClass; + let result; - /** @private */ - _parseSourceCode(sourceCode, sourceName) { - let ast; - let e = { - filename: sourceName - }; - let sourceType; + // Properties are handled below. + if (node.type !== Syntax.Property && node.enclosingScope) { + // For ES2015 constructor functions, we use the class declaration to resolve `this`. + if ( + node.parent && + node.parent.type === Syntax.MethodDefinition && + node.parent.kind === 'constructor' + ) { + doclet = this._getDocletById(node.parent.parent.parent.nodeId); + } + // Otherwise, if there's an enclosing scope, we use the enclosing scope to resolve `this`. + else { + doclet = this._getDocletById(node.enclosingScope.nodeId); + } - this.emit('fileBegin', e); - log.info(`Parsing ${sourceName} ...`); + if (!doclet) { + result = LONGNAMES.ANONYMOUS; // TODO handle global this? + } else if (doclet.this) { + result = doclet.this; + } else if (doclet.kind === 'function' && doclet.memberof) { + parentClass = this._getParentClass(node); - if (!e.defaultPrevented) { - e = { - filename: sourceName, - source: sourceCode - }; - this.emit('beforeParse', e); - sourceCode = e.source; - sourceName = e.filename; - - sourceCode = pretreat(e.source); - sourceType = this._conf.source ? this._conf.source.type : undefined; - - ast = AstBuilder.build(sourceCode, sourceName, sourceType); - if (ast) { - this._walkAst(ast, this._visitor, sourceName); - } - } - - this.emit('fileComplete', e); - } - - /** @private */ - _walkAst(ast, visitor, sourceName) { - this._walker.recurse(ast, visitor, sourceName); - } - - // TODO: docs - addDocletRef(e) { - let fakeDoclet; - let node; - - if (e && e.code && e.code.node) { - node = e.code.node; - if (e.doclet) { - // allow lookup from node ID => doclet - this._byNodeId.put(node.nodeId, e.doclet); - this._byLongname.put(e.doclet.longname, e.doclet); - } - // keep references to undocumented anonymous functions, too, as they might have scoped vars - else if ( - (node.type === Syntax.FunctionDeclaration || node.type === Syntax.FunctionExpression || - node.type === Syntax.ArrowFunctionExpression) && - !this._getDocletById(node.nodeId) ) { - fakeDoclet = { - longname: LONGNAMES.ANONYMOUS, - meta: { - code: e.code - } - }; - this._byNodeId.put(node.nodeId, fakeDoclet); - this._byLongname.put(fakeDoclet.longname, fakeDoclet); - } - } - } - - // TODO: docs - _getDocletById(id) { - return this._byNodeId.get(id); - } - - /** - * Retrieve the most recently seen doclet that has the given longname. - * - * @param {string} longname - The longname to search for. - * @return {module:jsdoc/doclet.Doclet?} The most recent doclet for the longname. - */ - _getDocletByLongname(longname) { - return this._byLongname.get(longname); - } - - // TODO: docs - /** - * Given a node, determine what the node is a member of. - * @param {node} node - * @returns {string} The long name of the node that this is a member of. - */ - astnodeToMemberof(node) { - let basename; - let doclet; - let scope; - - const result = {}; - const type = node.type; - - if ( (type === Syntax.FunctionDeclaration || type === Syntax.FunctionExpression || - type === Syntax.ArrowFunctionExpression || type === Syntax.VariableDeclarator) && - node.enclosingScope ) { - doclet = this._getDocletById(node.enclosingScope.nodeId); - - if (!doclet) { - result.memberof = LONGNAMES.ANONYMOUS + SCOPE.PUNC.INNER; - } - else { - result.memberof = doclet.longname + SCOPE.PUNC.INNER; - } - } - else if (type === Syntax.ClassPrivateProperty || type === Syntax.ClassProperty) { - doclet = this._getDocletById(node.enclosingScope.nodeId); - - if (!doclet) { - result.memberof = LONGNAMES.ANONYMOUS + SCOPE.PUNC.INSTANCE; - } - else { - result.memberof = doclet.longname + SCOPE.PUNC.INSTANCE; - } - } - else if (type === Syntax.MethodDefinition && node.kind === 'constructor') { - doclet = this._getDocletById(node.enclosingScope.nodeId); - - // global classes aren't a member of anything - if (doclet.memberof) { - result.memberof = doclet.memberof + SCOPE.PUNC.INNER; - } - } - // special case for methods in classes that are returned by arrow function expressions; for - // other method definitions, we get the memberof from the node name elsewhere. yes, this is - // confusing... - else if (type === Syntax.MethodDefinition && node.parent.parent.parent && - node.parent.parent.parent.type === Syntax.ArrowFunctionExpression) { - doclet = this._getDocletById(node.enclosingScope.nodeId); - - if (doclet) { - result.memberof = doclet.longname + - (node.static === true ? - SCOPE.PUNC.STATIC : - SCOPE.PUNC.INSTANCE); - } + // like: function Foo() { this.bar = function(n) { /** blah */ this.name = n; }; + // or: Foo.prototype.bar = function(n) { /** blah */ this.name = n; }; + // or: var Foo = exports.Foo = function(n) { /** blah */ this.name = n; }; + // or: Foo.constructor = function(n) { /** blah */ this.name = n; } + if (parentClass || /\.constructor$/.test(doclet.longname)) { + result = doclet.memberof; } + // like: function notAClass(n) { /** global this */ this.name = n; } else { - // check local references for aliases - scope = node; - basename = getBasename( astNode.nodeToValue(node) ); - - // walk up the scope chain until we find the scope in which the node is defined - while (scope.enclosingScope) { - doclet = this._getDocletById(scope.enclosingScope.nodeId); - if ( doclet && definedInScope(doclet, basename) ) { - result.memberof = doclet.meta.vars[basename]; - result.basename = basename; - break; - } - else { - // move up - scope = scope.enclosingScope; - } - } - - // do we know that it's a global? - doclet = this._getDocletByLongname(LONGNAMES.GLOBAL); - if ( doclet && definedInScope(doclet, basename) ) { - result.memberof = doclet.meta.vars[basename]; - result.basename = basename; - } - else { - doclet = this._getDocletById(node.parent.nodeId); - - // set the result if we found a doclet. (if we didn't, the AST node may describe a - // global symbol.) - if (doclet) { - result.memberof = doclet.longname || doclet.name; - } - } + result = doclet.longname; } + } + // like: var foo = function(n) { /** blah */ this.bar = n; } + else if (doclet.kind === 'member' && astNode.isAssignment(node)) { + result = doclet.longname; + } + // walk up to the closest class we can find + else if (doclet.kind === 'class' || doclet.kind === 'interface' || doclet.kind === 'module') { + result = doclet.longname; + } else if (node.enclosingScope) { + result = this.resolveThis(node.enclosingScope); + } + } + // For object properties, we use the node's parent (the object) instead. + else { + doclet = this._getDocletById(node.parent.nodeId); - return result; + if (!doclet) { + // The object wasn't documented, so we don't know what name to use. + result = ''; + } else { + result = doclet.longname; + } } - /** - * Get the doclet for the lowest-level class, if any, that is in the scope chain for a given node. - * - * @param {Object} node - The node whose scope chain will be searched. - * @return {module:jsdoc/doclet.Doclet?} The doclet for the lowest-level class in the node's scope - * chain. - */ - _getParentClass({enclosingScope}) { - let doclet; - let parts; - let scope = enclosingScope; + return result; + } - function isClass(d) { - return d && d.kind === 'class'; - } + /** + * Given an AST node representing an object property, find the doclets for the parent object or + * objects. + * + * If the object is part of a simple assignment (for example, `var foo = { x: 1 }`), this method + * returns a single doclet (in this case, the doclet for `foo`). + * + * If the object is part of a chained assignment (for example, `var foo = exports.FOO = { x: 1 }`, + * this method returns multiple doclets (in this case, the doclets for `foo` and `exports.FOO`). + * + * @param {Object} node - An AST node representing an object property. + * @return {Array.} An array of doclets for the parent object or objects, or + * an empty array if no doclets are found. + */ + resolvePropertyParents({ parent }) { + let currentAncestor = parent; + let nextAncestor = currentAncestor.parent; + let doclet; + const doclets = []; - while (scope) { - // get the doclet, if any, for the parent scope - doclet = this._getDocletById(scope.nodeId); + while (currentAncestor) { + doclet = this._getDocletById(currentAncestor.nodeId); + if (doclet) { + doclets.push(doclet); + } - if (doclet) { - // is the doclet for a class? if so, we're done - if ( isClass(doclet) ) { - break; - } - - // is the doclet for an instance member of a class? if so, try to get the doclet for the - // owning class - parts = toParts(doclet.longname); - if (parts.scope === SCOPE.PUNC.INSTANCE) { - doclet = this._getDocletByLongname(parts.memberof); - if ( isClass(doclet) ) { - break; - } - } - } - - // move up to the next parent scope - scope = scope.enclosingScope; - } - - return (isClass(doclet) ? doclet : null); + // if the next ancestor is an assignment expression (for example, `exports.FOO` in + // `var foo = exports.FOO = { x: 1 }`, keep walking upwards + if (nextAncestor && nextAncestor.type === Syntax.AssignmentExpression) { + nextAncestor = nextAncestor.parent; + currentAncestor = currentAncestor.parent; + } + // otherwise, we're done + else { + currentAncestor = null; + } } - // TODO: docs - /** - * Resolve what "this" refers to relative to a node. - * @param {node} node - The "this" node - * @returns {string} The longname of the enclosing node. - */ - resolveThis(node) { - let doclet; - let parentClass; - let result; + return doclets; + } - // Properties are handled below. - if (node.type !== Syntax.Property && node.enclosingScope) { - // For ES2015 constructor functions, we use the class declaration to resolve `this`. - if (node.parent && node.parent.type === Syntax.MethodDefinition && - node.parent.kind === 'constructor') { - doclet = this._getDocletById(node.parent.parent.parent.nodeId); - } - // Otherwise, if there's an enclosing scope, we use the enclosing scope to resolve `this`. - else { - doclet = this._getDocletById(node.enclosingScope.nodeId); - } + // TODO: docs + /** + * Resolve what function a var is limited to. + * @param {astnode} node + * @param {string} basename The leftmost name in the long name: in foo.bar.zip the basename is foo. + */ + resolveVar({ enclosingScope, type }, basename) { + let doclet; + let result; + const scope = enclosingScope; - if (!doclet) { - result = LONGNAMES.ANONYMOUS; // TODO handle global this? - } - else if (doclet.this) { - result = doclet.this; - } - else if (doclet.kind === 'function' && doclet.memberof) { - parentClass = this._getParentClass(node); - - // like: function Foo() { this.bar = function(n) { /** blah */ this.name = n; }; - // or: Foo.prototype.bar = function(n) { /** blah */ this.name = n; }; - // or: var Foo = exports.Foo = function(n) { /** blah */ this.name = n; }; - // or: Foo.constructor = function(n) { /** blah */ this.name = n; } - if ( parentClass || /\.constructor$/.test(doclet.longname) ) { - result = doclet.memberof; - } - // like: function notAClass(n) { /** global this */ this.name = n; } - else { - result = doclet.longname; - } - } - // like: var foo = function(n) { /** blah */ this.bar = n; } - else if ( doclet.kind === 'member' && astNode.isAssignment(node) ) { - result = doclet.longname; - } - // walk up to the closest class we can find - else if (doclet.kind === 'class' || doclet.kind === 'interface' || - doclet.kind === 'module') { - result = doclet.longname; - } - else if (node.enclosingScope) { - result = this.resolveThis(node.enclosingScope); - } - } - // For object properties, we use the node's parent (the object) instead. - else { - doclet = this._getDocletById(node.parent.nodeId); - - if (!doclet) { - // The object wasn't documented, so we don't know what name to use. - result = ''; - } - else { - result = doclet.longname; - } - } - - return result; + // HACK: return an empty string for function declarations so they don't end up in anonymous + // scope (see #685 and #693) + if (type === Syntax.FunctionDeclaration) { + result = ''; + } else if (!scope) { + result = ''; // global + } else { + doclet = this._getDocletById(scope.nodeId); + if (definedInScope(doclet, basename)) { + result = doclet.longname; + } else { + result = this.resolveVar(scope, basename); + } } - /** - * Given an AST node representing an object property, find the doclets for the parent object or - * objects. - * - * If the object is part of a simple assignment (for example, `var foo = { x: 1 }`), this method - * returns a single doclet (in this case, the doclet for `foo`). - * - * If the object is part of a chained assignment (for example, `var foo = exports.FOO = { x: 1 }`, - * this method returns multiple doclets (in this case, the doclets for `foo` and `exports.FOO`). - * - * @param {Object} node - An AST node representing an object property. - * @return {Array.} An array of doclets for the parent object or objects, or - * an empty array if no doclets are found. - */ - resolvePropertyParents({parent}) { - let currentAncestor = parent; - let nextAncestor = currentAncestor.parent; - let doclet; - const doclets = []; + return result; + } - while (currentAncestor) { - doclet = this._getDocletById(currentAncestor.nodeId); - if (doclet) { - doclets.push(doclet); - } + // TODO: docs + resolveEnum(e) { + const doclets = this.resolvePropertyParents(e.code.node.parent); - // if the next ancestor is an assignment expression (for example, `exports.FOO` in - // `var foo = exports.FOO = { x: 1 }`, keep walking upwards - if (nextAncestor && nextAncestor.type === Syntax.AssignmentExpression) { - nextAncestor = nextAncestor.parent; - currentAncestor = currentAncestor.parent; - } - // otherwise, we're done - else { - currentAncestor = null; - } + doclets.forEach((doclet) => { + if (doclet && doclet.isEnum) { + doclet.properties = doclet.properties || []; + + // members of an enum inherit the enum's type + if (doclet.type && !e.doclet.type) { + // clone the type to prevent circular refs + e.doclet.type = _.cloneDeep(doclet.type); } - return doclets; - } + delete e.doclet.undocumented; + e.doclet.defaultvalue = e.doclet.meta.code.value; - // TODO: docs - /** - * Resolve what function a var is limited to. - * @param {astnode} node - * @param {string} basename The leftmost name in the long name: in foo.bar.zip the basename is foo. - */ - resolveVar({enclosingScope, type}, basename) { - let doclet; - let result; - const scope = enclosingScope; - - // HACK: return an empty string for function declarations so they don't end up in anonymous - // scope (see #685 and #693) - if (type === Syntax.FunctionDeclaration) { - result = ''; - } - else if (!scope) { - result = ''; // global - } - else { - doclet = this._getDocletById(scope.nodeId); - if ( definedInScope(doclet, basename) ) { - result = doclet.longname; - } - else { - result = this.resolveVar(scope, basename); - } - } - - return result; - } - - // TODO: docs - resolveEnum(e) { - const doclets = this.resolvePropertyParents(e.code.node.parent); - - doclets.forEach(doclet => { - if (doclet && doclet.isEnum) { - doclet.properties = doclet.properties || []; - - // members of an enum inherit the enum's type - if (doclet.type && !e.doclet.type) { - // clone the type to prevent circular refs - e.doclet.type = _.cloneDeep(doclet.type); - } - - delete e.doclet.undocumented; - e.doclet.defaultvalue = e.doclet.meta.code.value; - - // add the doclet to the parent's properties - doclet.properties.push(e.doclet); - } - }); - } + // add the doclet to the parent's properties + doclet.properties.push(e.doclet); + } + }); + } } exports.Parser = Parser; diff --git a/packages/jsdoc/lib/jsdoc/src/scanner.js b/packages/jsdoc/lib/jsdoc/src/scanner.js index a82a3111..81aa748f 100644 --- a/packages/jsdoc/lib/jsdoc/src/scanner.js +++ b/packages/jsdoc/lib/jsdoc/src/scanner.js @@ -11,54 +11,52 @@ const { statSync } = require('fs'); * @extends module:events.EventEmitter */ class Scanner extends EventEmitter { - constructor() { - super(); - } + constructor() { + super(); + } - /** - * Recursively searches the given searchPaths for js files. - * @param {Array.} searchPaths - * @param {number} [depth] - * @fires sourceFileFound - */ - scan(searchPaths, depth, filter) { - let currentFile; - let filePaths = []; + /** + * Recursively searches the given searchPaths for js files. + * @param {Array.} searchPaths + * @param {number} [depth] + * @fires sourceFileFound + */ + scan(searchPaths, depth, filter) { + let currentFile; + let filePaths = []; - searchPaths = searchPaths || []; - depth = depth || 1; + searchPaths = searchPaths || []; + depth = depth || 1; - searchPaths.forEach($ => { - const filepath = path.resolve(process.cwd(), decodeURIComponent($)); + searchPaths.forEach(($) => { + const filepath = path.resolve(process.cwd(), decodeURIComponent($)); - try { - currentFile = statSync(filepath); - } - catch (e) { - log.error(`Unable to find the source file or directory ${filepath}`); + try { + currentFile = statSync(filepath); + } catch (e) { + log.error(`Unable to find the source file or directory ${filepath}`); - return; - } + return; + } - if ( currentFile.isFile() ) { - filePaths.push(filepath); - } - else { - filePaths = filePaths.concat(lsSync(filepath, depth)); - } - }); + if (currentFile.isFile()) { + filePaths.push(filepath); + } else { + filePaths = filePaths.concat(lsSync(filepath, depth)); + } + }); - filePaths = filePaths.filter($ => filter.isIncluded($)); + filePaths = filePaths.filter(($) => filter.isIncluded($)); - filePaths = filePaths.filter($ => { - const e = { fileName: $ }; + filePaths = filePaths.filter(($) => { + const e = { fileName: $ }; - this.emit('sourceFileFound', e); + this.emit('sourceFileFound', e); - return !e.defaultPrevented; - }); + return !e.defaultPrevented; + }); - return filePaths; - } + return filePaths; + } } exports.Scanner = Scanner; diff --git a/packages/jsdoc/lib/jsdoc/src/visitor.js b/packages/jsdoc/lib/jsdoc/src/visitor.js index 2d0f81d2..f997e83c 100644 --- a/packages/jsdoc/lib/jsdoc/src/visitor.js +++ b/packages/jsdoc/lib/jsdoc/src/visitor.js @@ -13,8 +13,8 @@ const { Syntax } = require('@jsdoc/parse'); * @private * @param {!Object} comment - A comment node with `type` and `value` properties. */ -function getRawComment({value}) { - return `/*${value}*/`; +function getRawComment({ value }) { + return `/*${value}*/`; } /** @@ -23,8 +23,8 @@ function getRawComment({value}) { * @param {!Object} comment - A comment node with `type` and `value` properties. * @return {boolean} `true` if the comment is a block comment, `false` otherwise. */ -function isBlockComment({type}) { - return type === 'CommentBlock'; +function isBlockComment({ type }) { + return type === 'CommentBlock'; } /** @@ -35,50 +35,59 @@ function isBlockComment({type}) { * @memberof module:jsdoc/src/parser.Parser */ function isValidJsdoc(commentSrc) { - return commentSrc && commentSrc.length > 4 && commentSrc.indexOf('/**') === 0 && - commentSrc.indexOf('/***') !== 0; + return ( + commentSrc && + commentSrc.length > 4 && + commentSrc.indexOf('/**') === 0 && + commentSrc.indexOf('/***') !== 0 + ); } // TODO: docs function getLeadingJsdocComment(node) { - let comment = null; - let leadingComments = node.leadingComments; + let comment = null; + let leadingComments = node.leadingComments; - if (Array.isArray(leadingComments) && leadingComments.length) { - // the attached comments may include line comments, which we don't want - leadingComments = leadingComments.filter(isBlockComment); + if (Array.isArray(leadingComments) && leadingComments.length) { + // the attached comments may include line comments, which we don't want + leadingComments = leadingComments.filter(isBlockComment); - if (leadingComments.length) { - // treat the comment closest to the node as the leading comment - comment = getRawComment(leadingComments[leadingComments.length - 1]); + if (leadingComments.length) { + // treat the comment closest to the node as the leading comment + comment = getRawComment(leadingComments[leadingComments.length - 1]); - if ( !isValidJsdoc(comment) ) { - comment = null; - } - } + if (!isValidJsdoc(comment)) { + comment = null; + } } + } - return comment; + return comment; } // TODO: docs function makeVarsFinisher(scopeDoclet) { - return ({doclet, code}) => { - // no need to evaluate all things related to scopeDoclet again, just use it - if ( scopeDoclet && doclet && (doclet.alias || doclet.memberof) ) { - scopeDoclet.meta.vars[code.name] = doclet.longname; - } - }; + return ({ doclet, code }) => { + // no need to evaluate all things related to scopeDoclet again, just use it + if (scopeDoclet && doclet && (doclet.alias || doclet.memberof)) { + scopeDoclet.meta.vars[code.name] = doclet.longname; + } + }; } // Given an event, get the parent node's doclet. -function getParentDocletFromEvent(parser, {doclet}) { - if (doclet && doclet.meta && doclet.meta.code && doclet.meta.code.node && - doclet.meta.code.node.parent) { - return parser._getDocletById(doclet.meta.code.node.parent.nodeId); - } +function getParentDocletFromEvent(parser, { doclet }) { + if ( + doclet && + doclet.meta && + doclet.meta.code && + doclet.meta.code.node && + doclet.meta.code.node.parent + ) { + return parser._getDocletById(doclet.meta.code.node.parent.nodeId); + } - return null; + return null; } /** @@ -92,56 +101,56 @@ function getParentDocletFromEvent(parser, {doclet}) { * doclet. */ function makeInlineParamsFinisher(parser) { - return e => { - let documentedParams; - let knownParams; - let param; - let parentDoclet; + return (e) => { + let documentedParams; + let knownParams; + let param; + let parentDoclet; - let i = 0; + let i = 0; - parentDoclet = getParentDocletFromEvent(parser, e); - if (!parentDoclet) { - return; - } + parentDoclet = getParentDocletFromEvent(parser, e); + if (!parentDoclet) { + return; + } - // we only want to use the doclet if it's param-specific (but not, for example, if it's - // a param tagged with `@exports` in an AMD module) - if (e.doclet.kind !== 'param') { - return; - } + // we only want to use the doclet if it's param-specific (but not, for example, if it's + // a param tagged with `@exports` in an AMD module) + if (e.doclet.kind !== 'param') { + return; + } - parentDoclet.params = parentDoclet.params || []; - documentedParams = parentDoclet.params; - knownParams = parentDoclet.meta.code.paramnames || []; + parentDoclet.params = parentDoclet.params || []; + documentedParams = parentDoclet.params; + knownParams = parentDoclet.meta.code.paramnames || []; - while (true) { - param = documentedParams[i]; + while (true) { + param = documentedParams[i]; - // is the param already documented? if so, we don't need to use the doclet - if (param && param.name === e.doclet.name) { - e.doclet.undocumented = true; - break; - } + // is the param already documented? if so, we don't need to use the doclet + if (param && param.name === e.doclet.name) { + e.doclet.undocumented = true; + break; + } - // if we ran out of documented params, or we're at the parameter's actual position, - // splice in the param at the current index - if ( !param || i === knownParams.indexOf(e.doclet.name) ) { - documentedParams.splice(i, 0, { - type: e.doclet.type || {}, - description: '', - name: e.doclet.name - }); + // if we ran out of documented params, or we're at the parameter's actual position, + // splice in the param at the current index + if (!param || i === knownParams.indexOf(e.doclet.name)) { + documentedParams.splice(i, 0, { + type: e.doclet.type || {}, + description: '', + name: e.doclet.name, + }); - // the doclet is no longer needed - e.doclet.undocumented = true; + // the doclet is no longer needed + e.doclet.undocumented = true; - break; - } + break; + } - i++; - } - }; + i++; + } + }; } /** @@ -153,19 +162,19 @@ function makeInlineParamsFinisher(parser) { * @return {Object?} The node for the rest parameter. */ function findRestParam(params) { - let restParam = null; + let restParam = null; - params.some(param => { - if (param.type === Syntax.RestElement) { - restParam = param; + params.some((param) => { + if (param.type === Syntax.RestElement) { + restParam = param; - return true; - } + return true; + } - return false; - }); + return false; + }); - return restParam; + return restParam; } /** @@ -178,30 +187,32 @@ function findRestParam(params) { * the parameter is repeatable. */ function makeRestParamFinisher() { - return e => { - const doclet = e.doclet; - let documentedParams; - let restNode; + return (e) => { + const doclet = e.doclet; + let documentedParams; + let restNode; - if (!doclet) { - return; + if (!doclet) { + return; + } + + documentedParams = doclet.params = doclet.params || []; + restNode = findRestParam( + e.code.node.params || + (e.code.node.value && e.code.node.value.params) || + (e.code.node.init && e.code.node.init.params) || + [] + ); + + if (restNode) { + for (let i = documentedParams.length - 1; i >= 0; i--) { + if (documentedParams[i].name === restNode.argument.name) { + documentedParams[i].variable = true; + break; } - - documentedParams = doclet.params = doclet.params || []; - restNode = findRestParam(e.code.node.params || - (e.code.node.value && e.code.node.value.params) || - (e.code.node.init && e.code.node.init.params) || - []); - - if (restNode) { - for (let i = documentedParams.length - 1; i >= 0; i--) { - if (documentedParams[i].name === restNode.argument.name) { - documentedParams[i].variable = true; - break; - } - } - } - }; + } + } + }; } /** @@ -213,18 +224,17 @@ function makeRestParamFinisher() { * @return {Array.} The nodes for the default parameters. */ function findDefaultParams(params) { - const defaultParams = []; + const defaultParams = []; - params.forEach(param => { - if (param.type === Syntax.AssignmentPattern) { - defaultParams.push(param); - } - else { - defaultParams.push(null); - } - }); + params.forEach((param) => { + if (param.type === Syntax.AssignmentPattern) { + defaultParams.push(param); + } else { + defaultParams.push(null); + } + }); - return defaultParams; + return defaultParams; } /** @@ -242,50 +252,50 @@ function findDefaultParams(params) { * parameters. */ function makeDefaultParamFinisher() { - return e => { - let defaultValues; - const doclet = e.doclet; - let documentedParams; - let paramName; - let params; + return (e) => { + let defaultValues; + const doclet = e.doclet; + let documentedParams; + let paramName; + let params; - if (!doclet) { - return; - } + if (!doclet) { + return; + } - documentedParams = doclet.params = doclet.params || []; - params = e.code.node.params || (e.code.node.value && e.code.node.value.params) || []; - defaultValues = findDefaultParams(params); + documentedParams = doclet.params = doclet.params || []; + params = e.code.node.params || (e.code.node.value && e.code.node.value.params) || []; + defaultValues = findDefaultParams(params); - for (let i = 0, j = 0, l = params.length; i < l; i++) { - // bail out if we ran out of documented params - if (!documentedParams[j]) { - break; - } + for (let i = 0, j = 0, l = params.length; i < l; i++) { + // bail out if we ran out of documented params + if (!documentedParams[j]) { + break; + } - // if the current parameter doesn't appear to be documented, move to the next one - paramName = params[i].type === Syntax.AssignmentPattern ? - params[i].left.name : - params[i].name; - if (paramName !== documentedParams[j].name) { - continue; - } + // if the current parameter doesn't appear to be documented, move to the next one + paramName = + params[i].type === Syntax.AssignmentPattern ? params[i].left.name : params[i].name; + if (paramName !== documentedParams[j].name) { + continue; + } - // add the default value iff a) a literal default value is defined in the code, - // b) no default value is documented, and c) the default value is not an empty string - if (defaultValues[i] && - defaultValues[i].right && - defaultValues[i].right.type === Syntax.Literal && - typeof documentedParams[j].defaultvalue === 'undefined' && - defaultValues[i].right.value !== '') { - documentedParams[j].defaultvalue = - astNode.nodeToValue(defaultValues[i].right); - } + // add the default value iff a) a literal default value is defined in the code, + // b) no default value is documented, and c) the default value is not an empty string + if ( + defaultValues[i] && + defaultValues[i].right && + defaultValues[i].right.type === Syntax.Literal && + typeof documentedParams[j].defaultvalue === 'undefined' && + defaultValues[i].right.value !== '' + ) { + documentedParams[j].defaultvalue = astNode.nodeToValue(defaultValues[i].right); + } - // move to the next documented param - j++; - } - }; + // move to the next documented param + j++; + } + }; } /** @@ -299,34 +309,36 @@ function makeDefaultParamFinisher() { * @return {function} A function that merges the constructor's doclet into the class's doclet. */ function makeConstructorFinisher(parser) { - return e => { - let combined; - const eventDoclet = e.doclet; - let parentDoclet; + return (e) => { + let combined; + const eventDoclet = e.doclet; + let parentDoclet; - // for class declarations that are named module exports, the node that's documented is the - // ExportNamedDeclaration, not the ClassDeclaration - if (e.code.node.parent.parent.parent && - e.code.node.parent.parent.parent.type === Syntax.ExportNamedDeclaration) { - parentDoclet = parser._getDocletById(e.code.node.parent.parent.parent.nodeId); - } - // otherwise, we want the ClassDeclaration - else { - parentDoclet = parser._getDocletById(e.code.node.parent.parent.nodeId); - } + // for class declarations that are named module exports, the node that's documented is the + // ExportNamedDeclaration, not the ClassDeclaration + if ( + e.code.node.parent.parent.parent && + e.code.node.parent.parent.parent.type === Syntax.ExportNamedDeclaration + ) { + parentDoclet = parser._getDocletById(e.code.node.parent.parent.parent.nodeId); + } + // otherwise, we want the ClassDeclaration + else { + parentDoclet = parser._getDocletById(e.code.node.parent.parent.nodeId); + } - if (!eventDoclet || !parentDoclet || parentDoclet.undocumented) { - return; - } + if (!eventDoclet || !parentDoclet || parentDoclet.undocumented) { + return; + } - // We prefer the parent doclet because it has the correct kind, longname, and memberof. - // The child doclet might or might not have the correct kind, longname, and memberof. - combined = combineDoclets(parentDoclet, eventDoclet); + // We prefer the parent doclet because it has the correct kind, longname, and memberof. + // The child doclet might or might not have the correct kind, longname, and memberof. + combined = combineDoclets(parentDoclet, eventDoclet); - parser.addResult(combined); + parser.addResult(combined); - parentDoclet.undocumented = eventDoclet.undocumented = true; - }; + parentDoclet.undocumented = eventDoclet.undocumented = true; + }; } /** @@ -336,18 +348,21 @@ function makeConstructorFinisher(parser) { * @return {function} A function that adds an `async` property to the doclet of async functions. */ function makeAsyncFunctionFinisher() { - return e => { - const doclet = e.doclet; + return (e) => { + const doclet = e.doclet; - if (!doclet) { - return; - } + if (!doclet) { + return; + } - if ( e.code.node.async || (e.code.node.value && e.code.node.value.async) || - (e.code.node.init && e.code.node.init.async) ) { - doclet.async = true; - } - }; + if ( + e.code.node.async || + (e.code.node.value && e.code.node.value.async) || + (e.code.node.init && e.code.node.init.async) + ) { + doclet.async = true; + } + }; } /** @@ -357,9 +372,9 @@ function makeAsyncFunctionFinisher() { * @return {function} A function that marks a doclet as private. */ function makePrivatePropertyFinisher() { - return ({doclet}) => { - doclet.access = 'private'; - }; + return ({ doclet }) => { + doclet.access = 'private'; + }; } /** @@ -369,482 +384,484 @@ function makePrivatePropertyFinisher() { * @return {function} A function that marks a doclet as a generator function. */ function makeGeneratorFinisher() { - return e => { - const doclet = e.doclet; + return (e) => { + const doclet = e.doclet; - if (!doclet) { - return; - } + if (!doclet) { + return; + } - if ( e.code.node.generator || (e.code.node.init && e.code.node.init.generator) || - (e.code.node.value && e.code.node.value.generator) ) { - doclet.generator = true; - } - }; + if ( + e.code.node.generator || + (e.code.node.init && e.code.node.init.generator) || + (e.code.node.value && e.code.node.value.generator) + ) { + doclet.generator = true; + } + }; } // TODO: docs class SymbolFound { - // TODO: docs - constructor(node, filename, extras = {}) { - this.id = extras.id || node.nodeId; - this.comment = extras.comment || getLeadingJsdocComment(node) || '@undocumented'; - this.lineno = extras.lineno || node.loc.start.line; - this.columnno = extras.columnno || node.loc.start.column; - this.range = extras.range || node.range; - this.filename = extras.filename || filename; - this.astnode = extras.astnode || node; - this.code = extras.code; - this.event = extras.event || 'symbolFound'; - this.finishers = extras.finishers || []; + // TODO: docs + constructor(node, filename, extras = {}) { + this.id = extras.id || node.nodeId; + this.comment = extras.comment || getLeadingJsdocComment(node) || '@undocumented'; + this.lineno = extras.lineno || node.loc.start.line; + this.columnno = extras.columnno || node.loc.start.column; + this.range = extras.range || node.range; + this.filename = extras.filename || filename; + this.astnode = extras.astnode || node; + this.code = extras.code; + this.event = extras.event || 'symbolFound'; + this.finishers = extras.finishers || []; - // make sure the event includes properties that don't have default values - Object.keys(extras).forEach(key => { - this[key] = extras[key]; - }); - } + // make sure the event includes properties that don't have default values + Object.keys(extras).forEach((key) => { + this[key] = extras[key]; + }); + } } // TODO: docs class JsdocCommentFound { - // TODO: docs - constructor({loc, range}, rawComment, filename) { - this.comment = rawComment; - this.lineno = loc.start.line; - this.columnno = loc.start.column; - this.filename = filename; - this.range = range; + // TODO: docs + constructor({ loc, range }, rawComment, filename) { + this.comment = rawComment; + this.lineno = loc.start.line; + this.columnno = loc.start.column; + this.filename = filename; + this.range = range; - Object.defineProperty(this, 'event', { - value: 'jsdocCommentFound' - }); - } + Object.defineProperty(this, 'event', { + value: 'jsdocCommentFound', + }); + } } // TODO: docs function hasComments(node) { - return (node && node.leadingComments && node.leadingComments.length) || - (node && node.trailingComments && node.trailingComments.length) || - (node && node.innerComments && node.innerComments.length); + return ( + (node && node.leadingComments && node.leadingComments.length) || + (node && node.trailingComments && node.trailingComments.length) || + (node && node.innerComments && node.innerComments.length) + ); } // TODO: docs function removeCommentDelimiters(comment) { - return comment.substring(2, comment.length - 2); + return comment.substring(2, comment.length - 2); } // TODO: docs function updateCommentNode(commentNode, comment) { - commentNode.value = removeCommentDelimiters(comment); + commentNode.value = removeCommentDelimiters(comment); } // TODO: docs // TODO: note that it's essential to call this function before you try to resolve names! -function trackVars(parser, {enclosingScope}, {code, finishers}) { - let doclet; - const enclosingScopeId = enclosingScope ? enclosingScope.nodeId : null; +function trackVars(parser, { enclosingScope }, { code, finishers }) { + let doclet; + const enclosingScopeId = enclosingScope ? enclosingScope.nodeId : null; - if (enclosingScopeId) { - doclet = parser._getDocletById(enclosingScopeId); - } - else { - doclet = parser._getDocletByLongname(LONGNAMES.GLOBAL); - } + if (enclosingScopeId) { + doclet = parser._getDocletById(enclosingScopeId); + } else { + doclet = parser._getDocletByLongname(LONGNAMES.GLOBAL); + } - if (doclet) { - doclet.meta.vars = doclet.meta.vars || {}; - doclet.meta.vars[code.name] = null; - finishers.push( makeVarsFinisher(doclet) ); - } + if (doclet) { + doclet.meta.vars = doclet.meta.vars || {}; + doclet.meta.vars[code.name] = null; + finishers.push(makeVarsFinisher(doclet)); + } } // TODO: docs function makeSymbolFoundEvent(node, parser, filename) { - let e; - let basename; - let parent; + let e; + let basename; + let parent; - const extras = { - code: astNode.getInfo(node) + const extras = { + code: astNode.getInfo(node), + }; + + switch (node.type) { + // like: i = 0; + case Syntax.AssignmentExpression: + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + + basename = getBasename(e.code.name); + if (basename !== 'this') { + e.code.funcscope = parser.resolveVar(node, basename); + } + + break; + + // like `bar='baz'` in: function foo(bar='baz') {} + case Syntax.AssignmentPattern: + parent = node.parent; + + if (node.leadingComments && parent && astNode.isFunction(parent)) { + extras.finishers = [makeInlineParamsFinisher(parser)]; + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + } + + break; + + // like: class foo {} + case Syntax.ClassDeclaration: + // falls through + + // like: let MyClass = class {} + case Syntax.ClassExpression: + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + + basename = getBasename(e.code.name); + + break; + + // like `#b = 1` in: class A { #b = 1; } + case Syntax.ClassPrivateProperty: + extras.finishers = [parser.resolveEnum, makePrivatePropertyFinisher()]; + + e = new SymbolFound(node, filename, extras); + + break; + + // like `b = 1` in: class A { b = 1; } + case Syntax.ClassProperty: + extras.finishers = [parser.resolveEnum]; + + e = new SymbolFound(node, filename, extras); + + break; + + // like: export * from 'foo' + case Syntax.ExportAllDeclaration: + e = new SymbolFound(node, filename, extras); + + break; + + // like: export default 'foo' + case Syntax.ExportDefaultDeclaration: + // falls through + + // like: export var foo; + // or: export {foo} + case Syntax.ExportNamedDeclaration: + // falls through + + // like `foo as bar` in: export {foo as bar} + case Syntax.ExportSpecifier: + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + + break; + + // like: var foo = () => {}; + case Syntax.ArrowFunctionExpression: + // falls through + + // like: function foo() {} + case Syntax.FunctionDeclaration: + // falls through + + // like: var foo = function() {}; + case Syntax.FunctionExpression: + extras.finishers = [ + // handle cases where at least one parameter has a default value + makeDefaultParamFinisher(), + // handle rest parameters + makeRestParamFinisher(), + // handle async functions + makeAsyncFunctionFinisher(), + // handle generator functions + makeGeneratorFinisher(), + ]; + + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + + basename = getBasename(e.code.name); + e.code.funcscope = parser.resolveVar(node, basename); + + break; + + // like `bar` in: function foo(/** @type {string} */ bar) {} + // or `module` in: define("MyModule", function(/** @exports MyModule */ module) {} + // This is an extremely common type of node; we only care about function parameters with + // inline comments. No need to fire an event in other cases. + case Syntax.Identifier: + parent = node.parent; + + // function parameters with inline comments + if (node.leadingComments && parent && astNode.isFunction(parent)) { + extras.finishers = [makeInlineParamsFinisher(parser)]; + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + } + + break; + + // like `obj.prop` in: /** @typedef {string} */ obj.prop; + // Closure Compiler uses this pattern extensively for enums. + // No need to fire an event unless the node is already commented. + case Syntax.MemberExpression: + if (node.leadingComments) { + e = new SymbolFound(node, filename, extras); + } + + break; + + // like: foo() {} + // or: constructor() {} + case Syntax.MethodDefinition: + extras.finishers = [ + // handle cases where at least one parameter has a default value + makeDefaultParamFinisher(), + // handle rest parameters + makeRestParamFinisher(), + // handle async functions + makeAsyncFunctionFinisher(), + // handle generator functions + makeGeneratorFinisher(), + ]; + // for constructors, we attempt to merge the constructor's docs into the class's docs + if (node.kind === 'constructor') { + extras.finishers.push(makeConstructorFinisher(parser)); + } + + e = new SymbolFound(node, filename, extras); + + break; + + // like `{}` in: function Foo = Class.create(/** @lends Foo */ {}); + case Syntax.ObjectExpression: + e = new SymbolFound(node, filename, extras); + + break; + + // like `bar: true` in: var foo = { bar: true }; + // like `get bar() {}` in: var foo = { get bar() {} }; + case Syntax.Property: + if (node.kind !== 'get' && node.kind !== 'set') { + extras.finishers = [parser.resolveEnum]; + } + + e = new SymbolFound(node, filename, extras); + + break; + + // like `...bar` in: function foo(...bar) {} + case Syntax.RestElement: + parent = node.parent; + + if (node.leadingComments && parent && astNode.isFunction(parent)) { + extras.finishers = [makeInlineParamsFinisher(parser)]; + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + } + + break; + + // like: var i = 0; + case Syntax.VariableDeclarator: + extras.finishers = [ + // handle cases where at least one parameter has a default value + makeDefaultParamFinisher(), + // handle rest parameters + makeRestParamFinisher(), + // handle async functions + makeAsyncFunctionFinisher(), + // handle generator functions + makeGeneratorFinisher(), + ]; + + e = new SymbolFound(node, filename, extras); + + trackVars(parser, node, e); + + basename = getBasename(e.code.name); + // auto-detect constants + if (node.parent.kind === 'const') { + e.code.kind = 'constant'; + } + + break; + + default: + // ignore + } + + if (!e) { + e = { + finishers: [], }; + } - switch (node.type) { - // like: i = 0; - case Syntax.AssignmentExpression: - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - - basename = getBasename(e.code.name); - if (basename !== 'this') { - e.code.funcscope = parser.resolveVar(node, basename); - } - - break; - - // like `bar='baz'` in: function foo(bar='baz') {} - case Syntax.AssignmentPattern: - parent = node.parent; - - if ( node.leadingComments && parent && astNode.isFunction(parent) ) { - extras.finishers = [makeInlineParamsFinisher(parser)]; - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - } - - break; - - // like: class foo {} - case Syntax.ClassDeclaration: - // falls through - - // like: let MyClass = class {} - case Syntax.ClassExpression: - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - - basename = getBasename(e.code.name); - - break; - - // like `#b = 1` in: class A { #b = 1; } - case Syntax.ClassPrivateProperty: - extras.finishers = [ - parser.resolveEnum, - makePrivatePropertyFinisher() - ]; - - e = new SymbolFound(node, filename, extras); - - break; - - // like `b = 1` in: class A { b = 1; } - case Syntax.ClassProperty: - extras.finishers = [parser.resolveEnum]; - - e = new SymbolFound(node, filename, extras); - - break; - - // like: export * from 'foo' - case Syntax.ExportAllDeclaration: - e = new SymbolFound(node, filename, extras); - - break; - - // like: export default 'foo' - case Syntax.ExportDefaultDeclaration: - // falls through - - // like: export var foo; - // or: export {foo} - case Syntax.ExportNamedDeclaration: - // falls through - - // like `foo as bar` in: export {foo as bar} - case Syntax.ExportSpecifier: - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - - break; - - // like: var foo = () => {}; - case Syntax.ArrowFunctionExpression: - // falls through - - // like: function foo() {} - case Syntax.FunctionDeclaration: - // falls through - - // like: var foo = function() {}; - case Syntax.FunctionExpression: - extras.finishers = [ - // handle cases where at least one parameter has a default value - makeDefaultParamFinisher(), - // handle rest parameters - makeRestParamFinisher(), - // handle async functions - makeAsyncFunctionFinisher(), - // handle generator functions - makeGeneratorFinisher() - ]; - - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - - basename = getBasename(e.code.name); - e.code.funcscope = parser.resolveVar(node, basename); - - break; - - // like `bar` in: function foo(/** @type {string} */ bar) {} - // or `module` in: define("MyModule", function(/** @exports MyModule */ module) {} - // This is an extremely common type of node; we only care about function parameters with - // inline comments. No need to fire an event in other cases. - case Syntax.Identifier: - parent = node.parent; - - // function parameters with inline comments - if ( node.leadingComments && parent && astNode.isFunction(parent) ) { - extras.finishers = [makeInlineParamsFinisher(parser)]; - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - } - - break; - - // like `obj.prop` in: /** @typedef {string} */ obj.prop; - // Closure Compiler uses this pattern extensively for enums. - // No need to fire an event unless the node is already commented. - case Syntax.MemberExpression: - if (node.leadingComments) { - e = new SymbolFound(node, filename, extras); - } - - break; - - // like: foo() {} - // or: constructor() {} - case Syntax.MethodDefinition: - extras.finishers = [ - // handle cases where at least one parameter has a default value - makeDefaultParamFinisher(), - // handle rest parameters - makeRestParamFinisher(), - // handle async functions - makeAsyncFunctionFinisher(), - // handle generator functions - makeGeneratorFinisher() - ]; - // for constructors, we attempt to merge the constructor's docs into the class's docs - if (node.kind === 'constructor') { - extras.finishers.push( makeConstructorFinisher(parser) ); - } - - e = new SymbolFound(node, filename, extras); - - break; - - // like `{}` in: function Foo = Class.create(/** @lends Foo */ {}); - case Syntax.ObjectExpression: - e = new SymbolFound(node, filename, extras); - - break; - - // like `bar: true` in: var foo = { bar: true }; - // like `get bar() {}` in: var foo = { get bar() {} }; - case Syntax.Property: - if (node.kind !== 'get' && node.kind !== 'set') { - extras.finishers = [parser.resolveEnum]; - } - - e = new SymbolFound(node, filename, extras); - - break; - - // like `...bar` in: function foo(...bar) {} - case Syntax.RestElement: - parent = node.parent; - - if ( node.leadingComments && parent && astNode.isFunction(parent) ) { - extras.finishers = [makeInlineParamsFinisher(parser)]; - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - } - - break; - - // like: var i = 0; - case Syntax.VariableDeclarator: - extras.finishers = [ - // handle cases where at least one parameter has a default value - makeDefaultParamFinisher(), - // handle rest parameters - makeRestParamFinisher(), - // handle async functions - makeAsyncFunctionFinisher(), - // handle generator functions - makeGeneratorFinisher() - ]; - - e = new SymbolFound(node, filename, extras); - - trackVars(parser, node, e); - - basename = getBasename(e.code.name); - // auto-detect constants - if (node.parent.kind === 'const') { - e.code.kind = 'constant'; - } - - break; - - default: - // ignore - } - - if (!e) { - e = { - finishers: [] - }; - } - - return e; + return e; } // TODO: docs class Visitor { - // TODO: docs - constructor() { - this._parser = null; + // TODO: docs + constructor() { + this._parser = null; - // ESTree node visitors added by plugins - this._nodeVisitors = []; - // built-in visitors - this._visitors = [ - this.visitNodeComments, - this.visitNode - ]; + // ESTree node visitors added by plugins + this._nodeVisitors = []; + // built-in visitors + this._visitors = [this.visitNodeComments, this.visitNode]; + } + + /** + * Set the parser instance that visitors can use. + * + * @param {module:jsdoc/src/parser.Parser} parser - The parser instance. + */ + setParser(parser) { + this._parser = parser; + } + + // TODO: docs + addAstNodeVisitor(visitor) { + this._nodeVisitors.push(visitor); + } + + // TODO: docs + removeAstNodeVisitor(visitor) { + const idx = this._nodeVisitors.indexOf(visitor); + + if (idx !== -1) { + this._nodeVisitors.splice(idx, 1); + } + } + + // TODO: docs + getAstNodeVisitors() { + return this._nodeVisitors; + } + + // TODO: docs; visitor signature is (node, parser, filename) + visit(node, filename) { + for (let visitor of this._visitors) { + visitor.call(this, node, this._parser, filename); } - /** - * Set the parser instance that visitors can use. - * - * @param {module:jsdoc/src/parser.Parser} parser - The parser instance. - */ - setParser(parser) { - this._parser = parser; + return true; + } + + /* eslint-disable class-methods-use-this */ + // TODO: docs + visitNodeComments(node, parser, filename) { + let comments; + let e; + const isBlock = isBlockComment(node); + let lastTrailingComment; + let nextProgramNode; + let nextProgramNodeIndex; + let rawComment; + + function addComments(source) { + comments = comments.concat(source.slice(0)); } - // TODO: docs - addAstNodeVisitor(visitor) { - this._nodeVisitors.push(visitor); + if (!hasComments(node) && (!node.type || !isBlock)) { + return true; } - // TODO: docs - removeAstNodeVisitor(visitor) { - const idx = this._nodeVisitors.indexOf(visitor); + comments = isBlock ? [node] : []; - if (idx !== -1) { - this._nodeVisitors.splice(idx, 1); - } + if (node.leadingComments && node.leadingComments.length) { + addComments(node.leadingComments); } - // TODO: docs - getAstNodeVisitors() { - return this._nodeVisitors; + // trailing comments are always duplicates of leading comments unless they're attached to the + // Program node... + if (node.type === Syntax.Program && node.trailingComments && node.trailingComments.length) { + addComments(node.trailingComments); } - // TODO: docs; visitor signature is (node, parser, filename) - visit(node, filename) { - for (let visitor of this._visitors) { - visitor.call(this, node, this._parser, filename); - } + // ...or if they were comments from the end of the file that were erroneously attached to a + // `'use strict';` declaration (https://github.com/babel/babel/issues/6688). + if ( + node.type === Syntax.ExpressionStatement && + node.directive === 'use strict' && + node.trailingComments && + node.trailingComments.length + ) { + // to be safe, we verify that the trailing comments came after the next node in the Program + // body, which means the comments were attached to the wrong node + if (node.parent.body.length > 1) { + nextProgramNodeIndex = node.parent.body.indexOf(node) + 1; + nextProgramNode = node.parent.body[nextProgramNodeIndex]; + lastTrailingComment = node.trailingComments[node.trailingComments.length - 1]; - return true; + if (lastTrailingComment.start > nextProgramNode.end) { + addComments(node.trailingComments); + } + } } - /* eslint-disable class-methods-use-this */ - // TODO: docs - visitNodeComments(node, parser, filename) { - let comments; - let e; - const isBlock = isBlockComment(node); - let lastTrailingComment; - let nextProgramNode; - let nextProgramNodeIndex; - let rawComment; - - function addComments(source) { - comments = comments.concat( source.slice(0) ); - } - - if ( !hasComments(node) && (!node.type || !isBlock) ) { - return true; - } - - comments = isBlock ? [node] : []; - - if (node.leadingComments && node.leadingComments.length) { - addComments(node.leadingComments); - } - - // trailing comments are always duplicates of leading comments unless they're attached to the - // Program node... - if (node.type === Syntax.Program && node.trailingComments && node.trailingComments.length) { - addComments(node.trailingComments); - } - - // ...or if they were comments from the end of the file that were erroneously attached to a - // `'use strict';` declaration (https://github.com/babel/babel/issues/6688). - if (node.type === Syntax.ExpressionStatement && node.directive === 'use strict' && - node.trailingComments && node.trailingComments.length) { - // to be safe, we verify that the trailing comments came after the next node in the Program - // body, which means the comments were attached to the wrong node - if (node.parent.body.length > 1) { - nextProgramNodeIndex = node.parent.body.indexOf(node) + 1; - nextProgramNode = node.parent.body[nextProgramNodeIndex]; - lastTrailingComment = node.trailingComments[node.trailingComments.length - 1]; - - if (lastTrailingComment.start > nextProgramNode.end) { - addComments(node.trailingComments); - } - } - } - - if (node.innerComments && node.innerComments.length) { - addComments(node.innerComments); - } - - for (let comment of comments) { - rawComment = getRawComment(comment); - - if ( isValidJsdoc(rawComment) ) { - e = new JsdocCommentFound(comment, rawComment, filename); - - parser.emit(e.event, e, parser); - - if (e.comment !== rawComment) { - updateCommentNode(comment, e.comment); - } - } - } - - return true; + if (node.innerComments && node.innerComments.length) { + addComments(node.innerComments); } - /* eslint-enable class-methods-use-this */ - // TODO: docs - visitNode(node, parser, filename) { - const e = makeSymbolFoundEvent(node, parser, filename); + for (let comment of comments) { + rawComment = getRawComment(comment); - if (this._nodeVisitors && this._nodeVisitors.length) { - for (let visitor of this._nodeVisitors) { - visitor.visitNode(node, e, parser, filename); - if (e.stopPropagation) { - break; - } - } + if (isValidJsdoc(rawComment)) { + e = new JsdocCommentFound(comment, rawComment, filename); + + parser.emit(e.event, e, parser); + + if (e.comment !== rawComment) { + updateCommentNode(comment, e.comment); } - - if (!e.preventDefault) { - parser.emit(e.event, e, parser); - } - - // add the node to the parser's lookup table - parser.addDocletRef(e); - - for (let finisher of e.finishers) { - finisher.call(parser, e); - } - - return true; + } } + + return true; + } + /* eslint-enable class-methods-use-this */ + + // TODO: docs + visitNode(node, parser, filename) { + const e = makeSymbolFoundEvent(node, parser, filename); + + if (this._nodeVisitors && this._nodeVisitors.length) { + for (let visitor of this._nodeVisitors) { + visitor.visitNode(node, e, parser, filename); + if (e.stopPropagation) { + break; + } + } + } + + if (!e.preventDefault) { + parser.emit(e.event, e, parser); + } + + // add the node to the parser's lookup table + parser.addDocletRef(e); + + for (let finisher of e.finishers) { + finisher.call(parser, e); + } + + return true; + } } exports.Visitor = Visitor; diff --git a/packages/jsdoc/lib/jsdoc/src/walker.js b/packages/jsdoc/lib/jsdoc/src/walker.js index 7414940e..c85adc6e 100644 --- a/packages/jsdoc/lib/jsdoc/src/walker.js +++ b/packages/jsdoc/lib/jsdoc/src/walker.js @@ -9,33 +9,34 @@ const { Syntax } = require('@jsdoc/parse'); // TODO: docs function getCurrentScope(scopes) { - return scopes[scopes.length - 1] || null; + return scopes[scopes.length - 1] || null; } // TODO: docs function moveLeadingComments(source, target, count) { - if (source.leadingComments) { - if (count === undefined) { - count = source.leadingComments.length; - } - - target.leadingComments = source.leadingComments.slice(0, count); - source.leadingComments = source.leadingComments.slice(count); + if (source.leadingComments) { + if (count === undefined) { + count = source.leadingComments.length; } + + target.leadingComments = source.leadingComments.slice(0, count); + source.leadingComments = source.leadingComments.slice(count); + } } // TODO: docs function moveTrailingComments(source, target, count) { - if (source.trailingComments) { - if (count === undefined) { - count = source.trailingComments.length; - } - - target.trailingComments = source.trailingComments.slice( - source.trailingComments.length - count, count - ); - source.trailingComments = source.trailingComments.slice(0); + if (source.trailingComments) { + if (count === undefined) { + count = source.trailingComments.length; } + + target.trailingComments = source.trailingComments.slice( + source.trailingComments.length - count, + count + ); + source.trailingComments = source.trailingComments.slice(0); + } } /* eslint-disable no-empty-function, no-unused-vars */ @@ -43,80 +44,80 @@ function leafNode(node, parent, state, cb) {} /* eslint-enable no-empty-function, no-unused-vars */ // TODO: docs -const walkers = exports.walkers = {}; +const walkers = (exports.walkers = {}); walkers[Syntax.ArrayExpression] = (node, parent, state, cb) => { - for (let element of node.elements) { - if (element) { - cb(element, node, state); - } + for (let element of node.elements) { + if (element) { + cb(element, node, state); } + } }; // TODO: verify correctness walkers[Syntax.ArrayPattern] = (node, parent, state, cb) => { - for (let element of node.elements) { - // must be an identifier or an expression - if (element && element.type !== Syntax.Identifier) { - cb(element, node, state); - } + for (let element of node.elements) { + // must be an identifier or an expression + if (element && element.type !== Syntax.Identifier) { + cb(element, node, state); } + } }; walkers[Syntax.ArrowFunctionExpression] = (node, parent, state, cb) => { - if (node.id) { - cb(node.id, node, state); - } + if (node.id) { + cb(node.id, node, state); + } - for (let param of node.params) { - cb(param, node, state); - } + for (let param of node.params) { + cb(param, node, state); + } - cb(node.body, node, state); + cb(node.body, node, state); }; walkers[Syntax.AssignmentExpression] = (node, parent, state, cb) => { - cb(node.left, node, state); - cb(node.right, node, state); + cb(node.left, node, state); + cb(node.right, node, state); }; walkers[Syntax.AssignmentPattern] = walkers[Syntax.AssignmentExpression]; walkers[Syntax.AwaitExpression] = (node, parent, state, cb) => { - cb(node.argument, node, state); + cb(node.argument, node, state); }; walkers[Syntax.BigIntLiteral] = leafNode; walkers[Syntax.BinaryExpression] = (node, parent, state, cb) => { - cb(node.left, node, state); - cb(node.right, node, state); + cb(node.left, node, state); + cb(node.right, node, state); }; walkers[Syntax.BindExpression] = (node, parent, state, cb) => { - if (node.object) { - cb(node.object, node, state); - } + if (node.object) { + cb(node.object, node, state); + } - cb(node.callee, node, state); + cb(node.callee, node, state); }; walkers[Syntax.BlockStatement] = (node, parent, state, cb) => { - for (let bodyItem of node.body) { - cb(bodyItem, node, state); - } + for (let bodyItem of node.body) { + cb(bodyItem, node, state); + } }; walkers[Syntax.BreakStatement] = leafNode; -walkers[Syntax.CallExpression] = function(node, parent, state, cb) { - cb(node.callee, node, state); +walkers[Syntax.CallExpression] = function (node, parent, state, cb) { + cb(node.callee, node, state); - if (node.arguments) { - for (let arg of node.arguments) { - cb(arg, node, state); - } + if (node.arguments) { + for (let arg of node.arguments) { + cb(arg, node, state); } + } }; walkers[Syntax.CatchClause] = leafNode; @@ -124,23 +125,23 @@ walkers[Syntax.CatchClause] = leafNode; walkers[Syntax.ClassBody] = walkers[Syntax.BlockStatement]; walkers[Syntax.ClassDeclaration] = (node, parent, state, cb) => { - if (node.id) { - cb(node.id, node, state); - } + if (node.id) { + cb(node.id, node, state); + } - if (node.superClass) { - cb(node.superClass, node, state); - } + if (node.superClass) { + cb(node.superClass, node, state); + } - if (node.body) { - cb(node.body, node, state); - } + if (node.body) { + cb(node.body, node, state); + } - if (node.decorators) { - for (let decorator of node.decorators) { - cb(decorator, node, state); - } + if (node.decorators) { + for (let decorator of node.decorators) { + cb(decorator, node, state); } + } }; walkers[Syntax.ClassExpression] = walkers[Syntax.ClassDeclaration]; @@ -154,21 +155,21 @@ walkers[Syntax.ComprehensionBlock] = walkers[Syntax.AssignmentExpression]; // TODO: verify correctness walkers[Syntax.ComprehensionExpression] = (node, parent, state, cb) => { - cb(node.body, node, state); + cb(node.body, node, state); - if (node.filter) { - cb(node.filter, node, state); - } + if (node.filter) { + cb(node.filter, node, state); + } - for (let block of node.blocks) { - cb(block, node, state); - } + for (let block of node.blocks) { + cb(block, node, state); + } }; walkers[Syntax.ConditionalExpression] = (node, parent, state, cb) => { - cb(node.test, node, state); - cb(node.consequent, node, state); - cb(node.alternate, node, state); + cb(node.test, node, state); + cb(node.consequent, node, state); + cb(node.alternate, node, state); }; walkers[Syntax.ContinueStatement] = leafNode; @@ -176,107 +177,107 @@ walkers[Syntax.ContinueStatement] = leafNode; walkers[Syntax.DebuggerStatement] = leafNode; walkers[Syntax.Decorator] = (node, parent, state, cb) => { - cb(node.expression, node, state); + cb(node.expression, node, state); }; walkers[Syntax.DoExpression] = (node, parent, state, cb) => { - cb(node.body, node, state); + cb(node.body, node, state); }; walkers[Syntax.DoWhileStatement] = (node, parent, state, cb) => { - cb(node.test, node, state); - cb(node.body, node, state); + cb(node.test, node, state); + cb(node.body, node, state); }; walkers[Syntax.EmptyStatement] = leafNode; walkers[Syntax.ExperimentalRestProperty] = (node, parent, state, cb) => { - cb(node.argument, node, state); + cb(node.argument, node, state); }; walkers[Syntax.ExperimentalSpreadProperty] = walkers[Syntax.ExperimentalRestProperty]; walkers[Syntax.ExportAllDeclaration] = (node, parent, state, cb) => { - if (node.source) { - cb(node.source, node, state); - } + if (node.source) { + cb(node.source, node, state); + } }; walkers[Syntax.ExportDefaultDeclaration] = (node, parent, state, cb) => { - // if the declaration target is a class, move leading comments to the declaration target - if (node.declaration && node.declaration.type === Syntax.ClassDeclaration) { - moveLeadingComments(node, node.declaration); - } + // if the declaration target is a class, move leading comments to the declaration target + if (node.declaration && node.declaration.type === Syntax.ClassDeclaration) { + moveLeadingComments(node, node.declaration); + } - if (node.declaration) { - cb(node.declaration, node, state); - } + if (node.declaration) { + cb(node.declaration, node, state); + } }; walkers[Syntax.ExportDefaultSpecifier] = (node, parent, state, cb) => { - cb(node.exported, node, state); + cb(node.exported, node, state); }; walkers[Syntax.ExportNamedDeclaration] = (node, parent, state, cb) => { - if (node.declaration) { - cb(node.declaration, node, state); - } + if (node.declaration) { + cb(node.declaration, node, state); + } - for (let specifier of node.specifiers) { - cb(specifier, node, state); - } + for (let specifier of node.specifiers) { + cb(specifier, node, state); + } - if (node.source) { - cb(node.source, node, state); - } + if (node.source) { + cb(node.source, node, state); + } }; walkers[Syntax.ExportNamespaceSpecifier] = (node, parent, state, cb) => { - cb(node.exported, node, state); + cb(node.exported, node, state); }; walkers[Syntax.ExportSpecifier] = (node, parent, state, cb) => { - if (node.exported) { - cb(node.exported, node, state); - } + if (node.exported) { + cb(node.exported, node, state); + } - if (node.local) { - cb(node.local, node, state); - } + if (node.local) { + cb(node.local, node, state); + } }; walkers[Syntax.ExpressionStatement] = (node, parent, state, cb) => { - moveLeadingComments(node, node.expression); + moveLeadingComments(node, node.expression); - cb(node.expression, node, state); + cb(node.expression, node, state); }; walkers[Syntax.File] = (node, parent, state, cb) => { - cb(node.program, node, state); + cb(node.program, node, state); }; walkers[Syntax.ForInStatement] = (node, parent, state, cb) => { - cb(node.left, node, state); - cb(node.right, node, state); - cb(node.body, node, state); + cb(node.left, node, state); + cb(node.right, node, state); + cb(node.body, node, state); }; walkers[Syntax.ForOfStatement] = walkers[Syntax.ForInStatement]; walkers[Syntax.ForStatement] = (node, parent, state, cb) => { - if (node.init) { - cb(node.init, node, state); - } + if (node.init) { + cb(node.init, node, state); + } - if (node.test) { - cb(node.test, node, state); - } + if (node.test) { + cb(node.test, node, state); + } - if (node.update) { - cb(node.update, node, state); - } + if (node.update) { + cb(node.update, node, state); + } - cb(node.body, node, state); + cb(node.body, node, state); }; walkers[Syntax.FunctionDeclaration] = walkers[Syntax.ArrowFunctionExpression]; @@ -286,31 +287,31 @@ walkers[Syntax.FunctionExpression] = walkers[Syntax.ArrowFunctionExpression]; walkers[Syntax.Identifier] = leafNode; walkers[Syntax.IfStatement] = (node, parent, state, cb) => { - cb(node.test, node, state); - cb(node.consequent, node, state); - if (node.alternate) { - cb(node.alternate, node, state); - } + cb(node.test, node, state); + cb(node.consequent, node, state); + if (node.alternate) { + cb(node.alternate, node, state); + } }; walkers[Syntax.Import] = leafNode; walkers[Syntax.ImportDeclaration] = (node, parent, state, cb) => { - if (node.specifiers) { - for (let specifier of node.specifiers) { - cb(specifier, node, state); - } + if (node.specifiers) { + for (let specifier of node.specifiers) { + cb(specifier, node, state); } + } - if (node.source) { - cb(node.source, node, state); - } + if (node.source) { + cb(node.source, node, state); + } }; walkers[Syntax.ImportDefaultSpecifier] = (node, parent, state, cb) => { - if (node.local) { - cb(node.local, node, state); - } + if (node.local) { + cb(node.local, node, state); + } }; walkers[Syntax.ImportNamespaceSpecifier] = walkers[Syntax.ImportDefaultSpecifier]; @@ -318,77 +319,77 @@ walkers[Syntax.ImportNamespaceSpecifier] = walkers[Syntax.ImportDefaultSpecifier walkers[Syntax.ImportSpecifier] = walkers[Syntax.ExportSpecifier]; walkers[Syntax.JSXAttribute] = (node, parent, state, cb) => { - cb(node.name, node, state); + cb(node.name, node, state); - if (node.value) { - cb(node.value, node, state); - } + if (node.value) { + cb(node.value, node, state); + } }; walkers[Syntax.JSXClosingElement] = (node, parent, state, cb) => { - cb(node.name, node, state); + cb(node.name, node, state); }; walkers[Syntax.JSXElement] = (node, parent, state, cb) => { - cb(node.openingElement, node, state); + cb(node.openingElement, node, state); - if (node.closingElement) { - cb(node.closingElement, node, state); - } + if (node.closingElement) { + cb(node.closingElement, node, state); + } - for (let child of node.children) { - cb(child, node, state); - } + for (let child of node.children) { + cb(child, node, state); + } }; walkers[Syntax.JSXEmptyExpression] = leafNode; walkers[Syntax.JSXExpressionContainer] = (node, parent, state, cb) => { - cb(node.expression, node, state); + cb(node.expression, node, state); }; walkers[Syntax.JSXIdentifier] = leafNode; walkers[Syntax.JSXMemberExpression] = (node, parent, state, cb) => { - cb(node.object, node, state); + cb(node.object, node, state); - cb(node.property, node, state); + cb(node.property, node, state); }; walkers[Syntax.JSXNamespacedName] = (node, parent, state, cb) => { - cb(node.namespace, node, state); + cb(node.namespace, node, state); - cb(node.name, node, state); + cb(node.name, node, state); }; walkers[Syntax.JSXOpeningElement] = (node, parent, state, cb) => { - cb(node.name, node, state); + cb(node.name, node, state); - for (let attribute of node.attributes) { - cb(attribute, node, state); - } + for (let attribute of node.attributes) { + cb(attribute, node, state); + } }; walkers[Syntax.JSXSpreadAttribute] = (node, parent, state, cb) => { - cb(node.argument, node, state); + cb(node.argument, node, state); }; walkers[Syntax.JSXText] = leafNode; walkers[Syntax.LabeledStatement] = (node, parent, state, cb) => { - cb(node.body, node, state); + cb(node.body, node, state); }; // TODO: add scope info?? walkers[Syntax.LetStatement] = (node, parent, state, cb) => { - for (let headItem of node.head) { - cb(headItem.id, node, state); - if (headItem.init) { - cb(headItem.init, node, state); - } + for (let headItem of node.head) { + cb(headItem.id, node, state); + if (headItem.init) { + cb(headItem.init, node, state); } + } - cb(node.body, node, state); + cb(node.body, node, state); }; walkers[Syntax.Literal] = leafNode; @@ -396,233 +397,233 @@ walkers[Syntax.Literal] = leafNode; walkers[Syntax.LogicalExpression] = walkers[Syntax.BinaryExpression]; walkers[Syntax.MemberExpression] = (node, parent, state, cb) => { - cb(node.object, node, state); - if (node.property) { - cb(node.property, node, state); - } + cb(node.object, node, state); + if (node.property) { + cb(node.property, node, state); + } }; walkers[Syntax.MetaProperty] = leafNode; walkers[Syntax.MethodDefinition] = (node, parent, state, cb) => { - if (node.key) { - cb(node.key, node, state); - } + if (node.key) { + cb(node.key, node, state); + } - if (node.value) { - cb(node.value, node, state); - } + if (node.value) { + cb(node.value, node, state); + } - if (node.decorators) { - for (let decorator of node.decorators) { - cb(decorator, node, state); - } + if (node.decorators) { + for (let decorator of node.decorators) { + cb(decorator, node, state); } + } }; walkers[Syntax.ModuleDeclaration] = (node, parent, state, cb) => { - if (node.id) { - cb(node.id, node, state); - } + if (node.id) { + cb(node.id, node, state); + } - if (node.source) { - cb(node.source, node, state); - } + if (node.source) { + cb(node.source, node, state); + } - if (node.body) { - cb(node.body, node, state); - } + if (node.body) { + cb(node.body, node, state); + } }; walkers[Syntax.NewExpression] = walkers[Syntax.CallExpression]; walkers[Syntax.ObjectExpression] = (node, parent, state, cb) => { - for (let property of node.properties) { - cb(property, node, state); - } + for (let property of node.properties) { + cb(property, node, state); + } }; walkers[Syntax.ObjectPattern] = walkers[Syntax.ObjectExpression]; walkers[Syntax.PrivateName] = (node, parent, state, cb) => { - cb(node.id, node, state); + cb(node.id, node, state); }; walkers[Syntax.Program] = (node, parent, state, cb) => { - // if the first item in the body has multiple leading comments, move all but the last one to - // this node. this happens, for example, when a file has a /** @module */ standalone comment - // followed by one or more other comments. - if (node.body[0] && node.body[0].leadingComments && node.body[0].leadingComments.length > 1) { - moveLeadingComments(node.body[0], node, node.body[0].leadingComments.length - 1); - } + // if the first item in the body has multiple leading comments, move all but the last one to + // this node. this happens, for example, when a file has a /** @module */ standalone comment + // followed by one or more other comments. + if (node.body[0] && node.body[0].leadingComments && node.body[0].leadingComments.length > 1) { + moveLeadingComments(node.body[0], node, node.body[0].leadingComments.length - 1); + } - // if the last item in the body has trailing comments, move them to this node - if (node.body.length && node.body[node.body.length - 1].trailingComments) { - moveTrailingComments(node.body[node.body.length - 1], node); - } + // if the last item in the body has trailing comments, move them to this node + if (node.body.length && node.body[node.body.length - 1].trailingComments) { + moveTrailingComments(node.body[node.body.length - 1], node); + } - for (let bodyItem of node.body) { - cb(bodyItem, node, state); - } + for (let bodyItem of node.body) { + cb(bodyItem, node, state); + } }; walkers[Syntax.Property] = (node, parent, state, cb) => { - // move leading comments from key to property node - moveLeadingComments(node.key, node); + // move leading comments from key to property node + moveLeadingComments(node.key, node); - if (node.value) { - cb(node.value, node, state); - } + if (node.value) { + cb(node.value, node, state); + } - if (node.decorators) { - for (let decorator of node.decorators) { - cb(decorator, node, state); - } + if (node.decorators) { + for (let decorator of node.decorators) { + cb(decorator, node, state); } + } }; walkers[Syntax.ClassPrivateProperty] = (node, parent, state, cb) => { - // move leading comments from key to property node - moveLeadingComments(node.key, node); + // move leading comments from key to property node + moveLeadingComments(node.key, node); - // add `name` property to key, so we don't have to give this type of node special treatment - // when we resolve its name - node.key.name = node.key.id.name; + // add `name` property to key, so we don't have to give this type of node special treatment + // when we resolve its name + node.key.name = node.key.id.name; - if (node.value) { - cb(node.value, node, state); - } - - if (node.decorators) { - for (let decorator of node.decorators) { - cb(decorator, node, state); - } + if (node.value) { + cb(node.value, node, state); + } + + if (node.decorators) { + for (let decorator of node.decorators) { + cb(decorator, node, state); } + } }; walkers[Syntax.ClassProperty] = walkers[Syntax.Property]; walkers[Syntax.RestElement] = (node, parent, state, cb) => { - if (node.argument) { - cb(node.argument, node, state); - } + if (node.argument) { + cb(node.argument, node, state); + } }; walkers[Syntax.ReturnStatement] = (node, parent, state, cb) => { - if (node.argument) { - cb(node.argument, node, state); - } + if (node.argument) { + cb(node.argument, node, state); + } }; walkers[Syntax.SequenceExpression] = (node, parent, state, cb) => { - for (let expression of node.expressions) { - cb(expression, node, state); - } + for (let expression of node.expressions) { + cb(expression, node, state); + } }; walkers[Syntax.SpreadElement] = (node, parent, state, cb) => { - if (node.argument) { - cb(node.argument, node, state); - } + if (node.argument) { + cb(node.argument, node, state); + } }; walkers[Syntax.Super] = leafNode; walkers[Syntax.SwitchCase] = (node, parent, state, cb) => { - if (node.test) { - cb(node.test, node, state); - } + if (node.test) { + cb(node.test, node, state); + } - for (let consequentItem of node.consequent) { - cb(consequentItem, node, state); - } + for (let consequentItem of node.consequent) { + cb(consequentItem, node, state); + } }; walkers[Syntax.SwitchStatement] = (node, parent, state, cb) => { - cb(node.discriminant, node, state); + cb(node.discriminant, node, state); - for (let caseItem of node.cases) { - cb(caseItem, node, state); - } + for (let caseItem of node.cases) { + cb(caseItem, node, state); + } }; walkers[Syntax.TaggedTemplateExpression] = (node, parent, state, cb) => { - if (node.tag) { - cb(node.tag, node, state); - } - if (node.quasi) { - cb(node.quasi, node, state); - } + if (node.tag) { + cb(node.tag, node, state); + } + if (node.quasi) { + cb(node.quasi, node, state); + } }; walkers[Syntax.TemplateElement] = leafNode; walkers[Syntax.TemplateLiteral] = (node, parent, state, cb) => { - if (node.quasis && node.quasis.length) { - for (let quasi of node.quasis) { - cb(quasi, node, state); - } + if (node.quasis && node.quasis.length) { + for (let quasi of node.quasis) { + cb(quasi, node, state); } + } - if (node.expressions && node.expressions.length) { - for (let expression of node.expressions) { - cb(expression, node, state); - } + if (node.expressions && node.expressions.length) { + for (let expression of node.expressions) { + cb(expression, node, state); } + } }; walkers[Syntax.ThisExpression] = leafNode; walkers[Syntax.ThrowStatement] = (node, parent, state, cb) => { - cb(node.argument, node, state); + cb(node.argument, node, state); }; walkers[Syntax.TryStatement] = (node, parent, state, cb) => { - cb(node.block, node, state); + cb(node.block, node, state); - if (node.handler) { - cb(node.handler.body, node, state); - } + if (node.handler) { + cb(node.handler.body, node, state); + } - if (node.finalizer) { - cb(node.finalizer, node, state); - } + if (node.finalizer) { + cb(node.finalizer, node, state); + } }; walkers[Syntax.UnaryExpression] = (node, parent, state, cb) => { - cb(node.argument, node, state); + cb(node.argument, node, state); }; walkers[Syntax.UpdateExpression] = walkers[Syntax.UnaryExpression]; walkers[Syntax.VariableDeclaration] = (node, parent, state, cb) => { - // move leading comments to first declarator - moveLeadingComments(node, node.declarations[0]); + // move leading comments to first declarator + moveLeadingComments(node, node.declarations[0]); - for (let declaration of node.declarations) { - cb(declaration, node, state); - } + for (let declaration of node.declarations) { + cb(declaration, node, state); + } }; walkers[Syntax.VariableDeclarator] = (node, parent, state, cb) => { - cb(node.id, node, state); + cb(node.id, node, state); - if (node.init) { - cb(node.init, node, state); - } + if (node.init) { + cb(node.init, node, state); + } }; walkers[Syntax.WhileStatement] = walkers[Syntax.DoWhileStatement]; walkers[Syntax.WithStatement] = (node, parent, state, cb) => { - cb(node.object, node, state); - cb(node.body, node, state); + cb(node.object, node, state); + cb(node.body, node, state); }; walkers[Syntax.YieldExpression] = (node, parent, state, cb) => { - if (node.argument) { - cb(node.argument, node, state); - } + if (node.argument) { + cb(node.argument, node, state); + } }; /** @@ -631,76 +632,75 @@ walkers[Syntax.YieldExpression] = (node, parent, state, cb) => { * @memberof module:jsdoc/src/walker */ class Walker { - // TODO: docs - constructor(walkerFuncs = walkers) { - this._walkers = walkerFuncs; + // TODO: docs + constructor(walkerFuncs = walkers) { + this._walkers = walkerFuncs; + } + + // TODO: docs + _recurse(filename, ast) { + const self = this; + const state = { + filename: filename, + nodes: [], + scopes: [], + }; + + function logUnknownNodeType({ type }) { + log.debug( + `Found a node with unrecognized type ${type}. Ignoring the node and its ` + 'descendants.' + ); } - // TODO: docs - _recurse(filename, ast) { - const self = this; - const state = { - filename: filename, - nodes: [], - scopes: [] - }; + function cb(node, parent, cbState) { + let currentScope; - function logUnknownNodeType({type}) { - log.debug( - `Found a node with unrecognized type ${type}. Ignoring the node and its ` + - 'descendants.' - ); - } + const isScope = astNode.isScope(node); - function cb(node, parent, cbState) { - let currentScope; + astNode.addNodeProperties(node); + node.parent = parent || null; - const isScope = astNode.isScope(node); + currentScope = getCurrentScope(cbState.scopes); + if (currentScope) { + node.enclosingScope = currentScope; + } - astNode.addNodeProperties(node); - node.parent = parent || null; + if (isScope) { + cbState.scopes.push(node); + } + cbState.nodes.push(node); - currentScope = getCurrentScope(cbState.scopes); - if (currentScope) { - node.enclosingScope = currentScope; - } + if (!self._walkers[node.type]) { + logUnknownNodeType(node); + } else { + self._walkers[node.type](node, parent, cbState, cb); + } - if (isScope) { - cbState.scopes.push(node); - } - cbState.nodes.push(node); - - if (!self._walkers[node.type]) { - logUnknownNodeType(node); - } else { - self._walkers[node.type](node, parent, cbState, cb); - } - - if (isScope) { - cbState.scopes.pop(); - } - } - - cb(ast, null, state); - - return state; + if (isScope) { + cbState.scopes.pop(); + } } - // TODO: docs - recurse(ast, visitor, filename) { - let shouldContinue; - const state = this._recurse(filename, ast); + cb(ast, null, state); - if (visitor) { - for (let node of state.nodes) { - shouldContinue = visitor.visit(node, filename); - if (!shouldContinue) { - break; - } - } + return state; + } + + // TODO: docs + recurse(ast, visitor, filename) { + let shouldContinue; + const state = this._recurse(filename, ast); + + if (visitor) { + for (let node of state.nodes) { + shouldContinue = visitor.visit(node, filename); + if (!shouldContinue) { + break; } - - return ast; + } } + + return ast; + } } exports.Walker = Walker; diff --git a/packages/jsdoc/lib/jsdoc/tag.js b/packages/jsdoc/lib/jsdoc/tag.js index 30c1f233..1cdc733c 100644 --- a/packages/jsdoc/lib/jsdoc/tag.js +++ b/packages/jsdoc/lib/jsdoc/tag.js @@ -6,115 +6,115 @@ const env = require('jsdoc/env'); const { log } = require('@jsdoc/util'); const path = require('path'); const tag = { - dictionary: require('jsdoc/tag/dictionary'), - validator: require('jsdoc/tag/validator'), - type: require('@jsdoc/tag').type + dictionary: require('jsdoc/tag/dictionary'), + validator: require('jsdoc/tag/validator'), + type: require('@jsdoc/tag').type, }; // Check whether the text is the same as a symbol name with leading or trailing whitespace. If so, // the whitespace must be preserved, and the text cannot be trimmed. function mustPreserveWhitespace(text, meta) { - return meta && meta.code && meta.code.name === text && text.match(/(?:^\s+)|(?:\s+$)/); + return meta && meta.code && meta.code.name === text && text.match(/(?:^\s+)|(?:\s+$)/); } function trim(text, opts, meta) { - let indentMatcher; - let match; + let indentMatcher; + let match; - opts = opts || {}; - text = String(typeof text === 'undefined' ? '' : text); + opts = opts || {}; + text = String(typeof text === 'undefined' ? '' : text); - if ( mustPreserveWhitespace(text, meta) ) { - text = `"${text}"`; - } - else if (opts.keepsWhitespace) { - text = text.replace(/^[\n\r\f]+|[\n\r\f]+$/g, ''); - if (opts.removesIndent) { - match = text.match(/^([ \t]+)/); - if (match && match[1]) { - indentMatcher = new RegExp(`^${match[1]}`, 'gm'); - text = text.replace(indentMatcher, ''); - } - } - } - else { - text = text.replace(/^\s+|\s+$/g, ''); + if (mustPreserveWhitespace(text, meta)) { + text = `"${text}"`; + } else if (opts.keepsWhitespace) { + text = text.replace(/^[\n\r\f]+|[\n\r\f]+$/g, ''); + if (opts.removesIndent) { + match = text.match(/^([ \t]+)/); + if (match && match[1]) { + indentMatcher = new RegExp(`^${match[1]}`, 'gm'); + text = text.replace(indentMatcher, ''); + } } + } else { + text = text.replace(/^\s+|\s+$/g, ''); + } - return text; + return text; } function addHiddenProperty(obj, propName, propValue) { - Object.defineProperty(obj, propName, { - value: propValue, - writable: true, - enumerable: Boolean(env.opts.debug), - configurable: true - }); + Object.defineProperty(obj, propName, { + value: propValue, + writable: true, + enumerable: Boolean(env.opts.debug), + configurable: true, + }); } -function parseType({text, originalTitle}, {canHaveName, canHaveType}, meta) { - try { - return tag.type.parse(text, canHaveName, canHaveType); - } - catch (e) { - log.error( - 'Unable to parse a tag\'s type expression%s with tag title "%s" and text "%s": %s', - meta.filename ? ( ` for source file ${path.join(meta.path, meta.filename)}${meta.lineno ? (` in line ${meta.lineno}`) : ''}` ) : '', - originalTitle, - text, - e.message - ); +function parseType({ text, originalTitle }, { canHaveName, canHaveType }, meta) { + try { + return tag.type.parse(text, canHaveName, canHaveType); + } catch (e) { + log.error( + 'Unable to parse a tag\'s type expression%s with tag title "%s" and text "%s": %s', + meta.filename + ? ` for source file ${path.join(meta.path, meta.filename)}${ + meta.lineno ? ` in line ${meta.lineno}` : '' + }` + : '', + originalTitle, + text, + e.message + ); - return {}; - } + return {}; + } } function processTagText(tagInstance, tagDef, meta) { - let tagType; + let tagType; - if (tagDef.onTagText) { - tagInstance.text = tagDef.onTagText(tagInstance.text); + if (tagDef.onTagText) { + tagInstance.text = tagDef.onTagText(tagInstance.text); + } + + if (tagDef.canHaveType || tagDef.canHaveName) { + /** The value property represents the result of parsing the tag text. */ + tagInstance.value = {}; + + tagType = parseType(tagInstance, tagDef, meta); + + // It is possible for a tag to *not* have a type but still have + // optional or defaultvalue, e.g. '@param [foo]'. + // Although tagType.type.length == 0 we should still copy the other properties. + if (tagType.type) { + if (tagType.type.length) { + tagInstance.value.type = { + names: tagType.type, + }; + addHiddenProperty(tagInstance.value.type, 'parsedType', tagType.parsedType); + } + + ['optional', 'nullable', 'variable', 'defaultvalue'].forEach((prop) => { + if (typeof tagType[prop] !== 'undefined') { + tagInstance.value[prop] = tagType[prop]; + } + }); } - if (tagDef.canHaveType || tagDef.canHaveName) { - /** The value property represents the result of parsing the tag text. */ - tagInstance.value = {}; - - tagType = parseType(tagInstance, tagDef, meta); - - // It is possible for a tag to *not* have a type but still have - // optional or defaultvalue, e.g. '@param [foo]'. - // Although tagType.type.length == 0 we should still copy the other properties. - if (tagType.type) { - if (tagType.type.length) { - tagInstance.value.type = { - names: tagType.type - }; - addHiddenProperty(tagInstance.value.type, 'parsedType', tagType.parsedType); - } - - ['optional', 'nullable', 'variable', 'defaultvalue'].forEach(prop => { - if (typeof tagType[prop] !== 'undefined') { - tagInstance.value[prop] = tagType[prop]; - } - }); - } - - if (tagType.text && tagType.text.length) { - tagInstance.value.description = tagType.text; - } - - if (tagDef.canHaveName) { - // note the dash is a special case: as a param name it means "no name" - if (tagType.name && tagType.name !== '-') { - tagInstance.value.name = tagType.name; - } - } + if (tagType.text && tagType.text.length) { + tagInstance.value.description = tagType.text; } - else { - tagInstance.value = tagInstance.text; + + if (tagDef.canHaveName) { + // note the dash is a special case: as a param name it means "no name" + if (tagType.name && tagType.name !== '-') { + tagInstance.value.name = tagType.name; + } } + } else { + tagInstance.value = tagInstance.text; + } } /** @@ -127,62 +127,62 @@ function processTagText(tagInstance, tagDef, meta) { * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. */ exports._replaceDictionary = function _replaceDictionary(dict) { - tag.dictionary = dict; + tag.dictionary = dict; }; /** * Represents a single doclet tag. */ class Tag { + /** + * Constructs a new tag object. Calls the tag validator. + * + * @param {string} tagTitle + * @param {string=} tagBody + * @param {object=} meta + */ + constructor(tagTitle, tagBody, meta) { + let tagDef; + let trimOpts; + + meta = meta || {}; + + this.originalTitle = trim(tagTitle); + + /** The title of the tag (for example, `title` in `@title text`). */ + this.title = tag.dictionary.normalize(this.originalTitle); + + tagDef = tag.dictionary.lookUp(this.title); + trimOpts = { + keepsWhitespace: tagDef.keepsWhitespace, + removesIndent: tagDef.removesIndent, + }; + /** - * Constructs a new tag object. Calls the tag validator. + * The text following the tag (for example, `text` in `@title text`). * - * @param {string} tagTitle - * @param {string=} tagBody - * @param {object=} meta + * Whitespace is trimmed from the tag text as follows: + * + * + If the tag's `keepsWhitespace` option is falsy, all leading and trailing whitespace are + * removed. + * + If the tag's `keepsWhitespace` option is set to `true`, leading and trailing whitespace are + * not trimmed, unless the `removesIndent` option is also enabled. + * + If the tag's `removesIndent` option is set to `true`, any indentation that is shared by + * every line in the string is removed. This option is ignored unless `keepsWhitespace` is set + * to `true`. + * + * **Note**: If the tag text is the name of a symbol, and the symbol's name includes leading or + * trailing whitespace (for example, the property names in `{ ' ': true, ' foo ': false }`), + * the tag text is not trimmed. Instead, the tag text is wrapped in double quotes to prevent the + * whitespace from being trimmed. */ - constructor(tagTitle, tagBody, meta) { - let tagDef; - let trimOpts; + this.text = trim(tagBody, trimOpts, meta); - meta = meta || {}; - - this.originalTitle = trim(tagTitle); - - /** The title of the tag (for example, `title` in `@title text`). */ - this.title = tag.dictionary.normalize(this.originalTitle); - - tagDef = tag.dictionary.lookUp(this.title); - trimOpts = { - keepsWhitespace: tagDef.keepsWhitespace, - removesIndent: tagDef.removesIndent - }; - - /** - * The text following the tag (for example, `text` in `@title text`). - * - * Whitespace is trimmed from the tag text as follows: - * - * + If the tag's `keepsWhitespace` option is falsy, all leading and trailing whitespace are - * removed. - * + If the tag's `keepsWhitespace` option is set to `true`, leading and trailing whitespace are - * not trimmed, unless the `removesIndent` option is also enabled. - * + If the tag's `removesIndent` option is set to `true`, any indentation that is shared by - * every line in the string is removed. This option is ignored unless `keepsWhitespace` is set - * to `true`. - * - * **Note**: If the tag text is the name of a symbol, and the symbol's name includes leading or - * trailing whitespace (for example, the property names in `{ ' ': true, ' foo ': false }`), - * the tag text is not trimmed. Instead, the tag text is wrapped in double quotes to prevent the - * whitespace from being trimmed. - */ - this.text = trim(tagBody, trimOpts, meta); - - if (this.text) { - processTagText(this, tagDef, meta); - } - - tag.validator.validate(this, tagDef, meta); + if (this.text) { + processTagText(this, tagDef, meta); } + + tag.validator.validate(this, tagDef, meta); + } } exports.Tag = Tag; diff --git a/packages/jsdoc/lib/jsdoc/tag/dictionary.js b/packages/jsdoc/lib/jsdoc/tag/dictionary.js index 14f4a5e8..ffa41b87 100644 --- a/packages/jsdoc/lib/jsdoc/tag/dictionary.js +++ b/packages/jsdoc/lib/jsdoc/tag/dictionary.js @@ -6,168 +6,171 @@ const { log } = require('@jsdoc/util'); const hasOwnProp = Object.prototype.hasOwnProperty; const DEFINITIONS = { - closure: 'closureTags', - jsdoc: 'jsdocTags' + closure: 'closureTags', + jsdoc: 'jsdocTags', }; let dictionary; /** @private */ class TagDefinition { - constructor(dict, title, etc) { - const self = this; + constructor(dict, title, etc) { + const self = this; - etc = etc || {}; + etc = etc || {}; - this.title = dict.normalize(title); + this.title = dict.normalize(title); - Object.defineProperty(this, '_dictionary', { - value: dict - }); + Object.defineProperty(this, '_dictionary', { + value: dict, + }); - Object.keys(etc).forEach(p => { - self[p] = etc[p]; - }); - } + Object.keys(etc).forEach((p) => { + self[p] = etc[p]; + }); + } - /** @private */ - synonym(synonymName) { - this._dictionary.defineSynonym(this.title, synonymName); + /** @private */ + synonym(synonymName) { + this._dictionary.defineSynonym(this.title, synonymName); - return this; - } + return this; + } } /** * @alias module:jsdoc/tag/dictionary.Dictionary */ class Dictionary { - constructor() { - // TODO: Consider adding internal tags in the constructor, ideally as fallbacks that aren't - // used to confirm whether a tag is defined/valid, rather than requiring every set of tag - // definitions to contain the internal tags. - this._tags = {}; - this._tagSynonyms = {}; - // The longnames for `Package` objects include a `package` namespace. There's no `package` - // tag, though, so we declare the namespace here. - // TODO: Consider making this a fallback as suggested above for internal tags. - this._namespaces = ['package']; + constructor() { + // TODO: Consider adding internal tags in the constructor, ideally as fallbacks that aren't + // used to confirm whether a tag is defined/valid, rather than requiring every set of tag + // definitions to contain the internal tags. + this._tags = {}; + this._tagSynonyms = {}; + // The longnames for `Package` objects include a `package` namespace. There's no `package` + // tag, though, so we declare the namespace here. + // TODO: Consider making this a fallback as suggested above for internal tags. + this._namespaces = ['package']; + } + + _defineNamespace(title) { + title = this.normalize(title || ''); + + if (title && !this._namespaces.includes(title)) { + this._namespaces.push(title); } - _defineNamespace(title) { - title = this.normalize(title || ''); + return this; + } - if (title && !this._namespaces.includes(title)) { - this._namespaces.push(title); - } + defineTag(title, opts) { + const tagDef = new TagDefinition(this, title, opts); - return this; + this._tags[tagDef.title] = tagDef; + + if (tagDef.isNamespace) { + this._defineNamespace(tagDef.title); + } + if (tagDef.synonyms) { + tagDef.synonyms.forEach((synonym) => { + this.defineSynonym(title, synonym); + }); } - defineTag(title, opts) { - const tagDef = new TagDefinition(this, title, opts); + return this._tags[tagDef.title]; + } - this._tags[tagDef.title] = tagDef; + defineTags(tagDefs) { + const tags = {}; - if (tagDef.isNamespace) { - this._defineNamespace(tagDef.title); - } - if (tagDef.synonyms) { - tagDef.synonyms.forEach(synonym => { - this.defineSynonym(title, synonym); - }); - } - - return this._tags[tagDef.title]; + for (const title of Object.keys(tagDefs)) { + tags[title] = this.defineTag(title, tagDefs[title]); } - defineTags(tagDefs) { - const tags = {}; + return tags; + } - for (const title of Object.keys(tagDefs)) { - tags[title] = this.defineTag(title, tagDefs[title]); - } + defineSynonym(title, synonym) { + this._tagSynonyms[synonym.toLowerCase()] = this.normalize(title); + } - return tags; - } + static fromConfig(env) { + let dictionaries = env.conf.tags.dictionaries; + const dict = new Dictionary(); - defineSynonym(title, synonym) { - this._tagSynonyms[synonym.toLowerCase()] = this.normalize(title); - } + if (!dictionaries) { + log.error( + 'The configuration setting "tags.dictionaries" is undefined. ' + + 'Unable to load tag definitions.' + ); + } else { + dictionaries + .slice() + .reverse() + .forEach((dictName) => { + const tagDefs = definitions[DEFINITIONS[dictName]]; - static fromConfig(env) { - let dictionaries = env.conf.tags.dictionaries; - const dict = new Dictionary(); - - if (!dictionaries) { + if (!tagDefs) { log.error( - 'The configuration setting "tags.dictionaries" is undefined. ' + - 'Unable to load tag definitions.' + 'The configuration setting "tags.dictionaries" contains ' + + `the unknown dictionary name ${dictName}. Ignoring the dictionary.` ); - } else { - dictionaries.slice().reverse().forEach(dictName => { - const tagDefs = definitions[DEFINITIONS[dictName]]; - if (!tagDefs) { - log.error( - 'The configuration setting "tags.dictionaries" contains ' + - `the unknown dictionary name ${dictName}. Ignoring the dictionary.` - ); + return; + } - return; - } + dict.defineTags(tagDefs); + }); - dict.defineTags(tagDefs); - }); - - dict.defineTags(definitions.internalTags); - } - - return dict; + dict.defineTags(definitions.internalTags); } - getNamespaces() { - return this._namespaces.slice(); + return dict; + } + + getNamespaces() { + return this._namespaces.slice(); + } + + isNamespace(kind) { + if (kind) { + kind = this.normalize(kind); + if (this._namespaces.includes(kind)) { + return true; + } } - isNamespace(kind) { - if (kind) { - kind = this.normalize(kind); - if (this._namespaces.includes(kind)) { - return true; - } - } + return false; + } - return false; + lookup(title) { + title = this.normalize(title); + + if (hasOwnProp.call(this._tags, title)) { + return this._tags[title]; } - lookup(title) { - title = this.normalize(title); + return false; + } - if ( hasOwnProp.call(this._tags, title) ) { - return this._tags[title]; - } + lookUp(title) { + return this.lookup(title); + } - return false; + normalise(title) { + return this.normalize(title); + } + + normalize(title) { + const canonicalName = title.toLowerCase(); + + if (hasOwnProp.call(this._tagSynonyms, canonicalName)) { + return this._tagSynonyms[canonicalName]; } - lookUp(title) { - return this.lookup(title); - } - - normalise(title) { - return this.normalize(title); - } - - normalize(title) { - const canonicalName = title.toLowerCase(); - - if ( hasOwnProp.call(this._tagSynonyms, canonicalName) ) { - return this._tagSynonyms[canonicalName]; - } - - return canonicalName; - } + return canonicalName; + } } // initialize the default dictionary diff --git a/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js b/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js index 5f7649b9..77ce875a 100644 --- a/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js +++ b/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js @@ -17,839 +17,831 @@ const hasOwnProp = Object.prototype.hasOwnProperty; const MODULE_NAMESPACE = 'module:'; const NOOP_TAG = { - onTagged: () => { - // Do nothing. - } + onTagged: () => { + // Do nothing. + }, }; // Clone a tag definition, excluding synonyms. function cloneTagDef(tagDef, extras) { - const newTagDef = _.cloneDeep(tagDef); + const newTagDef = _.cloneDeep(tagDef); - delete newTagDef.synonyms; + delete newTagDef.synonyms; - return (extras ? _.extend(newTagDef, extras) : newTagDef); + return extras ? _.extend(newTagDef, extras) : newTagDef; } function getSourcePaths() { - const sourcePaths = env.sourceFiles.slice(0) || []; + const sourcePaths = env.sourceFiles.slice(0) || []; - if (env.opts._) { - env.opts._.forEach(sourcePath => { - const resolved = path.resolve(process.cwd(), sourcePath); + if (env.opts._) { + env.opts._.forEach((sourcePath) => { + const resolved = path.resolve(process.cwd(), sourcePath); - if (!sourcePaths.includes(resolved)) { - sourcePaths.push(resolved); - } - }); - } + if (!sourcePaths.includes(resolved)) { + sourcePaths.push(resolved); + } + }); + } - return sourcePaths; + return sourcePaths; } function filepathMinusPrefix(filepath) { - let commonPrefix; - const sourcePaths = getSourcePaths(); - let result = ''; + let commonPrefix; + const sourcePaths = getSourcePaths(); + let result = ''; - commonPrefix = sourcePaths.length > 1 ? - commonPathPrefix(sourcePaths) : - path.dirname(sourcePaths[0] || '') + path.sep; + commonPrefix = + sourcePaths.length > 1 + ? commonPathPrefix(sourcePaths) + : path.dirname(sourcePaths[0] || '') + path.sep; - if (filepath) { - filepath = path.normalize(filepath); - // always use forward slashes in the result - result = (filepath + path.sep).replace(commonPrefix, '') - .replace(/\\/g, '/'); - } + if (filepath) { + filepath = path.normalize(filepath); + // always use forward slashes in the result + result = (filepath + path.sep).replace(commonPrefix, '').replace(/\\/g, '/'); + } - if (result.length > 0 && result[result.length - 1] !== '/') { - result += '/'; - } + if (result.length > 0 && result[result.length - 1] !== '/') { + result += '/'; + } - return result; + return result; } /** @private */ -function setDocletKindToTitle(doclet, {title}) { - doclet.addTag( 'kind', title ); +function setDocletKindToTitle(doclet, { title }) { + doclet.addTag('kind', title); } -function setDocletScopeToTitle(doclet, {title}) { - try { - doclet.setScope(title); - } - catch (e) { - log.error(e.message); - } +function setDocletScopeToTitle(doclet, { title }) { + try { + doclet.setScope(title); + } catch (e) { + log.error(e.message); + } } -function setDocletNameToValue(doclet, {value, text}) { - if (value && value.description) { // as in a long tag - doclet.addTag('name', value.description); - } - else if (text) { // or a short tag - doclet.addTag('name', text); - } +function setDocletNameToValue(doclet, { value, text }) { + if (value && value.description) { + // as in a long tag + doclet.addTag('name', value.description); + } else if (text) { + // or a short tag + doclet.addTag('name', text); + } } -function setDocletNameToValueName(doclet, {value}) { - if (value && value.name) { - doclet.addTag('name', value.name); - } +function setDocletNameToValueName(doclet, { value }) { + if (value && value.name) { + doclet.addTag('name', value.name); + } } -function setDocletDescriptionToValue(doclet, {value}) { - if (value) { - doclet.addTag('description', value); - } +function setDocletDescriptionToValue(doclet, { value }) { + if (value) { + doclet.addTag('description', value); + } } -function setDocletTypeToValueType(doclet, {value}) { - if (value && value.type) { - // Add the type names and other type properties (such as `optional`). - // Don't overwrite existing properties. - Object.keys(value).forEach(prop => { - if ( !hasOwnProp.call(doclet, prop) ) { - doclet[prop] = value[prop]; - } - }); - } +function setDocletTypeToValueType(doclet, { value }) { + if (value && value.type) { + // Add the type names and other type properties (such as `optional`). + // Don't overwrite existing properties. + Object.keys(value).forEach((prop) => { + if (!hasOwnProp.call(doclet, prop)) { + doclet[prop] = value[prop]; + } + }); + } } function setNameToFile(doclet) { - let docletName; + let docletName; - if (doclet.meta.filename) { - docletName = filepathMinusPrefix(doclet.meta.path) + doclet.meta.filename; - doclet.addTag('name', docletName); - } + if (doclet.meta.filename) { + docletName = filepathMinusPrefix(doclet.meta.path) + doclet.meta.filename; + doclet.addTag('name', docletName); + } } -function setDocletMemberof(doclet, {value}) { - if (value && value !== '') { - doclet.setMemberof(value); - } +function setDocletMemberof(doclet, { value }) { + if (value && value !== '') { + doclet.setMemberof(value); + } } function applyNamespaceToTag(docletOrNs, tag) { - if (typeof docletOrNs === 'string') { // ns - tag.value = applyNamespace(tag.value, docletOrNs); + if (typeof docletOrNs === 'string') { + // ns + tag.value = applyNamespace(tag.value, docletOrNs); + } else { + // doclet + if (!docletOrNs.name) { + return; // error? } - else { // doclet - if (!docletOrNs.name) { - return; // error? - } - docletOrNs.longname = applyNamespace(docletOrNs.name, tag.title); - } + docletOrNs.longname = applyNamespace(docletOrNs.name, tag.title); + } } function setDocletNameToFilename(doclet) { - let docletName = ''; + let docletName = ''; - if (doclet.meta.path) { - docletName = filepathMinusPrefix(doclet.meta.path); - } - docletName += doclet.meta.filename.replace(/\.js$/i, ''); + if (doclet.meta.path) { + docletName = filepathMinusPrefix(doclet.meta.path); + } + docletName += doclet.meta.filename.replace(/\.js$/i, ''); - doclet.name = docletName; + doclet.name = docletName; } function parseTypeText(text) { - const tagType = parseTagType(text, false, true); + const tagType = parseTagType(text, false, true); - return tagType.typeExpression || text; + return tagType.typeExpression || text; } -function parseBorrows(doclet, {text}) { - const m = /^([\s\S]+?)(?:\s+as\s+([\s\S]+))?$/.exec(text); +function parseBorrows(doclet, { text }) { + const m = /^([\s\S]+?)(?:\s+as\s+([\s\S]+))?$/.exec(text); - if (m) { - if (m[1] && m[2]) { - return { - target: m[1], - source: m[2] - }; - } - else if (m[1]) { - return { - target: m[1] - }; - } - - return {}; - } else { - return {}; + if (m) { + if (m[1] && m[2]) { + return { + target: m[1], + source: m[2], + }; + } else if (m[1]) { + return { + target: m[1], + }; } + + return {}; + } else { + return {}; + } } function stripModuleNamespace(docletName) { - return docletName.replace(/^module:/, ''); + return docletName.replace(/^module:/, ''); } function firstWordOf(string) { - const m = /^(\S+)/.exec(string); + const m = /^(\S+)/.exec(string); - if (m) { - return m[1]; - } - else { - return ''; - } + if (m) { + return m[1]; + } else { + return ''; + } } -function combineTypes({value}) { - let combined; +function combineTypes({ value }) { + let combined; - if (value && value.type) { - if (value.type.names.length === 1) { - combined = value.type.names[0]; - } - else { - combined = `(${value.type.names.join('|')})`; - } + if (value && value.type) { + if (value.type.names.length === 1) { + combined = value.type.names[0]; + } else { + combined = `(${value.type.names.join('|')})`; } + } - return combined; + return combined; } // Tags that JSDoc uses internally, and that must always be defined. -const internalTags = exports.internalTags = { - // Special separator tag indicating that multiple doclets should be generated for the same - // comment. Used internally (and by some JSDoc users, although it's not officially supported). - // In the following example, the parser will replace `//**` with an `@also` tag: - // /** - // * Foo. - // *//** - // * Foo with a param. - // * @param {string} bar - // */ - // function foo(bar) {} - also: { - onTagged() { - // let the parser handle it; we define the tag here to avoid "not a known tag" errors - } +const internalTags = (exports.internalTags = { + // Special separator tag indicating that multiple doclets should be generated for the same + // comment. Used internally (and by some JSDoc users, although it's not officially supported). + // In the following example, the parser will replace `//**` with an `@also` tag: + // /** + // * Foo. + // *//** + // * Foo with a param. + // * @param {string} bar + // */ + // function foo(bar) {} + also: { + onTagged() { + // let the parser handle it; we define the tag here to avoid "not a known tag" errors }, - description: { - mustHaveValue: true, - onTagged: (doclet, {value}) => { - doclet.description = value; - }, - synonyms: ['desc'] + }, + description: { + mustHaveValue: true, + onTagged: (doclet, { value }) => { + doclet.description = value; }, - kind: { - mustHaveValue: true, - onTagged: (doclet, {value}) => { - doclet.kind = value; - } + synonyms: ['desc'], + }, + kind: { + mustHaveValue: true, + onTagged: (doclet, { value }) => { + doclet.kind = value; }, - name: { - mustHaveValue: true, - onTagged: (doclet, {value}) => { - doclet.name = value; - } + }, + name: { + mustHaveValue: true, + onTagged: (doclet, { value }) => { + doclet.name = value; }, - undocumented: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.undocumented = true; - doclet.comment = ''; - } - } -}; + }, + undocumented: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.undocumented = true; + doclet.comment = ''; + }, + }, +}); // Core JSDoc tags that are shared with other tag dictionaries. -let baseTags = exports.baseTags = { - abstract: { - mustNotHaveValue: true, - onTagged(doclet) { - // we call this `virtual` because `abstract` is a reserved word - doclet.virtual = true; - }, - synonyms: ['virtual'] +let baseTags = (exports.baseTags = { + abstract: { + mustNotHaveValue: true, + onTagged(doclet) { + // we call this `virtual` because `abstract` is a reserved word + doclet.virtual = true; }, - access: { - mustHaveValue: true, - onTagged(doclet, {value}) { - // only valid values are package, private, protected and public - if ( /^(package|private|protected|public)$/i.test(value) ) { - doclet.access = value.toLowerCase(); - } - else { - delete doclet.access; - } - } + synonyms: ['virtual'], + }, + access: { + mustHaveValue: true, + onTagged(doclet, { value }) { + // only valid values are package, private, protected and public + if (/^(package|private|protected|public)$/i.test(value)) { + doclet.access = value.toLowerCase(); + } else { + delete doclet.access; + } }, - alias: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.alias = value; - } + }, + alias: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.alias = value; }, - async: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.async = true; - } + }, + async: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.async = true; }, - augments: { - mustHaveValue: true, - // Allow augments value to be specified as a normal type, e.g. {Type} - onTagText: parseTypeText, - onTagged(doclet, {value}) { - doclet.augment( firstWordOf(value) ); - }, - synonyms: ['extends'] + }, + augments: { + mustHaveValue: true, + // Allow augments value to be specified as a normal type, e.g. {Type} + onTagText: parseTypeText, + onTagged(doclet, { value }) { + doclet.augment(firstWordOf(value)); }, - author: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.author = doclet.author || []; - doclet.author.push(value); - } + synonyms: ['extends'], + }, + author: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.author = doclet.author || []; + doclet.author.push(value); }, - // this symbol has a member that should use the same docs as another symbol - borrows: { - mustHaveValue: true, - onTagged(doclet, tag) { - const borrows = parseBorrows(doclet, tag); + }, + // this symbol has a member that should use the same docs as another symbol + borrows: { + mustHaveValue: true, + onTagged(doclet, tag) { + const borrows = parseBorrows(doclet, tag); - doclet.borrow(borrows.target, borrows.source); - } + doclet.borrow(borrows.target, borrows.source); }, - class: { - onTagged(doclet, tag) { - let looksLikeDesc; + }, + class: { + onTagged(doclet, tag) { + let looksLikeDesc; - doclet.addTag('kind', 'class'); + doclet.addTag('kind', 'class'); - // handle special case where both @class and @constructor tags exist in same doclet - if (tag.originalTitle === 'class') { - // multiple words after @class? - looksLikeDesc = (tag.value || '').match(/\S+\s+\S+/); - if ((looksLikeDesc || /@construct(s|or)\b/i.test(doclet.comment)) && - !/@classdesc\b/i.test(doclet.comment)) { - // treat the @class tag as a @classdesc tag instead - doclet.classdesc = tag.value; + // handle special case where both @class and @constructor tags exist in same doclet + if (tag.originalTitle === 'class') { + // multiple words after @class? + looksLikeDesc = (tag.value || '').match(/\S+\s+\S+/); + if ( + (looksLikeDesc || /@construct(s|or)\b/i.test(doclet.comment)) && + !/@classdesc\b/i.test(doclet.comment) + ) { + // treat the @class tag as a @classdesc tag instead + doclet.classdesc = tag.value; - return; - } - } + return; + } + } - setDocletNameToValue(doclet, tag); - }, - synonyms: ['constructor'] + setDocletNameToValue(doclet, tag); }, - classdesc: { - onTagged(doclet, {value}) { - doclet.classdesc = value; - } + synonyms: ['constructor'], + }, + classdesc: { + onTagged(doclet, { value }) { + doclet.classdesc = value; }, - constant: { - canHaveType: true, - canHaveName: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValueName(doclet, tag); - setDocletTypeToValueType(doclet, tag); - }, - synonyms: ['const'] + }, + constant: { + canHaveType: true, + canHaveName: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValueName(doclet, tag); + setDocletTypeToValueType(doclet, tag); }, - constructs: { - onTagged(doclet, {value}) { - let ownerClassName; + synonyms: ['const'], + }, + constructs: { + onTagged(doclet, { value }) { + let ownerClassName; - if (!value) { - // this can be resolved later in the handlers - ownerClassName = '{@thisClass}'; - } - else { - ownerClassName = firstWordOf(value); - } - doclet.addTag('alias', ownerClassName); - doclet.addTag('kind', 'class'); - } + if (!value) { + // this can be resolved later in the handlers + ownerClassName = '{@thisClass}'; + } else { + ownerClassName = firstWordOf(value); + } + doclet.addTag('alias', ownerClassName); + doclet.addTag('kind', 'class'); }, - copyright: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.copyright = value; - } + }, + copyright: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.copyright = value; }, - default: { - onTagged(doclet, {value}) { - if (value) { - doclet.defaultvalue = value; - } - else if (doclet.meta && doclet.meta.code && - typeof doclet.meta.code.value !== 'undefined') { - switch (doclet.meta.code.type) { - case Syntax.ArrayExpression: - doclet.defaultvalue = nodeToValue(doclet.meta.code.node); - doclet.defaultvaluetype = 'array'; - break; + }, + default: { + onTagged(doclet, { value }) { + if (value) { + doclet.defaultvalue = value; + } else if (doclet.meta && doclet.meta.code && typeof doclet.meta.code.value !== 'undefined') { + switch (doclet.meta.code.type) { + case Syntax.ArrayExpression: + doclet.defaultvalue = nodeToValue(doclet.meta.code.node); + doclet.defaultvaluetype = 'array'; + break; - case Syntax.Literal: - doclet.defaultvalue = doclet.meta.code.value; - break; + case Syntax.Literal: + doclet.defaultvalue = doclet.meta.code.value; + break; - case Syntax.ObjectExpression: - doclet.defaultvalue = nodeToValue(doclet.meta.code.node); - doclet.defaultvaluetype = 'object'; - break; + case Syntax.ObjectExpression: + doclet.defaultvalue = nodeToValue(doclet.meta.code.node); + doclet.defaultvaluetype = 'object'; + break; - default: - // do nothing - break; - } - } - }, - synonyms: ['defaultvalue'] - }, - deprecated: { - // value is optional - onTagged(doclet, {value}) { - doclet.deprecated = value || true; + default: + // do nothing + break; } + } }, - enum: { - canHaveType: true, - onTagged(doclet, tag) { - doclet.kind = doclet.kind || 'member'; - doclet.isEnum = true; - setDocletTypeToValueType(doclet, tag); - } + synonyms: ['defaultvalue'], + }, + deprecated: { + // value is optional + onTagged(doclet, { value }) { + doclet.deprecated = value || true; }, - event: { - isNamespace: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - } + }, + enum: { + canHaveType: true, + onTagged(doclet, tag) { + doclet.kind = doclet.kind || 'member'; + doclet.isEnum = true; + setDocletTypeToValueType(doclet, tag); }, - example: { - keepsWhitespace: true, - removesIndent: true, - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.examples = doclet.examples || []; - doclet.examples.push(value); - } + }, + event: { + isNamespace: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); }, - exports: { - mustHaveValue: true, - onTagged(doclet, {value}) { - const modName = firstWordOf(value); + }, + example: { + keepsWhitespace: true, + removesIndent: true, + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.examples = doclet.examples || []; + doclet.examples.push(value); + }, + }, + exports: { + mustHaveValue: true, + onTagged(doclet, { value }) { + const modName = firstWordOf(value); - // in case the user wrote something like `/** @exports module:foo */`: - doclet.addTag( 'alias', stripModuleNamespace(modName) ); - doclet.addTag('kind', 'module'); - } + // in case the user wrote something like `/** @exports module:foo */`: + doclet.addTag('alias', stripModuleNamespace(modName)); + doclet.addTag('kind', 'module'); }, - external: { - canHaveType: true, - isNamespace: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - if (tag.value && tag.value.type) { - setDocletTypeToValueType(doclet, tag); - doclet.addTag('name', doclet.type.names[0]); - } - else { - setDocletNameToValue(doclet, tag); - } - }, - synonyms: ['host'] + }, + external: { + canHaveType: true, + isNamespace: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + if (tag.value && tag.value.type) { + setDocletTypeToValueType(doclet, tag); + doclet.addTag('name', doclet.type.names[0]); + } else { + setDocletNameToValue(doclet, tag); + } }, - file: { - onTagged(doclet, tag) { - setNameToFile(doclet); - setDocletKindToTitle(doclet, tag); - setDocletDescriptionToValue(doclet, tag); + synonyms: ['host'], + }, + file: { + onTagged(doclet, tag) { + setNameToFile(doclet); + setDocletKindToTitle(doclet, tag); + setDocletDescriptionToValue(doclet, tag); - doclet.preserveName = true; - }, - synonyms: ['fileoverview', 'overview'] + doclet.preserveName = true; }, - fires: { - mustHaveValue: true, - onTagged(doclet, tag) { - doclet.fires = doclet.fires || []; - applyNamespaceToTag('event', tag); - doclet.fires.push(tag.value); - }, - synonyms: ['emits'] + synonyms: ['fileoverview', 'overview'], + }, + fires: { + mustHaveValue: true, + onTagged(doclet, tag) { + doclet.fires = doclet.fires || []; + applyNamespaceToTag('event', tag); + doclet.fires.push(tag.value); }, - function: { - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - }, - synonyms: ['func', 'method'] + synonyms: ['emits'], + }, + function: { + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); }, - generator: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.generator = true; + synonyms: ['func', 'method'], + }, + generator: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.generator = true; + }, + }, + global: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.scope = SCOPE.NAMES.GLOBAL; + delete doclet.memberof; + }, + }, + hideconstructor: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.hideconstructor = true; + }, + }, + ignore: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.ignore = true; + }, + }, + implements: { + mustHaveValue: true, + onTagText: parseTypeText, + onTagged(doclet, { value }) { + doclet.implements = doclet.implements || []; + doclet.implements.push(value); + }, + }, + inheritdoc: { + mustNotHaveValue: true, + onTagged(doclet) { + // use an empty string so JSDoc can support `@inheritdoc Foo#bar` in the future + doclet.inheritdoc = ''; + }, + }, + inner: { + onTagged(doclet, tag) { + setDocletScopeToTitle(doclet, tag); + }, + }, + instance: { + onTagged(doclet, tag) { + setDocletScopeToTitle(doclet, tag); + }, + }, + interface: { + canHaveName: true, + onTagged(doclet, tag) { + doclet.addTag('kind', 'interface'); + if (tag.value) { + setDocletNameToValueName(doclet, tag); + } + }, + }, + lends: { + onTagged(doclet, { value }) { + doclet.alias = value || LONGNAMES.GLOBAL; + doclet.addTag('undocumented'); + }, + }, + license: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.license = value; + }, + }, + listens: { + mustHaveValue: true, + onTagged(doclet, tag) { + doclet.listens = doclet.listens || []; + applyNamespaceToTag('event', tag); + doclet.listens.push(tag.value); + }, + }, + member: { + canHaveType: true, + canHaveName: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValueName(doclet, tag); + setDocletTypeToValueType(doclet, tag); + }, + synonyms: ['var'], + }, + memberof: { + mustHaveValue: true, + onTagged(doclet, tag) { + if (tag.originalTitle === 'memberof!') { + doclet.forceMemberof = true; + if (tag.value === LONGNAMES.GLOBAL) { + doclet.addTag('global'); + delete doclet.memberof; } + } + setDocletMemberof(doclet, tag); }, - global: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.scope = SCOPE.NAMES.GLOBAL; - delete doclet.memberof; - } - }, - hideconstructor: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.hideconstructor = true; - } - }, - ignore: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.ignore = true; - } - }, - implements: { - mustHaveValue: true, - onTagText: parseTypeText, - onTagged(doclet, {value}) { - doclet.implements = doclet.implements || []; - doclet.implements.push(value); - } - }, - inheritdoc: { - mustNotHaveValue: true, - onTagged(doclet) { - // use an empty string so JSDoc can support `@inheritdoc Foo#bar` in the future - doclet.inheritdoc = ''; - } - }, - inner: { - onTagged(doclet, tag) { - setDocletScopeToTitle(doclet, tag); - } - }, - instance: { - onTagged(doclet, tag) { - setDocletScopeToTitle(doclet, tag); - } - }, - interface: { - canHaveName: true, - onTagged(doclet, tag) { - doclet.addTag('kind', 'interface'); - if (tag.value) { - setDocletNameToValueName(doclet, tag); - } - } - }, - lends: { - onTagged(doclet, {value}) { - doclet.alias = value || LONGNAMES.GLOBAL; - doclet.addTag('undocumented'); - } - }, - license: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.license = value; - } - }, - listens: { - mustHaveValue: true, - onTagged(doclet, tag) { - doclet.listens = doclet.listens || []; - applyNamespaceToTag('event', tag); - doclet.listens.push(tag.value); - } - }, - member: { - canHaveType: true, - canHaveName: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValueName(doclet, tag); - setDocletTypeToValueType(doclet, tag); - }, - synonyms: ['var'] - }, - memberof: { - mustHaveValue: true, - onTagged(doclet, tag) { - if (tag.originalTitle === 'memberof!') { - doclet.forceMemberof = true; - if (tag.value === LONGNAMES.GLOBAL) { - doclet.addTag('global'); - delete doclet.memberof; - } - } - setDocletMemberof(doclet, tag); - }, - synonyms: ['memberof!'] - }, - // this symbol mixes in all of the specified object's members - mixes: { - mustHaveValue: true, - onTagged(doclet, {value}) { - const source = firstWordOf(value); + synonyms: ['memberof!'], + }, + // this symbol mixes in all of the specified object's members + mixes: { + mustHaveValue: true, + onTagged(doclet, { value }) { + const source = firstWordOf(value); - doclet.mix(source); - } + doclet.mix(source); }, - mixin: { - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - } + }, + mixin: { + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); }, - modifies: { - canHaveType: true, - onTagged(doclet, {value}) { - doclet.modifies = doclet.modifies || []; - doclet.modifies.push(value); - } + }, + modifies: { + canHaveType: true, + onTagged(doclet, { value }) { + doclet.modifies = doclet.modifies || []; + doclet.modifies.push(value); }, - module: { - canHaveType: true, - isNamespace: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - if (!doclet.name) { - setDocletNameToFilename(doclet); - } - // in case the user wrote something like `/** @module module:foo */`: - doclet.name = stripModuleNamespace(doclet.name); + }, + module: { + canHaveType: true, + isNamespace: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + if (!doclet.name) { + setDocletNameToFilename(doclet); + } + // in case the user wrote something like `/** @module module:foo */`: + doclet.name = stripModuleNamespace(doclet.name); - setDocletTypeToValueType(doclet, tag); - } + setDocletTypeToValueType(doclet, tag); }, - namespace: { - canHaveType: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - setDocletTypeToValueType(doclet, tag); - } + }, + namespace: { + canHaveType: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + setDocletTypeToValueType(doclet, tag); }, - package: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.access = 'package'; - } + }, + package: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.access = 'package'; }, - param: { - canHaveType: true, - canHaveName: true, - onTagged(doclet, {value}) { - doclet.params = doclet.params || []; - doclet.params.push(value || {}); - }, - synonyms: ['arg', 'argument'] + }, + param: { + canHaveType: true, + canHaveName: true, + onTagged(doclet, { value }) { + doclet.params = doclet.params || []; + doclet.params.push(value || {}); }, - private: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.access = 'private'; - } + synonyms: ['arg', 'argument'], + }, + private: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.access = 'private'; }, - property: { - mustHaveValue: true, - canHaveType: true, - canHaveName: true, - onTagged(doclet, {value}) { - doclet.properties = doclet.properties || []; - doclet.properties.push(value); - }, - synonyms: ['prop'] + }, + property: { + mustHaveValue: true, + canHaveType: true, + canHaveName: true, + onTagged(doclet, { value }) { + doclet.properties = doclet.properties || []; + doclet.properties.push(value); }, - protected: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.access = 'protected'; - } + synonyms: ['prop'], + }, + protected: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.access = 'protected'; }, - public: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.access = 'public'; - } + }, + public: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.access = 'public'; }, - readonly: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.readonly = true; - } + }, + readonly: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.readonly = true; }, - requires: { - mustHaveValue: true, - onTagged(doclet, {value}) { - let requiresName; + }, + requires: { + mustHaveValue: true, + onTagged(doclet, { value }) { + let requiresName; - // inline link tags are passed through as-is so that `@requires {@link foo}` works - if ( isInlineTag(value, 'link\\S*') ) { - requiresName = value; - } - // otherwise, assume it's a module - else { - requiresName = firstWordOf(value); - if (requiresName.indexOf(MODULE_NAMESPACE) !== 0) { - requiresName = MODULE_NAMESPACE + requiresName; - } - } - - doclet.requires = doclet.requires || []; - doclet.requires.push(requiresName); + // inline link tags are passed through as-is so that `@requires {@link foo}` works + if (isInlineTag(value, 'link\\S*')) { + requiresName = value; + } + // otherwise, assume it's a module + else { + requiresName = firstWordOf(value); + if (requiresName.indexOf(MODULE_NAMESPACE) !== 0) { + requiresName = MODULE_NAMESPACE + requiresName; } + } + + doclet.requires = doclet.requires || []; + doclet.requires.push(requiresName); }, - returns: { - mustHaveValue: true, - canHaveType: true, - onTagged(doclet, {value}) { - doclet.returns = doclet.returns || []; - doclet.returns.push(value); - }, - synonyms: ['return'] + }, + returns: { + mustHaveValue: true, + canHaveType: true, + onTagged(doclet, { value }) { + doclet.returns = doclet.returns || []; + doclet.returns.push(value); }, - see: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.see = doclet.see || []; - doclet.see.push(value); + synonyms: ['return'], + }, + see: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.see = doclet.see || []; + doclet.see.push(value); + }, + }, + since: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.since = value; + }, + }, + static: { + onTagged(doclet, tag) { + setDocletScopeToTitle(doclet, tag); + }, + }, + summary: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.summary = value; + }, + }, + this: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.this = firstWordOf(value); + }, + }, + todo: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.todo = doclet.todo || []; + doclet.todo.push(value); + }, + }, + throws: { + mustHaveValue: true, + canHaveType: true, + onTagged(doclet, { value }) { + doclet.exceptions = doclet.exceptions || []; + doclet.exceptions.push(value); + }, + synonyms: ['exception'], + }, + type: { + mustHaveValue: true, + mustNotHaveDescription: true, + canHaveType: true, + onTagText(text) { + let closeIdx; + let openIdx; + + const OPEN_BRACE = '{'; + const CLOSE_BRACE = '}'; + + // remove line breaks + text = text.replace(/[\f\n\r]/g, ''); + + // Text must be a type expression; for backwards compatibility, we add braces if they're + // missing. But do NOT add braces to things like `@type {string} some pointless text`. + openIdx = text.indexOf(OPEN_BRACE); + closeIdx = text.indexOf(CLOSE_BRACE); + + // a type expression is at least one character long + if (openIdx !== 0 || closeIdx <= openIdx + 1) { + text = OPEN_BRACE + text + CLOSE_BRACE; + } + + return text; + }, + onTagged(doclet, tag) { + if (tag.value && tag.value.type) { + setDocletTypeToValueType(doclet, tag); + + // for backwards compatibility, we allow @type for functions to imply return type + if (doclet.kind === 'function') { + doclet.addTag('returns', tag.text); } + } }, - since: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.since = value; + }, + typedef: { + canHaveType: true, + canHaveName: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + + if (tag.value) { + setDocletNameToValueName(doclet, tag); + + // callbacks are always type {function} + if (tag.originalTitle === 'callback') { + doclet.type = { + names: ['function'], + }; + } else { + setDocletTypeToValueType(doclet, tag); } + } }, - static: { - onTagged(doclet, tag) { - setDocletScopeToTitle(doclet, tag); - } + synonyms: ['callback'], + }, + variation: { + mustHaveValue: true, + onTagged(doclet, tag) { + let value = tag.value; + + if (/^\((.+)\)$/.test(value)) { + value = RegExp.$1; + } + + doclet.variation = value; }, - summary: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.summary = value; - } + }, + version: { + mustHaveValue: true, + onTagged(doclet, { value }) { + doclet.version = value; }, - 'this': { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.this = firstWordOf(value); - } + }, + yields: { + mustHaveValue: true, + canHaveType: true, + onTagged(doclet, { value }) { + doclet.yields = doclet.yields || []; + doclet.yields.push(value); }, - todo: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.todo = doclet.todo || []; - doclet.todo.push(value); - } - }, - throws: { - mustHaveValue: true, - canHaveType: true, - onTagged(doclet, {value}) { - doclet.exceptions = doclet.exceptions || []; - doclet.exceptions.push(value); - }, - synonyms: ['exception'] - }, - type: { - mustHaveValue: true, - mustNotHaveDescription: true, - canHaveType: true, - onTagText(text) { - let closeIdx; - let openIdx; - - const OPEN_BRACE = '{'; - const CLOSE_BRACE = '}'; - - // remove line breaks - text = text.replace(/[\f\n\r]/g, ''); - - // Text must be a type expression; for backwards compatibility, we add braces if they're - // missing. But do NOT add braces to things like `@type {string} some pointless text`. - openIdx = text.indexOf(OPEN_BRACE); - closeIdx = text.indexOf(CLOSE_BRACE); - - // a type expression is at least one character long - if ( openIdx !== 0 || closeIdx <= openIdx + 1) { - text = OPEN_BRACE + text + CLOSE_BRACE; - } - - return text; - }, - onTagged(doclet, tag) { - if (tag.value && tag.value.type) { - setDocletTypeToValueType(doclet, tag); - - // for backwards compatibility, we allow @type for functions to imply return type - if (doclet.kind === 'function') { - doclet.addTag('returns', tag.text); - } - } - } - }, - typedef: { - canHaveType: true, - canHaveName: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - - if (tag.value) { - setDocletNameToValueName(doclet, tag); - - // callbacks are always type {function} - if (tag.originalTitle === 'callback') { - doclet.type = { - names: [ - 'function' - ] - }; - } - else { - setDocletTypeToValueType(doclet, tag); - } - } - }, - synonyms: ['callback'] - }, - variation: { - mustHaveValue: true, - onTagged(doclet, tag) { - let value = tag.value; - - if ( /^\((.+)\)$/.test(value) ) { - value = RegExp.$1; - } - - doclet.variation = value; - } - }, - version: { - mustHaveValue: true, - onTagged(doclet, {value}) { - doclet.version = value; - } - }, - yields: { - mustHaveValue: true, - canHaveType: true, - onTagged(doclet, {value}) { - doclet.yields = doclet.yields || []; - doclet.yields.push(value); - }, - synonyms: ['yield'] - } -}; + synonyms: ['yield'], + }, +}); baseTags = _.extend(baseTags, internalTags); @@ -858,138 +850,138 @@ exports.jsdocTags = baseTags; // Tag dictionary for Google Closure Compiler. exports.closureTags = { - const: { - canHaveType: true, - onTagged(doclet, tag) { - doclet.kind = 'constant'; - setDocletTypeToValueType(doclet, tag); - }, - // Closure Compiler only - synonyms: ['define'] + const: { + canHaveType: true, + onTagged(doclet, tag) { + doclet.kind = 'constant'; + setDocletTypeToValueType(doclet, tag); }, - constructor: cloneTagDef(baseTags.class), - deprecated: cloneTagDef(baseTags.deprecated), // Closure Compiler only - dict: NOOP_TAG, - enum: cloneTagDef(baseTags.enum), - // Closure Compiler only - export: NOOP_TAG, - // Closure Compiler only - externs: NOOP_TAG, - extends: cloneTagDef(baseTags.augments), - fileoverview: { - onTagged(doclet, tag) { - setNameToFile(doclet); - doclet.kind = 'file'; - setDocletDescriptionToValue(doclet, tag); + synonyms: ['define'], + }, + constructor: cloneTagDef(baseTags.class), + deprecated: cloneTagDef(baseTags.deprecated), + // Closure Compiler only + dict: NOOP_TAG, + enum: cloneTagDef(baseTags.enum), + // Closure Compiler only + export: NOOP_TAG, + // Closure Compiler only + externs: NOOP_TAG, + extends: cloneTagDef(baseTags.augments), + fileoverview: { + onTagged(doclet, tag) { + setNameToFile(doclet); + doclet.kind = 'file'; + setDocletDescriptionToValue(doclet, tag); - doclet.preserveName = true; - } + doclet.preserveName = true; }, - final: cloneTagDef(baseTags.readonly), - implements: cloneTagDef(baseTags.implements), + }, + final: cloneTagDef(baseTags.readonly), + implements: cloneTagDef(baseTags.implements), + // Closure Compiler only + implicitcast: NOOP_TAG, + inheritdoc: cloneTagDef(baseTags.inheritdoc), + interface: cloneTagDef(baseTags.interface, { + canHaveName: false, + mustNotHaveValue: true, // Closure Compiler only - implicitcast: NOOP_TAG, - inheritdoc: cloneTagDef(baseTags.inheritdoc), - interface: cloneTagDef(baseTags.interface, { - canHaveName: false, - mustNotHaveValue: true, - // Closure Compiler only - synonyms: ['record'] - }), - lends: cloneTagDef(baseTags.lends), - license: cloneTagDef(baseTags.license), - modifies: cloneTagDef(baseTags.modifies), - // Closure Compiler only - noalias: NOOP_TAG, - // Closure Compiler only - nocollapse: NOOP_TAG, - // Closure Compiler only - nocompile: NOOP_TAG, - // Closure Compiler only - nosideeffects: { - onTagged(doclet) { - doclet.modifies = []; - } + synonyms: ['record'], + }), + lends: cloneTagDef(baseTags.lends), + license: cloneTagDef(baseTags.license), + modifies: cloneTagDef(baseTags.modifies), + // Closure Compiler only + noalias: NOOP_TAG, + // Closure Compiler only + nocollapse: NOOP_TAG, + // Closure Compiler only + nocompile: NOOP_TAG, + // Closure Compiler only + nosideeffects: { + onTagged(doclet) { + doclet.modifies = []; }, - // Closure Compiler only - override: { - mustNotHaveValue: true, - onTagged(doclet) { - doclet.override = true; - } + }, + // Closure Compiler only + override: { + mustNotHaveValue: true, + onTagged(doclet) { + doclet.override = true; }, - package: { - canHaveType: true, - onTagged(doclet, tag) { - doclet.access = 'package'; + }, + package: { + canHaveType: true, + onTagged(doclet, tag) { + doclet.access = 'package'; - if (tag.value && tag.value.type) { - setDocletTypeToValueType(doclet, tag); - } - } + if (tag.value && tag.value.type) { + setDocletTypeToValueType(doclet, tag); + } }, - param: cloneTagDef(baseTags.param), - // Closure Compiler only - polymer: NOOP_TAG, - // Closure Compiler only - polymerBehavior: NOOP_TAG, - // Closure Compiler only - preserve: cloneTagDef(baseTags.license), - private: { - canHaveType: true, - onTagged(doclet, tag) { - doclet.access = 'private'; + }, + param: cloneTagDef(baseTags.param), + // Closure Compiler only + polymer: NOOP_TAG, + // Closure Compiler only + polymerBehavior: NOOP_TAG, + // Closure Compiler only + preserve: cloneTagDef(baseTags.license), + private: { + canHaveType: true, + onTagged(doclet, tag) { + doclet.access = 'private'; - if (tag.value && tag.value.type) { - setDocletTypeToValueType(doclet, tag); - } - } + if (tag.value && tag.value.type) { + setDocletTypeToValueType(doclet, tag); + } }, - protected: { - canHaveType: true, - onTagged(doclet, tag) { - doclet.access = 'protected'; + }, + protected: { + canHaveType: true, + onTagged(doclet, tag) { + doclet.access = 'protected'; - if (tag.value && tag.value.type) { - setDocletTypeToValueType(doclet, tag); - } - } + if (tag.value && tag.value.type) { + setDocletTypeToValueType(doclet, tag); + } }, - public: { - canHaveType: true, - onTagged(doclet, tag) { - doclet.access = 'public'; + }, + public: { + canHaveType: true, + onTagged(doclet, tag) { + doclet.access = 'public'; - if (tag.value && tag.value.type) { - setDocletTypeToValueType(doclet, tag); - } - } + if (tag.value && tag.value.type) { + setDocletTypeToValueType(doclet, tag); + } }, - return: cloneTagDef(baseTags.returns), - // Closure Compiler only - struct: NOOP_TAG, - // Closure Compiler only - suppress: NOOP_TAG, - // Closure Compiler only - template: NOOP_TAG, - 'this': { - canHaveType: true, - onTagged(doclet, tag) { - doclet.this = combineTypes(tag); - } + }, + return: cloneTagDef(baseTags.returns), + // Closure Compiler only + struct: NOOP_TAG, + // Closure Compiler only + suppress: NOOP_TAG, + // Closure Compiler only + template: NOOP_TAG, + this: { + canHaveType: true, + onTagged(doclet, tag) { + doclet.this = combineTypes(tag); }, - throws: cloneTagDef(baseTags.throws), - type: cloneTagDef(baseTags.type, { - mustNotHaveDescription: false - }), - typedef: { - canHaveType: true, - onTagged(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletTypeToValueType(doclet, tag); - } + }, + throws: cloneTagDef(baseTags.throws), + type: cloneTagDef(baseTags.type, { + mustNotHaveDescription: false, + }), + typedef: { + canHaveType: true, + onTagged(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletTypeToValueType(doclet, tag); }, - // Closure Compiler only - unrestricted: NOOP_TAG + }, + // Closure Compiler only + unrestricted: NOOP_TAG, }; diff --git a/packages/jsdoc/lib/jsdoc/tag/validator.js b/packages/jsdoc/lib/jsdoc/tag/validator.js index ae594ba0..eb85517c 100644 --- a/packages/jsdoc/lib/jsdoc/tag/validator.js +++ b/packages/jsdoc/lib/jsdoc/tag/validator.js @@ -5,47 +5,47 @@ const env = require('jsdoc/env'); const { log } = require('@jsdoc/util'); -function buildMessage(tagName, {filename, lineno, comment}, desc) { - let result = `The @${tagName} tag ${desc}. File: ${filename}, line: ${lineno}`; +function buildMessage(tagName, { filename, lineno, comment }, desc) { + let result = `The @${tagName} tag ${desc}. File: ${filename}, line: ${lineno}`; - if (comment) { - result += `\n${comment}`; - } + if (comment) { + result += `\n${comment}`; + } - return result; + return result; } /** * Validate the given tag. */ -exports.validate = ({title, text, value}, tagDef, meta) => { - const allowUnknownTags = env.conf.tags.allowUnknownTags; +exports.validate = ({ title, text, value }, tagDef, meta) => { + const allowUnknownTags = env.conf.tags.allowUnknownTags; - // handle cases where the tag definition does not exist - if (!tagDef) { - // log an error if unknown tags are not allowed - if (!allowUnknownTags || - (Array.isArray(allowUnknownTags) && - !allowUnknownTags.includes(title))) { - log.error(buildMessage(title, meta, 'is not a known tag')); - } - - // stop validation, since there's nothing to validate against - return; + // handle cases where the tag definition does not exist + if (!tagDef) { + // log an error if unknown tags are not allowed + if ( + !allowUnknownTags || + (Array.isArray(allowUnknownTags) && !allowUnknownTags.includes(title)) + ) { + log.error(buildMessage(title, meta, 'is not a known tag')); } - // check for errors that make the tag useless - if (!text && tagDef.mustHaveValue) { - log.error(buildMessage(title, meta, 'requires a value')); - } + // stop validation, since there's nothing to validate against + return; + } - // check for minor issues that are usually harmless - else if (text && tagDef.mustNotHaveValue) { - log.warn(buildMessage(title, meta, - 'does not permit a value; the value will be ignored')); - } - else if (value && value.description && tagDef.mustNotHaveDescription) { - log.warn(buildMessage(title, meta, - 'does not permit a description; the description will be ignored')); - } + // check for errors that make the tag useless + if (!text && tagDef.mustHaveValue) { + log.error(buildMessage(title, meta, 'requires a value')); + } + + // check for minor issues that are usually harmless + else if (text && tagDef.mustNotHaveValue) { + log.warn(buildMessage(title, meta, 'does not permit a value; the value will be ignored')); + } else if (value && value.description && tagDef.mustNotHaveDescription) { + log.warn( + buildMessage(title, meta, 'does not permit a description; the description will be ignored') + ); + } }; diff --git a/packages/jsdoc/lib/jsdoc/template.js b/packages/jsdoc/lib/jsdoc/template.js index 4d7ff79c..df0fb592 100644 --- a/packages/jsdoc/lib/jsdoc/template.js +++ b/packages/jsdoc/lib/jsdoc/template.js @@ -10,71 +10,71 @@ const path = require('path'); * Template helper. */ class Template { - /** - * @param {string} filepath - Templates directory. - */ - constructor(filepath) { - this.path = filepath; - this.layout = null; - this.cache = {}; - // override default template tag settings - this.settings = { - evaluate: /<\?js([\s\S]+?)\?>/g, - interpolate: /<\?js=([\s\S]+?)\?>/g, - escape: /<\?js~([\s\S]+?)\?>/g - }; + /** + * @param {string} filepath - Templates directory. + */ + constructor(filepath) { + this.path = filepath; + this.layout = null; + this.cache = {}; + // override default template tag settings + this.settings = { + evaluate: /<\?js([\s\S]+?)\?>/g, + interpolate: /<\?js=([\s\S]+?)\?>/g, + escape: /<\?js~([\s\S]+?)\?>/g, + }; + } + + /** + * Loads template from given file. + * @param {string} file - Template filename. + * @return {function} Returns template closure. + */ + load(file) { + return _.template(fs.readFileSync(file, 'utf8'), this.settings); + } + + /** + * Renders template using given data. + * + * This is low-level function, for rendering full templates use {@link Template.render()}. + * + * @param {string} file - Template filename. + * @param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use). + * @return {string} Rendered template. + */ + partial(file, data) { + file = path.resolve(this.path, file); + + // load template into cache + if (!(file in this.cache)) { + this.cache[file] = this.load(file); } - /** - * Loads template from given file. - * @param {string} file - Template filename. - * @return {function} Returns template closure. - */ - load(file) { - return _.template(fs.readFileSync(file, 'utf8'), this.settings); + // keep template helper context + return this.cache[file].call(this, data); + } + + /** + * Renders template with given data. + * + * This method automaticaly applies layout if set. + * + * @param {string} file - Template filename. + * @param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use). + * @return {string} Rendered template. + */ + render(file, data) { + // main content + let content = this.partial(file, data); + + // apply layout + if (this.layout) { + data.content = content; + content = this.partial(this.layout, data); } - /** - * Renders template using given data. - * - * This is low-level function, for rendering full templates use {@link Template.render()}. - * - * @param {string} file - Template filename. - * @param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use). - * @return {string} Rendered template. - */ - partial(file, data) { - file = path.resolve(this.path, file); - - // load template into cache - if (!(file in this.cache)) { - this.cache[file] = this.load(file); - } - - // keep template helper context - return this.cache[file].call(this, data); - } - - /** - * Renders template with given data. - * - * This method automaticaly applies layout if set. - * - * @param {string} file - Template filename. - * @param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use). - * @return {string} Rendered template. - */ - render(file, data) { - // main content - let content = this.partial(file, data); - - // apply layout - if (this.layout) { - data.content = content; - content = this.partial(this.layout, data); - } - - return content; - } + return content; + } } exports.Template = Template; diff --git a/packages/jsdoc/lib/jsdoc/util/templateHelper.js b/packages/jsdoc/lib/jsdoc/util/templateHelper.js index c3ca3a93..3ee69cf9 100644 --- a/packages/jsdoc/lib/jsdoc/util/templateHelper.js +++ b/packages/jsdoc/lib/jsdoc/util/templateHelper.js @@ -23,71 +23,71 @@ exports.fileExtension = '.html'; exports.SCOPE_TO_PUNC = SCOPE_TO_PUNC; const linkMap = { - // two-way lookup - longnameToUrl: {}, - urlToLongname: {}, + // two-way lookup + longnameToUrl: {}, + urlToLongname: {}, - // one-way lookup (IDs are only unique per file) - longnameToId: {} + // one-way lookup (IDs are only unique per file) + longnameToId: {}, }; -const longnameToUrl = exports.longnameToUrl = linkMap.longnameToUrl; -const longnameToId = exports.longnameToId = linkMap.longnameToId; +const longnameToUrl = (exports.longnameToUrl = linkMap.longnameToUrl); +const longnameToId = (exports.longnameToId = linkMap.longnameToId); -const registerLink = exports.registerLink = (longname, fileUrl) => { - linkMap.longnameToUrl[longname] = fileUrl; - linkMap.urlToLongname[fileUrl] = longname; -}; +const registerLink = (exports.registerLink = (longname, fileUrl) => { + linkMap.longnameToUrl[longname] = fileUrl; + linkMap.urlToLongname[fileUrl] = longname; +}); -const registerId = exports.registerId = (longname, fragment) => { - linkMap.longnameToId[longname] = fragment; -}; +const registerId = (exports.registerId = (longname, fragment) => { + linkMap.longnameToId[longname] = fragment; +}); function getNamespace(kind) { - if (dictionary.isNamespace(kind)) { - return `${kind}:`; - } + if (dictionary.isNamespace(kind)) { + return `${kind}:`; + } - return ''; + return ''; } function formatNameForLink(doclet) { - let newName = getNamespace(doclet.kind) + (doclet.name || '') + (doclet.variation || ''); - const scopePunc = SCOPE_TO_PUNC[doclet.scope] || ''; + let newName = getNamespace(doclet.kind) + (doclet.name || '') + (doclet.variation || ''); + const scopePunc = SCOPE_TO_PUNC[doclet.scope] || ''; - // Only prepend the scope punctuation if it's not the same character that marks the start of a - // fragment ID. Using `#` in HTML5 fragment IDs is legal, but URLs like `foo.html##bar` are - // just confusing. - if (scopePunc !== '#') { - newName = scopePunc + newName; - } + // Only prepend the scope punctuation if it's not the same character that marks the start of a + // fragment ID. Using `#` in HTML5 fragment IDs is legal, but URLs like `foo.html##bar` are + // just confusing. + if (scopePunc !== '#') { + newName = scopePunc + newName; + } - return newName; + return newName; } function makeUniqueFilename(filename, str) { - let key = filename.toLowerCase(); - let nonUnique = true; + let key = filename.toLowerCase(); + let nonUnique = true; - // don't allow filenames to begin with an underscore - if (!filename.length || filename[0] === '_') { - filename = `-${filename}`; - key = filename.toLowerCase(); + // don't allow filenames to begin with an underscore + if (!filename.length || filename[0] === '_') { + filename = `-${filename}`; + key = filename.toLowerCase(); + } + + // append enough underscores to make the filename unique + while (nonUnique) { + if (hasOwnProp.call(files, key)) { + filename += '_'; + key = filename.toLowerCase(); + } else { + nonUnique = false; } + } - // append enough underscores to make the filename unique - while (nonUnique) { - if ( hasOwnProp.call(files, key) ) { - filename += '_'; - key = filename.toLowerCase(); - } else { - nonUnique = false; - } - } + files[key] = str; - files[key] = str; - - return filename; + return filename; } /** @@ -103,29 +103,29 @@ function makeUniqueFilename(filename, str) { * @param {string} str The string to convert. * @return {string} The filename to use for the string. */ -const getUniqueFilename = exports.getUniqueFilename = str => { - const namespaces = dictionary.getNamespaces().join('|'); - let basename = (str || '') - // use - instead of : in namespace prefixes - .replace(new RegExp(`^(${namespaces}):`), '$1-') - // replace characters that can cause problems on some filesystems - .replace(/[\\/?*:|'"<>]/g, '_') - // use - instead of ~ to denote 'inner' - .replace(/~/g, '-') - // use _ instead of # to denote 'instance' - .replace(/#/g, '_') - // use _ instead of / (for example, in module names) - .replace(/\//g, '_') - // remove the variation, if any - .replace(/\([\s\S]*\)$/, '') - // make sure we don't create hidden files, or files whose names start with a dash - .replace(/^[.-]/, ''); +const getUniqueFilename = (exports.getUniqueFilename = (str) => { + const namespaces = dictionary.getNamespaces().join('|'); + let basename = (str || '') + // use - instead of : in namespace prefixes + .replace(new RegExp(`^(${namespaces}):`), '$1-') + // replace characters that can cause problems on some filesystems + .replace(/[\\/?*:|'"<>]/g, '_') + // use - instead of ~ to denote 'inner' + .replace(/~/g, '-') + // use _ instead of # to denote 'instance' + .replace(/#/g, '_') + // use _ instead of / (for example, in module names) + .replace(/\//g, '_') + // remove the variation, if any + .replace(/\([\s\S]*\)$/, '') + // make sure we don't create hidden files, or files whose names start with a dash + .replace(/^[.-]/, ''); - // in case we've now stripped the entire basename (uncommon, but possible): - basename = basename.length ? basename : '_'; + // in case we've now stripped the entire basename (uncommon, but possible): + basename = basename.length ? basename : '_'; - return makeUniqueFilename(basename, str) + exports.fileExtension; -}; + return makeUniqueFilename(basename, str) + exports.fileExtension; +}); /** * Get a longname's filename if one has been registered; otherwise, generate a unique filename, then @@ -133,17 +133,16 @@ const getUniqueFilename = exports.getUniqueFilename = str => { * @private */ function getFilename(longname) { - let fileUrl; + let fileUrl; - if ( hasOwnProp.call(longnameToUrl, longname) ) { - fileUrl = longnameToUrl[longname]; - } - else { - fileUrl = getUniqueFilename(longname); - registerLink(longname, fileUrl); - } + if (hasOwnProp.call(longnameToUrl, longname)) { + fileUrl = longnameToUrl[longname]; + } else { + fileUrl = getUniqueFilename(longname); + registerLink(longname, fileUrl); + } - return fileUrl; + return fileUrl; } /** @@ -156,34 +155,37 @@ function getFilename(longname) { * `false`. */ function isModuleExports(doclet) { - return doclet.longname && doclet.longname === doclet.name && - doclet.longname.indexOf(MODULE_NAMESPACE) === 0 && doclet.kind !== 'module'; + return ( + doclet.longname && + doclet.longname === doclet.name && + doclet.longname.indexOf(MODULE_NAMESPACE) === 0 && + doclet.kind !== 'module' + ); } function makeUniqueId(filename, id) { - let key; - let nonUnique = true; + let key; + let nonUnique = true; - key = id.toLowerCase(); + key = id.toLowerCase(); - // HTML5 IDs cannot contain whitespace characters - id = id.replace(/\s/g, ''); + // HTML5 IDs cannot contain whitespace characters + id = id.replace(/\s/g, ''); - // append enough underscores to make the identifier unique - while (nonUnique) { - if ( hasOwnProp.call(ids, filename) && hasOwnProp.call(ids[filename], key) ) { - id += '_'; - key = id.toLowerCase(); - } - else { - nonUnique = false; - } + // append enough underscores to make the identifier unique + while (nonUnique) { + if (hasOwnProp.call(ids, filename) && hasOwnProp.call(ids[filename], key)) { + id += '_'; + key = id.toLowerCase(); + } else { + nonUnique = false; } + } - ids[filename] = ids[filename] || {}; - ids[filename][key] = id; + ids[filename] = ids[filename] || {}; + ids[filename][key] = id; - return id; + return id; } /** @@ -192,19 +194,17 @@ function makeUniqueId(filename, id) { * @private */ function getId(longname, id) { - if ( hasOwnProp.call(longnameToId, longname) ) { - id = longnameToId[longname]; - } - else if (!id) { - // no ID required - return ''; - } - else { - id = makeUniqueId(longname, id); - registerId(longname, id); - } + if (hasOwnProp.call(longnameToId, longname)) { + id = longnameToId[longname]; + } else if (!id) { + // no ID required + return ''; + } else { + id = makeUniqueId(longname, id); + registerId(longname, id); + } - return id; + return id; } /** @@ -220,56 +220,54 @@ function getId(longname, id) { */ exports.getUniqueId = makeUniqueId; -const htmlsafe = exports.htmlsafe = str => { - if (typeof str !== 'string') { - str = String(str); - } +const htmlsafe = (exports.htmlsafe = (str) => { + if (typeof str !== 'string') { + str = String(str); + } - return str.replace(/&/g, '&') - .replace(/$/.test(expr); + // record types, type unions, and type applications all count as "complex" + return /^{.+}$/.test(expr) || /^.+\|.+$/.test(expr) || /^.+<.+>$/.test(expr); } function fragmentHash(fragmentId) { - if (!fragmentId) { - return ''; - } + if (!fragmentId) { + return ''; + } - return `#${fragmentId}`; + return `#${fragmentId}`; } function getShortName(longname) { - return toParts(longname).name; + return toParts(longname).name; } /** @@ -299,43 +297,45 @@ function getShortName(longname) { * @return {string} The HTML link, or the link text if the link is not available. */ function buildLink(longname, linkText, options) { - const classString = options.cssClass ? ` class="${options.cssClass}"` : ''; - let fileUrl; - const fragmentString = fragmentHash(options.fragmentId); - let stripped; - let text; + const classString = options.cssClass ? ` class="${options.cssClass}"` : ''; + let fileUrl; + const fragmentString = fragmentHash(options.fragmentId); + let stripped; + let text; - let parsedType; + let parsedType; - // handle cases like: - // @see - // @see http://example.org - stripped = longname ? longname.replace(/^<|>$/g, '') : ''; - if ( hasUrlPrefix(stripped) ) { - fileUrl = stripped; - text = linkText || stripped; - } - // handle complex type expressions that may require multiple links - // (but skip anything that looks like an inline tag or HTML tag) - else if (longname && isComplexTypeExpression(longname) && /\{@.+\}/.test(longname) === false && - /^<[\s\S]+>/.test(longname) === false) { - parsedType = parseType(longname); + // handle cases like: + // @see + // @see http://example.org + stripped = longname ? longname.replace(/^<|>$/g, '') : ''; + if (hasUrlPrefix(stripped)) { + fileUrl = stripped; + text = linkText || stripped; + } + // handle complex type expressions that may require multiple links + // (but skip anything that looks like an inline tag or HTML tag) + else if ( + longname && + isComplexTypeExpression(longname) && + /\{@.+\}/.test(longname) === false && + /^<[\s\S]+>/.test(longname) === false + ) { + parsedType = parseType(longname); - return stringifyType(parsedType, options.cssClass, options.linkMap); - } - else { - fileUrl = hasOwnProp.call(options.linkMap, longname) ? options.linkMap[longname] : ''; - text = linkText || (options.shortenName ? getShortName(longname) : longname); - } + return stringifyType(parsedType, options.cssClass, options.linkMap); + } else { + fileUrl = hasOwnProp.call(options.linkMap, longname) ? options.linkMap[longname] : ''; + text = linkText || (options.shortenName ? getShortName(longname) : longname); + } - text = options.monospace ? `${text}` : text; + text = options.monospace ? `${text}` : text; - if (!fileUrl) { - return text; - } - else { - return `${text}`; - } + if (!fileUrl) { + return text; + } else { + return `${text}`; + } } /** @@ -358,68 +358,66 @@ function buildLink(longname, linkText, options) { * append to the link target. * @return {string} The HTML link, or a plain-text string if the link is not available. */ -const linkto = exports.linkto = (longname, linkText, cssClass, fragmentId) => buildLink(longname, linkText, { +const linkto = (exports.linkto = (longname, linkText, cssClass, fragmentId) => + buildLink(longname, linkText, { cssClass: cssClass, fragmentId: fragmentId, - linkMap: longnameToUrl -}); + linkMap: longnameToUrl, + })); function useMonospace(tag, text) { - let cleverLinks; - let monospaceLinks; - let result; + let cleverLinks; + let monospaceLinks; + let result; - if ( hasUrlPrefix(text) ) { - result = false; - } - else if (tag === 'linkplain') { - result = false; - } - else if (tag === 'linkcode') { - result = true; - } - else { - cleverLinks = env.conf.templates.cleverLinks; - monospaceLinks = env.conf.templates.monospaceLinks; + if (hasUrlPrefix(text)) { + result = false; + } else if (tag === 'linkplain') { + result = false; + } else if (tag === 'linkcode') { + result = true; + } else { + cleverLinks = env.conf.templates.cleverLinks; + monospaceLinks = env.conf.templates.monospaceLinks; - if (monospaceLinks || cleverLinks) { - result = true; - } + if (monospaceLinks || cleverLinks) { + result = true; } + } - return result || false; + return result || false; } function splitLinkText(text) { - let linkText; - let target; - let splitIndex; + let linkText; + let target; + let splitIndex; - // if a pipe is not present, we split on the first space - splitIndex = text.indexOf('|'); - if (splitIndex === -1) { - splitIndex = text.search(/\s/); - } + // if a pipe is not present, we split on the first space + splitIndex = text.indexOf('|'); + if (splitIndex === -1) { + splitIndex = text.search(/\s/); + } - if (splitIndex !== -1) { - linkText = text.substr(splitIndex + 1); - // Normalize subsequent newlines to a single space. - linkText = linkText.replace(/\n+/, ' '); - target = text.substr(0, splitIndex); - } + if (splitIndex !== -1) { + linkText = text.substr(splitIndex + 1); + // Normalize subsequent newlines to a single space. + linkText = linkText.replace(/\n+/, ' '); + target = text.substr(0, splitIndex); + } - return { - linkText: linkText, - target: target || text - }; + return { + linkText: linkText, + target: target || text, + }; } function shouldShortenLongname() { - if (env.conf && env.conf.templates && env.conf.templates.useShortNamesInLinks) { - return true; - } + if (env.conf && env.conf.templates && env.conf.templates.useShortNamesInLinks) { + return true; + } - return false; + return false; } /** @@ -428,61 +426,64 @@ function shouldShortenLongname() { * @param {string} str - The string to search for `{@link ...}` tags. * @return {string} The linkified text. */ -exports.resolveLinks = str => { - let replacers; +exports.resolveLinks = (str) => { + let replacers; - function extractLeadingText(string, completeTag) { - const tagIndex = string.indexOf(completeTag); - let leadingText = null; - const leadingTextRegExp = /\[(.+?)\]/g; - let leadingTextInfo = leadingTextRegExp.exec(string); + function extractLeadingText(string, completeTag) { + const tagIndex = string.indexOf(completeTag); + let leadingText = null; + const leadingTextRegExp = /\[(.+?)\]/g; + let leadingTextInfo = leadingTextRegExp.exec(string); - // did we find leading text, and if so, does it immediately precede the tag? - while (leadingTextInfo && leadingTextInfo.length) { - if (leadingTextInfo.index + leadingTextInfo[0].length === tagIndex) { - string = string.replace(leadingTextInfo[0], ''); - leadingText = leadingTextInfo[1]; - break; - } + // did we find leading text, and if so, does it immediately precede the tag? + while (leadingTextInfo && leadingTextInfo.length) { + if (leadingTextInfo.index + leadingTextInfo[0].length === tagIndex) { + string = string.replace(leadingTextInfo[0], ''); + leadingText = leadingTextInfo[1]; + break; + } - leadingTextInfo = leadingTextRegExp.exec(string); - } - - return { - leadingText: leadingText, - string: string - }; + leadingTextInfo = leadingTextRegExp.exec(string); } - function processLink(string, {completeTag, text, tag}) { - const leading = extractLeadingText(string, completeTag); - let linkText = leading.leadingText; - let monospace; - let split; - let target; - - string = leading.string; - - split = splitLinkText(text); - target = split.target; - linkText = linkText || split.linkText; - - monospace = useMonospace(tag, text); - - return string.replace( completeTag, buildLink(target, linkText, { - linkMap: longnameToUrl, - monospace: monospace, - shortenName: shouldShortenLongname() - }) ); - } - - replacers = { - link: processLink, - linkcode: processLink, - linkplain: processLink + return { + leadingText: leadingText, + string: string, }; + } - return inline.replaceInlineTags(str, replacers).newString; + function processLink(string, { completeTag, text, tag }) { + const leading = extractLeadingText(string, completeTag); + let linkText = leading.leadingText; + let monospace; + let split; + let target; + + string = leading.string; + + split = splitLinkText(text); + target = split.target; + linkText = linkText || split.linkText; + + monospace = useMonospace(tag, text); + + return string.replace( + completeTag, + buildLink(target, linkText, { + linkMap: longnameToUrl, + monospace: monospace, + shortenName: shouldShortenLongname(), + }) + ); + } + + replacers = { + link: processLink, + linkcode: processLink, + linkplain: processLink, + }; + + return inline.replaceInlineTags(str, replacers).newString; }; /** @@ -491,22 +492,21 @@ exports.resolveLinks = str => { * @param {string} str - The tag text. * @return {string} The linkified text. */ -exports.resolveAuthorLinks = str => { - let author = ''; - let matches; +exports.resolveAuthorLinks = (str) => { + let author = ''; + let matches; - if (str) { - matches = str.match(/^\s?([\s\S]+)\b\s+<(\S+@\S+)>\s?$/); + if (str) { + matches = str.match(/^\s?([\s\S]+)\b\s+<(\S+@\S+)>\s?$/); - if (matches && matches.length === 3) { - author = `${htmlsafe(matches[1])}`; - } - else { - author = htmlsafe(str); - } + if (matches && matches.length === 3) { + author = `${htmlsafe(matches[1])}`; + } else { + author = htmlsafe(str); } + } - return author; + return author; }; /** @@ -519,7 +519,7 @@ exports.resolveAuthorLinks = str => { * does not match. * @return {array} The matching items. */ -const find = exports.find = (data, spec) => data(spec).get(); +const find = (exports.find = (data, spec) => data(spec).get()); /** * Retrieve all of the following types of members from a set of doclets: @@ -535,35 +535,35 @@ const find = exports.find = (data, spec) => data(spec).get(); * @return {object} An object with `classes`, `externals`, `globals`, `mixins`, `modules`, * `events`, and `namespaces` properties. Each property contains an array of objects. */ -exports.getMembers = data => { - const members = { - classes: find( data, {kind: 'class'} ), - externals: find( data, {kind: 'external'} ), - events: find( data, {kind: 'event'} ), - globals: find(data, { - kind: ['member', 'function', 'constant', 'typedef'], - memberof: { isUndefined: true } - }), - mixins: find( data, {kind: 'mixin'} ), - modules: find( data, {kind: 'module'} ), - namespaces: find( data, {kind: 'namespace'} ), - interfaces: find( data, {kind: 'interface'} ) - }; +exports.getMembers = (data) => { + const members = { + classes: find(data, { kind: 'class' }), + externals: find(data, { kind: 'external' }), + events: find(data, { kind: 'event' }), + globals: find(data, { + kind: ['member', 'function', 'constant', 'typedef'], + memberof: { isUndefined: true }, + }), + mixins: find(data, { kind: 'mixin' }), + modules: find(data, { kind: 'module' }), + namespaces: find(data, { kind: 'namespace' }), + interfaces: find(data, { kind: 'interface' }), + }; - // strip quotes from externals, since we allow quoted names that would normally indicate a - // namespace hierarchy (as in `@external "jquery.fn"`) - // TODO: we should probably be doing this for other types of symbols, here or elsewhere; see - // jsdoc3/jsdoc#396 - members.externals = members.externals.map(doclet => { - doclet.name = doclet.name.replace(/(^"|"$)/g, ''); + // strip quotes from externals, since we allow quoted names that would normally indicate a + // namespace hierarchy (as in `@external "jquery.fn"`) + // TODO: we should probably be doing this for other types of symbols, here or elsewhere; see + // jsdoc3/jsdoc#396 + members.externals = members.externals.map((doclet) => { + doclet.name = doclet.name.replace(/(^"|"$)/g, ''); - return doclet; - }); + return doclet; + }); - // functions that are also modules (as in `module.exports = function() {};`) are not globals - members.globals = members.globals.filter(doclet => !isModuleExports(doclet)); + // functions that are also modules (as in `module.exports = function() {};`) are not globals + members.globals = members.globals.filter((doclet) => !isModuleExports(doclet)); - return members; + return members; }; /** @@ -572,53 +572,52 @@ exports.getMembers = data => { * @param {object} d The doclet whose attributes will be retrieved. * @return {array} The member attributes for the doclet. */ -exports.getAttribs = d => { - const attribs = []; - - if (!d) { - return attribs; - } - - if (d.async) { - attribs.push('async'); - } - - if (d.generator) { - attribs.push('generator'); - } - - if (d.virtual) { - attribs.push('abstract'); - } - - if (d.access && d.access !== 'public') { - attribs.push(d.access); - } - - if (d.scope && d.scope !== 'instance' && d.scope !== SCOPE.NAMES.GLOBAL) { - if (d.kind === 'function' || d.kind === 'member' || d.kind === 'constant') { - attribs.push(d.scope); - } - } - - if (d.readonly === true) { - if (d.kind === 'member') { - attribs.push('readonly'); - } - } - - if (d.kind === 'constant') { - attribs.push('constant'); - } - - if (d.nullable === true) { - attribs.push('nullable'); - } - else if (d.nullable === false) { - attribs.push('non-null'); - } +exports.getAttribs = (d) => { + const attribs = []; + if (!d) { return attribs; + } + + if (d.async) { + attribs.push('async'); + } + + if (d.generator) { + attribs.push('generator'); + } + + if (d.virtual) { + attribs.push('abstract'); + } + + if (d.access && d.access !== 'public') { + attribs.push(d.access); + } + + if (d.scope && d.scope !== 'instance' && d.scope !== SCOPE.NAMES.GLOBAL) { + if (d.kind === 'function' || d.kind === 'member' || d.kind === 'constant') { + attribs.push(d.scope); + } + } + + if (d.readonly === true) { + if (d.kind === 'member') { + attribs.push('readonly'); + } + } + + if (d.kind === 'constant') { + attribs.push('constant'); + } + + if (d.nullable === true) { + attribs.push('nullable'); + } else if (d.nullable === false) { + attribs.push('non-null'); + } + + return attribs; }; /** @@ -628,18 +627,18 @@ exports.getAttribs = d => { * @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link. * @return {Array.} HTML links to allowed types for the member. */ -exports.getSignatureTypes = ({type}, cssClass) => { - let types = []; +exports.getSignatureTypes = ({ type }, cssClass) => { + let types = []; - if (type && type.names) { - types = type.names; - } + if (type && type.names) { + types = type.names; + } - if (types && types.length) { - types = types.map(t => linkto(t, htmlsafe(t), cssClass)); - } + if (types && types.length) { + types = types.map((t) => linkto(t, htmlsafe(t), cssClass)); + } - return types; + return types; }; /** @@ -652,23 +651,22 @@ exports.getSignatureTypes = ({type}, cssClass) => { * @return {array} An array of parameter names, with or without `` tags wrapping the * names of optional parameters. */ -exports.getSignatureParams = ({params}, optClass) => { - const pnames = []; +exports.getSignatureParams = ({ params }, optClass) => { + const pnames = []; - if (params) { - params.forEach(p => { - if (p.name && !p.name.includes('.')) { - if (p.optional && optClass) { - pnames.push(`${p.name}`); - } - else { - pnames.push(p.name); - } - } - }); - } + if (params) { + params.forEach((p) => { + if (p.name && !p.name.includes('.')) { + if (p.optional && optClass) { + pnames.push(`${p.name}`); + } else { + pnames.push(p.name); + } + } + }); + } - return pnames; + return pnames; }; /** @@ -678,24 +676,24 @@ exports.getSignatureParams = ({params}, optClass) => { * @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link. * @return {Array.} HTML links to types that the member can return or yield. */ -exports.getSignatureReturns = ({yields, returns}, cssClass) => { - let returnTypes = []; +exports.getSignatureReturns = ({ yields, returns }, cssClass) => { + let returnTypes = []; - if (yields || returns) { - (yields || returns).forEach(r => { - if (r && r.type && r.type.names) { - if (!returnTypes.length) { - returnTypes = r.type.names; - } - } - }); - } + if (yields || returns) { + (yields || returns).forEach((r) => { + if (r && r.type && r.type.names) { + if (!returnTypes.length) { + returnTypes = r.type.names; + } + } + }); + } - if (returnTypes && returnTypes.length) { - returnTypes = returnTypes.map(r => linkto(r, htmlsafe(r), cssClass)); - } + if (returnTypes && returnTypes.length) { + returnTypes = returnTypes.map((r) => linkto(r, htmlsafe(r), cssClass)); + } - return returnTypes; + return returnTypes; }; /** @@ -707,25 +705,25 @@ exports.getSignatureReturns = ({yields, returns}, cssClass) => { * least distant. */ exports.getAncestors = (data, doclet) => { - const ancestors = []; - let doc = doclet; - let previousDoc; + const ancestors = []; + let doc = doclet; + let previousDoc; - while (doc) { - previousDoc = doc; - doc = find(data, {longname: doc.memberof})[0]; + while (doc) { + previousDoc = doc; + doc = find(data, { longname: doc.memberof })[0]; - // prevent infinite loop that can be caused by duplicated module definitions - if (previousDoc === doc) { - break; - } - - if (doc) { - ancestors.unshift(doc); - } + // prevent infinite loop that can be caused by duplicated module definitions + if (previousDoc === doc) { + break; } - return ancestors; + if (doc) { + ancestors.unshift(doc); + } + } + + return ancestors; }; /** @@ -737,21 +735,21 @@ exports.getAncestors = (data, doclet) => { * @return {Array.} HTML links to a member's ancestors. */ exports.getAncestorLinks = (data, doclet, cssClass) => { - const ancestors = exports.getAncestors(data, doclet); - const links = []; + const ancestors = exports.getAncestors(data, doclet); + const links = []; - ancestors.forEach(ancestor => { - const linkText = (SCOPE_TO_PUNC[ancestor.scope] || '') + ancestor.name; - const link = linkto(ancestor.longname, linkText, cssClass); + ancestors.forEach((ancestor) => { + const linkText = (SCOPE_TO_PUNC[ancestor.scope] || '') + ancestor.name; + const link = linkto(ancestor.longname, linkText, cssClass); - links.push(link); - }); + links.push(link); + }); - if (links.length) { - links[links.length - 1] += (SCOPE_TO_PUNC[doclet.scope] || ''); - } + if (links.length) { + links[links.length - 1] += SCOPE_TO_PUNC[doclet.scope] || ''; + } - return links; + return links; }; /** @@ -760,40 +758,42 @@ exports.getAncestorLinks = (data, doclet, cssClass) => { * * @param {TAFFY} data - The TaffyDB database to search. */ -exports.addEventListeners = data => { - // just a cache to prevent me doing so many lookups - const _events = {}; - let doc; - let l; - // TODO: do this on the *pruned* data - // find all doclets that @listen to something. - /* eslint-disable no-invalid-this */ - const listeners = find(data, function() { - return this.listens && this.listens.length; - }); - /* eslint-enable no-invalid-this */ +exports.addEventListeners = (data) => { + // just a cache to prevent me doing so many lookups + const _events = {}; + let doc; + let l; + // TODO: do this on the *pruned* data + // find all doclets that @listen to something. + /* eslint-disable no-invalid-this */ + const listeners = find(data, function () { + return this.listens && this.listens.length; + }); + /* eslint-enable no-invalid-this */ - if (!listeners.length) { - return; - } + if (!listeners.length) { + return; + } - listeners.forEach(({listens, longname}) => { - l = listens; - l.forEach(eventLongname => { - doc = _events[eventLongname] || find(data, { - longname: eventLongname, - kind: 'event' - })[0]; - if (doc) { - if (!doc.listeners) { - doc.listeners = [longname]; - } else { - doc.listeners.push(longname); - } - _events[eventLongname] = _events[eventLongname] || doc; - } - }); + listeners.forEach(({ listens, longname }) => { + l = listens; + l.forEach((eventLongname) => { + doc = + _events[eventLongname] || + find(data, { + longname: eventLongname, + kind: 'event', + })[0]; + if (doc) { + if (!doc.listeners) { + doc.listeners = [longname]; + } else { + doc.listeners.push(longname); + } + _events[eventLongname] = _events[eventLongname] || doc; + } }); + }); }; /** @@ -807,30 +807,33 @@ exports.addEventListeners = data => { * @param {TAFFY} data The TaffyDB database to prune. * @return {TAFFY} The pruned database. */ -exports.prune = data => { - data({undocumented: true}).remove(); - data({ignore: true}).remove(); - data({memberof: ''}).remove(); +exports.prune = (data) => { + data({ undocumented: true }).remove(); + data({ ignore: true }).remove(); + data({ memberof: '' }).remove(); - if (!env.opts.access || (env.opts.access && !env.opts.access.includes('all'))) { - if (env.opts.access && !env.opts.access.includes('package')) { - data({access: 'package'}).remove(); - } - if (env.opts.access && !env.opts.access.includes('public')) { - data({access: 'public'}).remove(); - } - if (env.opts.access && !env.opts.access.includes('protected')) { - data({access: 'protected'}).remove(); - } - if (!env.opts.private && (!env.opts.access || (env.opts.access && !env.opts.access.includes('private')))) { - data({access: 'private'}).remove(); - } - if (env.opts.access && !env.opts.access.includes('undefined')) { - data({access: {isUndefined: true}}).remove(); - } + if (!env.opts.access || (env.opts.access && !env.opts.access.includes('all'))) { + if (env.opts.access && !env.opts.access.includes('package')) { + data({ access: 'package' }).remove(); } + if (env.opts.access && !env.opts.access.includes('public')) { + data({ access: 'public' }).remove(); + } + if (env.opts.access && !env.opts.access.includes('protected')) { + data({ access: 'protected' }).remove(); + } + if ( + !env.opts.private && + (!env.opts.access || (env.opts.access && !env.opts.access.includes('private'))) + ) { + data({ access: 'private' }).remove(); + } + if (env.opts.access && !env.opts.access.includes('undefined')) { + data({ access: { isUndefined: true } }).remove(); + } + } - return data; + return data; }; /** @@ -845,49 +848,49 @@ exports.prune = data => { * @param {module:jsdoc/doclet.Doclet} doclet - The doclet that will be used to create the URL. * @return {string} The URL to the generated documentation for the doclet. */ -exports.createLink = doclet => { - let fakeContainer; - let filename; - let fileUrl; - let fragment = ''; - const longname = doclet.longname; - let match; +exports.createLink = (doclet) => { + let fakeContainer; + let filename; + let fileUrl; + let fragment = ''; + const longname = doclet.longname; + let match; - // handle doclets in which doclet.longname implies that the doclet gets its own HTML file, but - // doclet.kind says otherwise. this happens due to mistagged JSDoc (for example, a module that - // somehow has doclet.kind set to `member`). - // TODO: generate a warning (ideally during parsing!) - if (!containers.includes(doclet.kind)) { - match = /(\S+):/.exec(longname); - if (match && containers.includes(match[1])) { - fakeContainer = match[1]; - } + // handle doclets in which doclet.longname implies that the doclet gets its own HTML file, but + // doclet.kind says otherwise. this happens due to mistagged JSDoc (for example, a module that + // somehow has doclet.kind set to `member`). + // TODO: generate a warning (ideally during parsing!) + if (!containers.includes(doclet.kind)) { + match = /(\S+):/.exec(longname); + if (match && containers.includes(match[1])) { + fakeContainer = match[1]; } + } - // the doclet gets its own HTML file - if ( containers.includes(doclet.kind) || isModuleExports(doclet) ) { - filename = getFilename(longname); + // the doclet gets its own HTML file + if (containers.includes(doclet.kind) || isModuleExports(doclet)) { + filename = getFilename(longname); + } + // mistagged version of a doclet that gets its own HTML file + else if (!containers.includes(doclet.kind) && fakeContainer) { + filename = getFilename(doclet.memberof || longname); + if (doclet.name !== doclet.longname) { + fragment = formatNameForLink(doclet); + fragment = getId(longname, fragment); } - // mistagged version of a doclet that gets its own HTML file - else if ( !containers.includes(doclet.kind) && fakeContainer ) { - filename = getFilename(doclet.memberof || longname); - if (doclet.name !== doclet.longname) { - fragment = formatNameForLink(doclet); - fragment = getId(longname, fragment); - } - } - // the doclet is within another HTML file - else { - filename = getFilename(doclet.memberof || exports.globalName); - if ( (doclet.name !== doclet.longname) || (doclet.scope === SCOPE.NAMES.GLOBAL) ) { - fragment = formatNameForLink(doclet); - fragment = getId(longname, fragment); - } + } + // the doclet is within another HTML file + else { + filename = getFilename(doclet.memberof || exports.globalName); + if (doclet.name !== doclet.longname || doclet.scope === SCOPE.NAMES.GLOBAL) { + fragment = formatNameForLink(doclet); + fragment = getId(longname, fragment); } + } - fileUrl = encodeURI( filename + fragmentHash(fragment) ); + fileUrl = encodeURI(filename + fragmentHash(fragment)); - return fileUrl; + return fileUrl; }; /** @@ -914,5 +917,5 @@ exports.longnamesToTree = longnamesToTree; * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. */ exports._replaceDictionary = function _replaceDictionary(dict) { - dictionary = dict; + dictionary = dict; }; diff --git a/packages/jsdoc/package-lock.json b/packages/jsdoc/package-lock.json index 0e069331..b49f671d 100644 --- a/packages/jsdoc/package-lock.json +++ b/packages/jsdoc/package-lock.json @@ -1,8 +1,134 @@ { "name": "jsdoc", "version": "4.0.0-dev.16", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "jsdoc", + "version": "4.0.0-dev.16", + "license": "Apache-2.0", + "dependencies": { + "@babel/parser": "^7.15.7", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "code-prettify": "^0.1.0", + "color-themes-for-google-code-prettify": "^2.0.4", + "common-path-prefix": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "lodash": "^4.17.21", + "open-sans-fonts": "^1.6.2", + "requizzle": "^0.2.3", + "strip-bom": "^4.0.0", + "strip-json-comments": "^3.1.1", + "taffydb": "2.6.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=v14.17.6" + } + }, + "node_modules/@babel/parser": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/code-prettify": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/code-prettify/-/code-prettify-0.1.0.tgz", + "integrity": "sha1-RocMyMGlDQm61TmzOpg9vUqjSx4=" + }, + "node_modules/color-themes-for-google-code-prettify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/color-themes-for-google-code-prettify/-/color-themes-for-google-code-prettify-2.0.4.tgz", + "integrity": "sha1-3urPZX/WhXaGR1TU5IbXjf2x54Q=", + "engines": { + "node": ">=5.9.0" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/open-sans-fonts": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/open-sans-fonts/-/open-sans-fonts-1.6.2.tgz", + "integrity": "sha512-vsJ6/Mm0TdUKQJqxfkXJy+0K2X0QeRuTmxQq9YE1ycziw6CbDPolDsHhQ6+ImoV/7OTh8K8ZTGklY1Z5nUAwug==" + }, + "node_modules/requizzle": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=" + } + }, "dependencies": { "@babel/parser": { "version": "7.15.7", diff --git a/packages/jsdoc/plugins/commentConvert.js b/packages/jsdoc/plugins/commentConvert.js index 44c23839..d42d8661 100644 --- a/packages/jsdoc/plugins/commentConvert.js +++ b/packages/jsdoc/plugins/commentConvert.js @@ -5,17 +5,17 @@ * @module plugins/commentConvert */ exports.handlers = { - /// - /// Convert ///-style comments into jsdoc comments. - /// @param e - /// @param e.filename - /// @param e.source - /// - beforeParse(e) { - e.source = e.source.replace(/(\n[ \t]*\/\/\/[^\n]*)+/g, $ => { - const replacement = `\n/**${$.replace(/^[ \t]*\/\/\//mg, '').replace(/(\n$|$)/, '*/$1')}`; + /// + /// Convert ///-style comments into jsdoc comments. + /// @param e + /// @param e.filename + /// @param e.source + /// + beforeParse(e) { + e.source = e.source.replace(/(\n[ \t]*\/\/\/[^\n]*)+/g, ($) => { + const replacement = `\n/**${$.replace(/^[ \t]*\/\/\//gm, '').replace(/(\n$|$)/, '*/$1')}`; - return replacement; - }); - } + return replacement; + }); + }, }; diff --git a/packages/jsdoc/plugins/commentsOnly.js b/packages/jsdoc/plugins/commentsOnly.js index fb39af2a..8875800f 100644 --- a/packages/jsdoc/plugins/commentsOnly.js +++ b/packages/jsdoc/plugins/commentsOnly.js @@ -4,14 +4,14 @@ * @module plugins/commentsOnly */ exports.handlers = { - beforeParse(e) { - // a JSDoc comment looks like: /**[one or more chars]*/ - const comments = e.source.match(/\/\*\*[\s\S]+?\*\//g); + beforeParse(e) { + // a JSDoc comment looks like: /**[one or more chars]*/ + const comments = e.source.match(/\/\*\*[\s\S]+?\*\//g); - if (comments) { - e.source = comments.join('\n\n'); - } else { - e.source = ''; // If file has no comments, parser should still receive no code - } + if (comments) { + e.source = comments.join('\n\n'); + } else { + e.source = ''; // If file has no comments, parser should still receive no code } + }, }; diff --git a/packages/jsdoc/plugins/escapeHtml.js b/packages/jsdoc/plugins/escapeHtml.js index 4c64d310..fa9fa151 100644 --- a/packages/jsdoc/plugins/escapeHtml.js +++ b/packages/jsdoc/plugins/escapeHtml.js @@ -4,15 +4,15 @@ * @module plugins/escapeHtml */ exports.handlers = { - /** - * Translate HTML tags in descriptions into safe entities. Replaces <, & and newlines - */ - newDoclet({doclet}) { - if (doclet.description) { - doclet.description = doclet.description - .replace(/&/g, '&') - .replace(/'); - } + /** + * Translate HTML tags in descriptions into safe entities. Replaces <, & and newlines + */ + newDoclet({ doclet }) { + if (doclet.description) { + doclet.description = doclet.description + .replace(/&/g, '&') + .replace(/'); } + }, }; diff --git a/packages/jsdoc/plugins/eventDumper.js b/packages/jsdoc/plugins/eventDumper.js index 0a522276..13297de0 100644 --- a/packages/jsdoc/plugins/eventDumper.js +++ b/packages/jsdoc/plugins/eventDumper.js @@ -10,20 +10,20 @@ const conf = env.conf.eventDumper || {}; // Dump the included parser events (defaults to all events) let events = conf.include || [ - 'parseBegin', - 'fileBegin', - 'beforeParse', - 'jsdocCommentFound', - 'symbolFound', - 'newDoclet', - 'fileComplete', - 'parseComplete', - 'processingComplete' + 'parseBegin', + 'fileBegin', + 'beforeParse', + 'jsdocCommentFound', + 'symbolFound', + 'newDoclet', + 'fileComplete', + 'parseComplete', + 'processingComplete', ]; // Don't dump the excluded parser events if (conf.exclude) { - events = _.difference(events, conf.exclude); + events = _.difference(events, conf.exclude); } /** @@ -33,25 +33,25 @@ if (conf.exclude) { * @return {Object} The modified object. */ function replaceNodeObjects(o) { - const OBJECT_PLACEHOLDER = ''; + const OBJECT_PLACEHOLDER = ''; - if (o.code && o.code.node) { - // don't break the original object! - o.code = _.cloneDeep(o.code); - o.code.node = OBJECT_PLACEHOLDER; - } + if (o.code && o.code.node) { + // don't break the original object! + o.code = _.cloneDeep(o.code); + o.code.node = OBJECT_PLACEHOLDER; + } - if (o.doclet && o.doclet.meta && o.doclet.meta.code && o.doclet.meta.code.node) { - // don't break the original object! - o.doclet.meta.code = _.cloneDeep(o.doclet.meta.code); - o.doclet.meta.code.node = OBJECT_PLACEHOLDER; - } + if (o.doclet && o.doclet.meta && o.doclet.meta.code && o.doclet.meta.code.node) { + // don't break the original object! + o.doclet.meta.code = _.cloneDeep(o.doclet.meta.code); + o.doclet.meta.code.node = OBJECT_PLACEHOLDER; + } - if (o.astnode) { - o.astnode = OBJECT_PLACEHOLDER; - } + if (o.astnode) { + o.astnode = OBJECT_PLACEHOLDER; + } - return o; + return o; } /** @@ -61,35 +61,43 @@ function replaceNodeObjects(o) { * @return {object} The fixed-up object. */ function cleanse(e) { - let result = {}; + let result = {}; - Object.keys(e).forEach(prop => { - // by default, don't stringify properties that contain an array of functions - if (!conf.includeFunctions && Array.isArray(e[prop]) && e[prop][0] && - String(typeof e[prop][0]) === 'function') { - result[prop] = `function[${e[prop].length}]`; - } - // never include functions that belong to the object - else if (typeof e[prop] !== 'function') { - result[prop] = e[prop]; - } - }); - - // allow users to omit node objects, which can be enormous - if (conf.omitNodes) { - result = replaceNodeObjects(result); + Object.keys(e).forEach((prop) => { + // by default, don't stringify properties that contain an array of functions + if ( + !conf.includeFunctions && + Array.isArray(e[prop]) && + e[prop][0] && + String(typeof e[prop][0]) === 'function' + ) { + result[prop] = `function[${e[prop].length}]`; } + // never include functions that belong to the object + else if (typeof e[prop] !== 'function') { + result[prop] = e[prop]; + } + }); - return result; + // allow users to omit node objects, which can be enormous + if (conf.omitNodes) { + result = replaceNodeObjects(result); + } + + return result; } exports.handlers = {}; -events.forEach(eventType => { - exports.handlers[eventType] = e => { - console.log(JSON.stringify({ - type: eventType, - content: cleanse(e) - }), null, 4); - }; +events.forEach((eventType) => { + exports.handlers[eventType] = (e) => { + console.log( + JSON.stringify({ + type: eventType, + content: cleanse(e), + }), + null, + 4 + ); + }; }); diff --git a/packages/jsdoc/plugins/overloadHelper.js b/packages/jsdoc/plugins/overloadHelper.js index 99fda762..f6d359ff 100644 --- a/packages/jsdoc/plugins/overloadHelper.js +++ b/packages/jsdoc/plugins/overloadHelper.js @@ -38,144 +38,143 @@ let functionDoclets; function hasUniqueValues(obj) { - let isUnique = true; - const seen = []; + let isUnique = true; + const seen = []; - Object.keys(obj).forEach(key => { - if (seen.includes(obj[key])) { - isUnique = false; - } + Object.keys(obj).forEach((key) => { + if (seen.includes(obj[key])) { + isUnique = false; + } - seen.push(obj[key]); - }); + seen.push(obj[key]); + }); - return isUnique; + return isUnique; } function getParamNames(params) { - const names = []; + const names = []; - params.forEach(param => { - let name = param.name || ''; + params.forEach((param) => { + let name = param.name || ''; - if (param.variable) { - name = `...${name}`; - } - if (name !== '') { - names.push(name); - } - }); + if (param.variable) { + name = `...${name}`; + } + if (name !== '') { + names.push(name); + } + }); - return names.length ? names.join(', ') : ''; + return names.length ? names.join(', ') : ''; } -function getParamVariation({params}) { - return getParamNames(params || []); +function getParamVariation({ params }) { + return getParamNames(params || []); } function getUniqueVariations(doclets) { - let counter = 0; - const variations = {}; - const docletKeys = Object.keys(doclets); + let counter = 0; + const variations = {}; + const docletKeys = Object.keys(doclets); - function getUniqueNumbers() { - docletKeys.forEach(doclet => { - let newLongname; + function getUniqueNumbers() { + docletKeys.forEach((doclet) => { + let newLongname; - while (true) { - counter++; - variations[doclet] = String(counter); + while (true) { + counter++; + variations[doclet] = String(counter); - // is this longname + variation unique? - newLongname = `${doclets[doclet].longname}(${variations[doclet]})`; - if ( !functionDoclets[newLongname] ) { - break; - } - } - }); - } - - function getUniqueNames() { - // start by trying to preserve existing variations - docletKeys.forEach(doclet => { - variations[doclet] = doclets[doclet].variation || getParamVariation(doclets[doclet]); - }); - - // if they're identical, try again, without preserving existing variations - if ( !hasUniqueValues(variations) ) { - docletKeys.forEach(doclet => { - variations[doclet] = getParamVariation(doclets[doclet]); - }); - - // if they're STILL identical, switch to numeric variations - if ( !hasUniqueValues(variations) ) { - getUniqueNumbers(); - } + // is this longname + variation unique? + newLongname = `${doclets[doclet].longname}(${variations[doclet]})`; + if (!functionDoclets[newLongname]) { + break; } - } + } + }); + } - // are we already using numeric variations? if so, keep doing that - if (functionDoclets[`${doclets.newDoclet.longname}(1)`]) { + function getUniqueNames() { + // start by trying to preserve existing variations + docletKeys.forEach((doclet) => { + variations[doclet] = doclets[doclet].variation || getParamVariation(doclets[doclet]); + }); + + // if they're identical, try again, without preserving existing variations + if (!hasUniqueValues(variations)) { + docletKeys.forEach((doclet) => { + variations[doclet] = getParamVariation(doclets[doclet]); + }); + + // if they're STILL identical, switch to numeric variations + if (!hasUniqueValues(variations)) { getUniqueNumbers(); + } } - else { - getUniqueNames(); - } + } - return variations; + // are we already using numeric variations? if so, keep doing that + if (functionDoclets[`${doclets.newDoclet.longname}(1)`]) { + getUniqueNumbers(); + } else { + getUniqueNames(); + } + + return variations; } function ensureUniqueLongname(newDoclet) { - const doclets = { - oldDoclet: functionDoclets[newDoclet.longname], - newDoclet: newDoclet - }; - const docletKeys = Object.keys(doclets); - let oldDocletLongname; - let variations = {}; + const doclets = { + oldDoclet: functionDoclets[newDoclet.longname], + newDoclet: newDoclet, + }; + const docletKeys = Object.keys(doclets); + let oldDocletLongname; + let variations = {}; - if (doclets.oldDoclet) { - oldDocletLongname = doclets.oldDoclet.longname; - // if the shared longname has a variation, like MyClass#myLongname(variation), - // remove the variation - if (doclets.oldDoclet.variation || doclets.oldDoclet.variation === '') { - docletKeys.forEach(doclet => { - doclets[doclet].longname = doclets[doclet].longname.replace(/\([\s\S]*\)$/, ''); - doclets[doclet].variation = null; - }); - } - - variations = getUniqueVariations(doclets); - - // update the longnames/variations - docletKeys.forEach(doclet => { - doclets[doclet].longname += `(${variations[doclet]})`; - doclets[doclet].variation = variations[doclet]; - }); - - // update the old doclet in the lookup table - functionDoclets[oldDocletLongname] = null; - functionDoclets[doclets.oldDoclet.longname] = doclets.oldDoclet; + if (doclets.oldDoclet) { + oldDocletLongname = doclets.oldDoclet.longname; + // if the shared longname has a variation, like MyClass#myLongname(variation), + // remove the variation + if (doclets.oldDoclet.variation || doclets.oldDoclet.variation === '') { + docletKeys.forEach((doclet) => { + doclets[doclet].longname = doclets[doclet].longname.replace(/\([\s\S]*\)$/, ''); + doclets[doclet].variation = null; + }); } - // always store the new doclet in the lookup table - functionDoclets[doclets.newDoclet.longname] = doclets.newDoclet; + variations = getUniqueVariations(doclets); - return doclets.newDoclet; + // update the longnames/variations + docletKeys.forEach((doclet) => { + doclets[doclet].longname += `(${variations[doclet]})`; + doclets[doclet].variation = variations[doclet]; + }); + + // update the old doclet in the lookup table + functionDoclets[oldDocletLongname] = null; + functionDoclets[doclets.oldDoclet.longname] = doclets.oldDoclet; + } + + // always store the new doclet in the lookup table + functionDoclets[doclets.newDoclet.longname] = doclets.newDoclet; + + return doclets.newDoclet; } exports.handlers = { - parseBegin() { - functionDoclets = {}; - }, + parseBegin() { + functionDoclets = {}; + }, - newDoclet(e) { - if (e.doclet.kind === 'function') { - e.doclet = ensureUniqueLongname(e.doclet); - } - }, - - parseComplete() { - functionDoclets = null; + newDoclet(e) { + if (e.doclet.kind === 'function') { + e.doclet = ensureUniqueLongname(e.doclet); } + }, + + parseComplete() { + functionDoclets = null; + }, }; diff --git a/packages/jsdoc/plugins/partial.js b/packages/jsdoc/plugins/partial.js index e3ea0ccd..f383f1ad 100644 --- a/packages/jsdoc/plugins/partial.js +++ b/packages/jsdoc/plugins/partial.js @@ -8,23 +8,23 @@ const fs = require('fs'); const path = require('path'); exports.handlers = { - /** - * Include a partial jsdoc - * - * @param e - * @param e.filename - * @param e.source - * @example - * @partial "partial_doc.jsdoc" - */ - beforeParse(e) { - e.source = e.source.replace(/(@partial ".*")+/g, $ => { - const pathArg = $.match(/".*"/)[0].replace(/"/g, ''); - const fullPath = path.join(e.filename, '..', pathArg); + /** + * Include a partial jsdoc + * + * @param e + * @param e.filename + * @param e.source + * @example + * @partial "partial_doc.jsdoc" + */ + beforeParse(e) { + e.source = e.source.replace(/(@partial ".*")+/g, ($) => { + const pathArg = $.match(/".*"/)[0].replace(/"/g, ''); + const fullPath = path.join(e.filename, '..', pathArg); - const partialData = fs.readFileSync(fullPath, env.opts.encoding); + const partialData = fs.readFileSync(fullPath, env.opts.encoding); - return partialData; - }); - } + return partialData; + }); + }, }; diff --git a/packages/jsdoc/plugins/railsTemplate.js b/packages/jsdoc/plugins/railsTemplate.js index d0eea131..773d8f4b 100644 --- a/packages/jsdoc/plugins/railsTemplate.js +++ b/packages/jsdoc/plugins/railsTemplate.js @@ -4,16 +4,16 @@ * @module plugins/railsTemplate */ exports.handlers = { - /** - * Remove rails tags from the source input (e.g. <% foo bar %>) - * - * @param e - * @param e.filename - * @param e.source - */ - beforeParse(e) { - if (e.filename.match(/\.erb$/)) { - e.source = e.source.replace(/<%.*%>/g, ''); - } + /** + * Remove rails tags from the source input (e.g. <% foo bar %>) + * + * @param e + * @param e.filename + * @param e.source + */ + beforeParse(e) { + if (e.filename.match(/\.erb$/)) { + e.source = e.source.replace(/<%.*%>/g, ''); } + }, }; diff --git a/packages/jsdoc/plugins/shout.js b/packages/jsdoc/plugins/shout.js index 433a1d83..6426f5ae 100644 --- a/packages/jsdoc/plugins/shout.js +++ b/packages/jsdoc/plugins/shout.js @@ -4,12 +4,12 @@ * @module plugins/shout */ exports.handlers = { - /** - * Make your descriptions more shoutier. - */ - newDoclet({doclet}) { - if (typeof doclet.description === 'string') { - doclet.description = doclet.description.toUpperCase(); - } + /** + * Make your descriptions more shoutier. + */ + newDoclet({ doclet }) { + if (typeof doclet.description === 'string') { + doclet.description = doclet.description.toUpperCase(); } + }, }; diff --git a/packages/jsdoc/plugins/sourcetag.js b/packages/jsdoc/plugins/sourcetag.js index 59444905..1de1b5ac 100644 --- a/packages/jsdoc/plugins/sourcetag.js +++ b/packages/jsdoc/plugins/sourcetag.js @@ -4,49 +4,48 @@ const { log } = require('@jsdoc/util'); exports.handlers = { - /** - * Support @source tag. Expected value like: - * - * { "filename": "myfile.js", "lineno": 123 } - * - * Modifies the corresponding meta values on the given doclet. - * - * WARNING: If you are using a JSDoc template that generates pretty-printed source files, - * such as JSDoc's default template, this plugin can cause JSDoc to crash. To fix this issue, - * update your template settings to disable pretty-printed source files. - * - * @source { "filename": "sourcetag.js", "lineno": 9 } - */ - newDoclet({doclet}) { - let tags = doclet.tags; - let tag; - let value; + /** + * Support @source tag. Expected value like: + * + * { "filename": "myfile.js", "lineno": 123 } + * + * Modifies the corresponding meta values on the given doclet. + * + * WARNING: If you are using a JSDoc template that generates pretty-printed source files, + * such as JSDoc's default template, this plugin can cause JSDoc to crash. To fix this issue, + * update your template settings to disable pretty-printed source files. + * + * @source { "filename": "sourcetag.js", "lineno": 9 } + */ + newDoclet({ doclet }) { + let tags = doclet.tags; + let tag; + let value; - // any user-defined tags in this doclet? - if (typeof tags !== 'undefined') { - // only interested in the @source tags - tags = tags.filter(({title}) => title === 'source'); + // any user-defined tags in this doclet? + if (typeof tags !== 'undefined') { + // only interested in the @source tags + tags = tags.filter(({ title }) => title === 'source'); - if (tags.length) { - // take the first one - tag = tags[0]; + if (tags.length) { + // take the first one + tag = tags[0]; - try { - value = JSON.parse(tag.value); - } - catch (ex) { - log.error( - '@source tag expects a valid JSON value, like ' + - '{ "filename": "myfile.js", "lineno": 123 }.' - ); + try { + value = JSON.parse(tag.value); + } catch (ex) { + log.error( + '@source tag expects a valid JSON value, like ' + + '{ "filename": "myfile.js", "lineno": 123 }.' + ); - return; - } - - doclet.meta = doclet.meta || {}; - doclet.meta.filename = value.filename || ''; - doclet.meta.lineno = value.lineno || ''; - } + return; } + + doclet.meta = doclet.meta || {}; + doclet.meta.filename = value.filename || ''; + doclet.meta.lineno = value.lineno || ''; + } } + }, }; diff --git a/packages/jsdoc/plugins/summarize.js b/packages/jsdoc/plugins/summarize.js index 2b397844..23cc4799 100644 --- a/packages/jsdoc/plugins/summarize.js +++ b/packages/jsdoc/plugins/summarize.js @@ -4,55 +4,55 @@ * @module plugins/summarize */ exports.handlers = { - /** - * Autogenerate summaries, if missing, from the description, if present. - */ - newDoclet({doclet}) { - let endTag; - let tags; - let stack; + /** + * Autogenerate summaries, if missing, from the description, if present. + */ + newDoclet({ doclet }) { + let endTag; + let tags; + let stack; - // If the summary is missing, grab the first sentence from the description - // and use that. - if (doclet && !doclet.summary && doclet.description) { - // The summary may end with `.$`, `. `, or `.<` (a period followed by an HTML tag). - doclet.summary = doclet.description.split(/\.$|\.\s|\.]+>/g) || []; - stack = []; + // This is an excerpt of something that is possibly HTML. + // Balance it using a stack. Assume it was initially balanced. + tags = doclet.summary.match(/<[^>]+>/g) || []; + stack = []; - tags.forEach(tag => { - const idx = tag.indexOf('/'); + tags.forEach((tag) => { + const idx = tag.indexOf('/'); - if (idx === -1) { - // start tag -- push onto the stack - stack.push(tag); - } else if (idx === 1) { - // end tag -- pop off of the stack - stack.pop(); - } - - // otherwise, it's a self-closing tag; don't modify the stack - }); - - // stack should now contain only the start tags that lack end tags, - // with the most deeply nested start tag at the top - while (stack.length > 0) { - // pop the unmatched tag off the stack - endTag = stack.pop(); - // get just the tag name - endTag = endTag.substring(1, endTag.search(/[ >]/)); - // append the end tag - doclet.summary += ``; - } - - // and, finally, if the summary starts and ends with a

tag, remove it; let the - // template decide whether to wrap the summary in a

tag - doclet.summary = doclet.summary.replace(/^

(.*)<\/p>$/i, '$1'); + if (idx === -1) { + // start tag -- push onto the stack + stack.push(tag); + } else if (idx === 1) { + // end tag -- pop off of the stack + stack.pop(); } + + // otherwise, it's a self-closing tag; don't modify the stack + }); + + // stack should now contain only the start tags that lack end tags, + // with the most deeply nested start tag at the top + while (stack.length > 0) { + // pop the unmatched tag off the stack + endTag = stack.pop(); + // get just the tag name + endTag = endTag.substring(1, endTag.search(/[ >]/)); + // append the end tag + doclet.summary += ``; + } + + // and, finally, if the summary starts and ends with a

tag, remove it; let the + // template decide whether to wrap the summary in a

tag + doclet.summary = doclet.summary.replace(/^

(.*)<\/p>$/i, '$1'); } + }, }; diff --git a/packages/jsdoc/plugins/test/specs/commentConvert.js b/packages/jsdoc/plugins/test/specs/commentConvert.js index 1209a3ee..1066b6ef 100644 --- a/packages/jsdoc/plugins/test/specs/commentConvert.js +++ b/packages/jsdoc/plugins/test/specs/commentConvert.js @@ -1,20 +1,20 @@ /* global jsdoc */ describe('commentConvert plugin', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let docSet; - const parser = jsdoc.createParser(); - const pluginPath = 'plugins/commentConvert'; - const pluginPathResolved = path.join(env.dirname, pluginPath); + let docSet; + const parser = jsdoc.createParser(); + const pluginPath = 'plugins/commentConvert'; + const pluginPathResolved = path.join(env.dirname, pluginPath); - require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); - docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); + require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); + docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); - it('should convert ///-style comments into jsdoc comments', () => { - const doclet = docSet.getByLongname('module:plugins/commentConvert.handlers.beforeParse'); + it('should convert ///-style comments into jsdoc comments', () => { + const doclet = docSet.getByLongname('module:plugins/commentConvert.handlers.beforeParse'); - expect(doclet.length).toEqual(1); - }); + expect(doclet.length).toEqual(1); + }); }); diff --git a/packages/jsdoc/plugins/test/specs/escapeHtml.js b/packages/jsdoc/plugins/test/specs/escapeHtml.js index 8d74202b..c5911bd7 100644 --- a/packages/jsdoc/plugins/test/specs/escapeHtml.js +++ b/packages/jsdoc/plugins/test/specs/escapeHtml.js @@ -1,20 +1,22 @@ /* global jsdoc */ describe('escapeHtml plugin', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let docSet; - const parser = jsdoc.createParser(); - const pluginPath = 'plugins/escapeHtml'; - const pluginPathResolved = path.join(env.dirname, pluginPath); + let docSet; + const parser = jsdoc.createParser(); + const pluginPath = 'plugins/escapeHtml'; + const pluginPathResolved = path.join(env.dirname, pluginPath); - require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); - docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); + require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); + docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); - it("should escape '&', '<' and newlines in doclet descriptions", () => { - const doclet = docSet.getByLongname('module:plugins/escapeHtml.handlers.newDoclet'); + it("should escape '&', '<' and newlines in doclet descriptions", () => { + const doclet = docSet.getByLongname('module:plugins/escapeHtml.handlers.newDoclet'); - expect(doclet[0].description).toBe('Translate HTML tags in descriptions into safe ' + - 'entities. Replaces <, & and newlines'); - }); + expect(doclet[0].description).toBe( + 'Translate HTML tags in descriptions into safe ' + + 'entities. Replaces <, & and newlines' + ); + }); }); diff --git a/packages/jsdoc/plugins/test/specs/overloadHelper.js b/packages/jsdoc/plugins/test/specs/overloadHelper.js index 2aec7fe3..de45bbcd 100644 --- a/packages/jsdoc/plugins/test/specs/overloadHelper.js +++ b/packages/jsdoc/plugins/test/specs/overloadHelper.js @@ -1,101 +1,101 @@ /* global jsdoc */ describe('plugins/overloadHelper', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let docSet; - const parser = jsdoc.createParser(); - const pluginPath = 'plugins/overloadHelper'; - const pluginPathResolved = path.resolve(env.dirname, pluginPath); - const plugin = require(pluginPathResolved); + let docSet; + const parser = jsdoc.createParser(); + const pluginPath = 'plugins/overloadHelper'; + const pluginPathResolved = path.resolve(env.dirname, pluginPath); + const plugin = require(pluginPathResolved); - require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); - docSet = jsdoc.getDocSetFromFile('plugins/test/fixtures/overloadHelper.js', parser); + require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); + docSet = jsdoc.getDocSetFromFile('plugins/test/fixtures/overloadHelper.js', parser); - it('should exist', () => { - expect(plugin).toBeDefined(); - expect(typeof plugin).toBe('object'); + it('should exist', () => { + expect(plugin).toBeDefined(); + expect(typeof plugin).toBe('object'); + }); + + it('should export handlers', () => { + expect(plugin.handlers).toBeDefined(); + expect(typeof plugin.handlers).toBe('object'); + }); + + it('should export a "newDoclet" handler', () => { + expect(plugin.handlers.newDoclet).toBeDefined(); + expect(typeof plugin.handlers.newDoclet).toBe('function'); + }); + + it('should export a "parseComplete" handler', () => { + expect(plugin.handlers.parseComplete).toBeDefined(); + expect(typeof plugin.handlers.parseComplete).toBe('function'); + }); + + describe('newDoclet handler', () => { + it('should not add unique longnames to constructors', () => { + const soup = docSet.getByLongname('Soup'); + const soup1 = docSet.getByLongname('Soup()'); + const soup2 = docSet.getByLongname('Soup(spiciness)'); + + expect(soup.length).toBe(2); + expect(soup1.length).toBe(0); + expect(soup2.length).toBe(0); }); - it('should export handlers', () => { - expect(plugin.handlers).toBeDefined(); - expect(typeof plugin.handlers).toBe('object'); + it('should add unique longnames to methods', () => { + const slurp = docSet.getByLongname('Soup#slurp'); + const slurp1 = docSet.getByLongname('Soup#slurp()'); + const slurp2 = docSet.getByLongname('Soup#slurp(dBA)'); + + expect(slurp.length).toBe(0); + expect(slurp1.length).toBe(1); + expect(slurp2.length).toBe(1); }); - it('should export a "newDoclet" handler', () => { - expect(plugin.handlers.newDoclet).toBeDefined(); - expect(typeof plugin.handlers.newDoclet).toBe('function'); + it('should update the "variation" property of the method', () => { + const slurp1 = docSet.getByLongname('Soup#slurp()')[0]; + const slurp2 = docSet.getByLongname('Soup#slurp(dBA)')[0]; + + expect(slurp1.variation).toBe(''); + expect(slurp2.variation).toBe('dBA'); }); - it('should export a "parseComplete" handler', () => { - expect(plugin.handlers.parseComplete).toBeDefined(); - expect(typeof plugin.handlers.parseComplete).toBe('function'); + it('should not add to or change existing variations that are unique', () => { + const salt1 = docSet.getByLongname('Soup#salt'); + const salt2 = docSet.getByLongname('Soup#salt(mg)'); + + expect(salt1.length).toBe(1); + expect(salt2.length).toBe(1); }); - describe('newDoclet handler', () => { - it('should not add unique longnames to constructors', () => { - const soup = docSet.getByLongname('Soup'); - const soup1 = docSet.getByLongname('Soup()'); - const soup2 = docSet.getByLongname('Soup(spiciness)'); + it('should not duplicate the names of existing numeric variations', () => { + const heat1 = docSet.getByLongname('Soup#heat(1)'); + const heat2 = docSet.getByLongname('Soup#heat(2)'); + const heat3 = docSet.getByLongname('Soup#heat(3)'); - expect(soup.length).toBe(2); - expect(soup1.length).toBe(0); - expect(soup2.length).toBe(0); - }); - - it('should add unique longnames to methods', () => { - const slurp = docSet.getByLongname('Soup#slurp'); - const slurp1 = docSet.getByLongname('Soup#slurp()'); - const slurp2 = docSet.getByLongname('Soup#slurp(dBA)'); - - expect(slurp.length).toBe(0); - expect(slurp1.length).toBe(1); - expect(slurp2.length).toBe(1); - }); - - it('should update the "variation" property of the method', () => { - const slurp1 = docSet.getByLongname('Soup#slurp()')[0]; - const slurp2 = docSet.getByLongname('Soup#slurp(dBA)')[0]; - - expect(slurp1.variation).toBe(''); - expect(slurp2.variation).toBe('dBA'); - }); - - it('should not add to or change existing variations that are unique', () => { - const salt1 = docSet.getByLongname('Soup#salt'); - const salt2 = docSet.getByLongname('Soup#salt(mg)'); - - expect(salt1.length).toBe(1); - expect(salt2.length).toBe(1); - }); - - it('should not duplicate the names of existing numeric variations', () => { - const heat1 = docSet.getByLongname('Soup#heat(1)'); - const heat2 = docSet.getByLongname('Soup#heat(2)'); - const heat3 = docSet.getByLongname('Soup#heat(3)'); - - expect(heat1.length).toBe(1); - expect(heat2.length).toBe(1); - expect(heat3.length).toBe(1); - }); - - it('should replace identical variations with new, unique variations', () => { - const discard1 = docSet.getByLongname('Soup#discard()'); - const discard2 = docSet.getByLongname('Soup#discard(container)'); - - expect(discard1.length).toBe(1); - expect(discard2.length).toBe(1); - }); + expect(heat1.length).toBe(1); + expect(heat2.length).toBe(1); + expect(heat3.length).toBe(1); }); - describe('parseComplete handler', () => { - // disabled because on the second run, each comment is being parsed twice; who knows why... - xit('should not retain parse results between parser runs', () => { - parser.clear(); - docSet = jsdoc.getDocSetFromFile('plugins/test/fixtures/overloadHelper.js', parser); - const heat = docSet.getByLongname('Soup#heat(4)'); + it('should replace identical variations with new, unique variations', () => { + const discard1 = docSet.getByLongname('Soup#discard()'); + const discard2 = docSet.getByLongname('Soup#discard(container)'); - expect(heat.length).toBe(0); - }); + expect(discard1.length).toBe(1); + expect(discard2.length).toBe(1); }); + }); + + describe('parseComplete handler', () => { + // disabled because on the second run, each comment is being parsed twice; who knows why... + xit('should not retain parse results between parser runs', () => { + parser.clear(); + docSet = jsdoc.getDocSetFromFile('plugins/test/fixtures/overloadHelper.js', parser); + const heat = docSet.getByLongname('Soup#heat(4)'); + + expect(heat.length).toBe(0); + }); + }); }); diff --git a/packages/jsdoc/plugins/test/specs/railsTemplate.js b/packages/jsdoc/plugins/test/specs/railsTemplate.js index 5110e401..e45a1ebb 100644 --- a/packages/jsdoc/plugins/test/specs/railsTemplate.js +++ b/packages/jsdoc/plugins/test/specs/railsTemplate.js @@ -1,17 +1,19 @@ /* global jsdoc */ describe('railsTemplate plugin', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - const parser = jsdoc.createParser(); - const pluginPath = path.join(env.dirname, 'plugins/railsTemplate'); + const parser = jsdoc.createParser(); + const pluginPath = path.join(env.dirname, 'plugins/railsTemplate'); - require('jsdoc/plugins').installPlugins([pluginPath], parser); - require('jsdoc/src/handlers').attachTo(parser); + require('jsdoc/plugins').installPlugins([pluginPath], parser); + require('jsdoc/src/handlers').attachTo(parser); - it('should remove <% %> rails template tags from the source of *.erb files', () => { - const docSet = parser.parse([path.join(env.dirname, 'plugins/test/fixtures/railsTemplate.js.erb')]); + it('should remove <% %> rails template tags from the source of *.erb files', () => { + const docSet = parser.parse([ + path.join(env.dirname, 'plugins/test/fixtures/railsTemplate.js.erb'), + ]); - expect(docSet[2].description).toEqual('Remove rails tags from the source input (e.g. )'); - }); + expect(docSet[2].description).toEqual('Remove rails tags from the source input (e.g. )'); + }); }); diff --git a/packages/jsdoc/plugins/test/specs/shout.js b/packages/jsdoc/plugins/test/specs/shout.js index 56464d20..8831c2bb 100644 --- a/packages/jsdoc/plugins/test/specs/shout.js +++ b/packages/jsdoc/plugins/test/specs/shout.js @@ -1,19 +1,19 @@ /* global jsdoc */ describe('shout plugin', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let docSet; - const parser = jsdoc.createParser(); - const pluginPath = 'plugins/shout'; - const pluginPathResolved = path.join(env.dirname, pluginPath); + let docSet; + const parser = jsdoc.createParser(); + const pluginPath = 'plugins/shout'; + const pluginPathResolved = path.join(env.dirname, pluginPath); - require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); - docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); + require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); + docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); - it('should make the description uppercase', () => { - const doclet = docSet.getByLongname('module:plugins/shout.handlers.newDoclet'); + it('should make the description uppercase', () => { + const doclet = docSet.getByLongname('module:plugins/shout.handlers.newDoclet'); - expect(doclet[0].description).toEqual('MAKE YOUR DESCRIPTIONS MORE SHOUTIER.'); - }); + expect(doclet[0].description).toEqual('MAKE YOUR DESCRIPTIONS MORE SHOUTIER.'); + }); }); diff --git a/packages/jsdoc/plugins/test/specs/sourcetag.js b/packages/jsdoc/plugins/test/specs/sourcetag.js index 2dc703d9..3e1f693a 100644 --- a/packages/jsdoc/plugins/test/specs/sourcetag.js +++ b/packages/jsdoc/plugins/test/specs/sourcetag.js @@ -1,21 +1,21 @@ /* global jsdoc */ describe('sourcetag plugin', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let docSet; - const parser = jsdoc.createParser(); - const pluginPath = 'plugins/sourcetag'; - const pluginPathResolved = path.join(env.dirname, pluginPath); + let docSet; + const parser = jsdoc.createParser(); + const pluginPath = 'plugins/sourcetag'; + const pluginPathResolved = path.join(env.dirname, pluginPath); - require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); - docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); + require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); + docSet = jsdoc.getDocSetFromFile(`${pluginPath}.js`, parser); - it("should set the lineno and filename of the doclet's meta property", () => { - const doclet = docSet.getByLongname('module:plugins/sourcetag.handlers.newDoclet'); + it("should set the lineno and filename of the doclet's meta property", () => { + const doclet = docSet.getByLongname('module:plugins/sourcetag.handlers.newDoclet'); - expect(doclet[0].meta).toBeDefined(); - expect(doclet[0].meta.filename).toEqual('sourcetag.js'); - expect(doclet[0].meta.lineno).toEqual(9); - }); + expect(doclet[0].meta).toBeDefined(); + expect(doclet[0].meta.filename).toEqual('sourcetag.js'); + expect(doclet[0].meta.lineno).toEqual(9); + }); }); diff --git a/packages/jsdoc/plugins/test/specs/summarize.js b/packages/jsdoc/plugins/test/specs/summarize.js index b259628a..f39d307d 100644 --- a/packages/jsdoc/plugins/test/specs/summarize.js +++ b/packages/jsdoc/plugins/test/specs/summarize.js @@ -1,116 +1,122 @@ const summarize = require('../../summarize'); describe('summarize', () => { - it('should export handlers', () => { - expect(summarize.handlers).toBeDefined(); - expect(typeof summarize.handlers).toBe('object'); + it('should export handlers', () => { + expect(summarize.handlers).toBeDefined(); + expect(typeof summarize.handlers).toBe('object'); + }); + + it('should export a newDoclet handler', () => { + expect(summarize.handlers.newDoclet).toBeDefined(); + expect(typeof summarize.handlers.newDoclet).toBe('function'); + }); + + describe('newDoclet handler', () => { + const handler = summarize.handlers.newDoclet; + + it('should not blow up if the doclet is missing', () => { + function noDoclet() { + return handler({}); + } + + expect(noDoclet).not.toThrow(); }); - it('should export a newDoclet handler', () => { - expect(summarize.handlers.newDoclet).toBeDefined(); - expect(typeof summarize.handlers.newDoclet).toBe('function'); + it('should not change the summary if it is already defined', () => { + const doclet = { + summary: 'This is a summary.', + description: 'Descriptions are good.', + }; + + handler({ doclet: doclet }); + + expect(doclet.summary).not.toBe(doclet.description); }); - describe('newDoclet handler', () => { - const handler = summarize.handlers.newDoclet; + it('should not do anything if the description is missing', () => { + const doclet = {}; - it('should not blow up if the doclet is missing', () => { - function noDoclet() { - return handler({}); - } + handler({ doclet: doclet }); - expect(noDoclet).not.toThrow(); - }); - - it('should not change the summary if it is already defined', () => { - const doclet = { - summary: 'This is a summary.', - description: 'Descriptions are good.' - }; - - handler({ doclet: doclet }); - - expect(doclet.summary).not.toBe(doclet.description); - }); - - it('should not do anything if the description is missing', () => { - const doclet = {}; - - handler({ doclet: doclet }); - - expect(doclet.summary).not.toBeDefined(); - }); - - it('should use the first sentence as the summary', () => { - const doclet = { - description: 'This sentence is the summary. This sentence is not.' - }; - - handler({ doclet: doclet }); - - expect(doclet.summary).toBe('This sentence is the summary.'); - }); - - it('should not add an extra period if there is only one sentence in the description', () => { - const doclet = { - description: 'This description has only one sentence.' - }; - - handler({ doclet: doclet }); - - expect(doclet.summary).toBe('This description has only one sentence.'); - }); - - it('should use the entire description, plus a period, as the summary if the description ' + - 'does not contain a period', () => { - const doclet = { - description: 'This is a description' - }; - - handler({ doclet: doclet }); - - expect(doclet.summary).toBe('This is a description.'); - }); - - it('should use the entire description as the summary if the description contains only ' + - 'one sentence', () => { - const doclet = { - description: 'This is a description.' - }; - - handler({ doclet: doclet }); - - expect(doclet.description).toBe('This is a description.'); - }); - - it('should work when an HTML tag immediately follows the first sentence', () => { - const doclet = { - description: 'This sentence is the summary.This sentence is small.' - }; - - handler({ doclet: doclet }); - - expect(doclet.summary).toBe('This sentence is the summary.'); - }); - - it('should generate valid HTML if a tag is opened, but not closed, in the summary', () => { - const doclet = { - description: 'This description has a tag. The tag straddles sentences.' - }; - - handler({ doclet: doclet }); - - expect(doclet.summary).toBe('This description has a tag.'); - }); - - it('should not include a

tag in the summary', () => { - const doclet = { - description: '

This description contains HTML.

And plenty of it!

' - }; - - handler({ doclet: doclet }); - - expect(doclet.summary).toBe('This description contains HTML.'); - }); + expect(doclet.summary).not.toBeDefined(); }); + + it('should use the first sentence as the summary', () => { + const doclet = { + description: 'This sentence is the summary. This sentence is not.', + }; + + handler({ doclet: doclet }); + + expect(doclet.summary).toBe('This sentence is the summary.'); + }); + + it('should not add an extra period if there is only one sentence in the description', () => { + const doclet = { + description: 'This description has only one sentence.', + }; + + handler({ doclet: doclet }); + + expect(doclet.summary).toBe('This description has only one sentence.'); + }); + + it( + 'should use the entire description, plus a period, as the summary if the description ' + + 'does not contain a period', + () => { + const doclet = { + description: 'This is a description', + }; + + handler({ doclet: doclet }); + + expect(doclet.summary).toBe('This is a description.'); + } + ); + + it( + 'should use the entire description as the summary if the description contains only ' + + 'one sentence', + () => { + const doclet = { + description: 'This is a description.', + }; + + handler({ doclet: doclet }); + + expect(doclet.description).toBe('This is a description.'); + } + ); + + it('should work when an HTML tag immediately follows the first sentence', () => { + const doclet = { + description: 'This sentence is the summary.This sentence is small.', + }; + + handler({ doclet: doclet }); + + expect(doclet.summary).toBe('This sentence is the summary.'); + }); + + it('should generate valid HTML if a tag is opened, but not closed, in the summary', () => { + const doclet = { + description: 'This description has a tag. The tag straddles sentences.', + }; + + handler({ doclet: doclet }); + + expect(doclet.summary).toBe('This description has a tag.'); + }); + + it('should not include a

tag in the summary', () => { + const doclet = { + description: '

This description contains HTML.

And plenty of it!

', + }; + + handler({ doclet: doclet }); + + expect(doclet.summary).toBe('This description contains HTML.'); + }); + }); }); diff --git a/packages/jsdoc/plugins/test/specs/underscore.js b/packages/jsdoc/plugins/test/specs/underscore.js index 17b276c6..8de3d7a9 100644 --- a/packages/jsdoc/plugins/test/specs/underscore.js +++ b/packages/jsdoc/plugins/test/specs/underscore.js @@ -1,37 +1,37 @@ /* global jsdoc */ describe('underscore plugin', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let docSet; - const parser = jsdoc.createParser(); - const pluginPath = 'plugins/underscore'; - const fixturePath = 'plugins/test/fixtures/underscore'; - const pluginPathResolved = path.join(env.dirname, pluginPath); + let docSet; + const parser = jsdoc.createParser(); + const pluginPath = 'plugins/underscore'; + const fixturePath = 'plugins/test/fixtures/underscore'; + const pluginPathResolved = path.join(env.dirname, pluginPath); - require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); - docSet = jsdoc.getDocSetFromFile(`${fixturePath}.js`, parser); + require('jsdoc/plugins').installPlugins([pluginPathResolved], parser); + docSet = jsdoc.getDocSetFromFile(`${fixturePath}.js`, parser); - it('should not mark normal, public properties as private', () => { - // Base line tests - const normal = docSet.getByLongname('normal'); + it('should not mark normal, public properties as private', () => { + // Base line tests + const normal = docSet.getByLongname('normal'); - expect(normal[0].access).toBeUndefined(); + expect(normal[0].access).toBeUndefined(); - const realPrivate = docSet.getByLongname('Klass#privateProp'); + const realPrivate = docSet.getByLongname('Klass#privateProp'); - expect(realPrivate[0].access).toEqual('private'); - }); + expect(realPrivate[0].access).toEqual('private'); + }); - it('should hide doclet for symbols beginning with an underscore under normal circumstances', () => { - const hidden = docSet.getByLongname('_hidden'); + it('should hide doclet for symbols beginning with an underscore under normal circumstances', () => { + const hidden = docSet.getByLongname('_hidden'); - expect(hidden[0].access).toEqual('private'); - }); + expect(hidden[0].access).toEqual('private'); + }); - it('picks up "this"', () => { - const privateUnderscore = docSet.getByLongname('Klass#_privateProp'); + it('picks up "this"', () => { + const privateUnderscore = docSet.getByLongname('Klass#_privateProp'); - expect(privateUnderscore[0].access).toEqual('private'); - }); + expect(privateUnderscore[0].access).toEqual('private'); + }); }); diff --git a/packages/jsdoc/plugins/underscore.js b/packages/jsdoc/plugins/underscore.js index 1bb48c7e..a89ab558 100644 --- a/packages/jsdoc/plugins/underscore.js +++ b/packages/jsdoc/plugins/underscore.js @@ -7,10 +7,10 @@ */ exports.handlers = { - newDoclet({doclet}) { - // Ignore comment blocks for all symbols that begin with underscore - if (doclet.name.charAt(0) === '_' || doclet.name.substr(0, 6) === 'this._') { - doclet.access = 'private'; - } + newDoclet({ doclet }) { + // Ignore comment blocks for all symbols that begin with underscore + if (doclet.name.charAt(0) === '_' || doclet.name.substr(0, 6) === 'this._') { + doclet.access = 'private'; } + }, }; diff --git a/packages/jsdoc/templates/README.md b/packages/jsdoc/templates/README.md index 7424e741..d60c10fd 100644 --- a/packages/jsdoc/templates/README.md +++ b/packages/jsdoc/templates/README.md @@ -5,7 +5,7 @@ To create or use your own template: For example: -````javascript +```javascript /** @module publish */ /** @@ -15,13 +15,13 @@ For example: * all the symbols documented in your code. * @param {object} opts - An object with options information. */ -exports.publish = function(data, opts) { - // do stuff here to generate your output files +exports.publish = function (data, opts) { + // do stuff here to generate your output files }; -```` +``` To invoke JSDoc 3 with your own template, use the `-t` command line option, and specify the path to your template folder: -```` +``` ./jsdoc mycode.js -t /path/to/mycooltemplate -```` +``` diff --git a/packages/jsdoc/templates/default/publish.js b/packages/jsdoc/templates/default/publish.js index ef5fa52b..de923531 100644 --- a/packages/jsdoc/templates/default/publish.js +++ b/packages/jsdoc/templates/default/publish.js @@ -15,20 +15,15 @@ const resolveAuthorLinks = helper.resolveAuthorLinks; const hasOwnProp = Object.prototype.hasOwnProperty; const FONT_NAMES = [ - 'OpenSans-Bold', - 'OpenSans-BoldItalic', - 'OpenSans-Italic', - 'OpenSans-Light', - 'OpenSans-LightItalic', - 'OpenSans-Regular' -]; -const PRETTIFIER_CSS_FILES = [ - 'tomorrow.min.css' -]; -const PRETTIFIER_SCRIPT_FILES = [ - 'lang-css.js', - 'prettify.js' + 'OpenSans-Bold', + 'OpenSans-BoldItalic', + 'OpenSans-Italic', + 'OpenSans-Light', + 'OpenSans-LightItalic', + 'OpenSans-Regular', ]; +const PRETTIFIER_CSS_FILES = ['tomorrow.min.css']; +const PRETTIFIER_SCRIPT_FILES = ['lang-css.js', 'prettify.js']; let data; let view; @@ -36,242 +31,244 @@ let view; let outdir = path.normalize(env.opts.destination); function mkdirpSync(filepath) { - return fs.mkdirSync(filepath, { recursive: true }); + return fs.mkdirSync(filepath, { recursive: true }); } function find(spec) { - return helper.find(data, spec); + return helper.find(data, spec); } function getAncestorLinks(doclet) { - return helper.getAncestorLinks(data, doclet); + return helper.getAncestorLinks(data, doclet); } function hashToLink(doclet, hash) { - let url; + let url; - if ( !/^(#.+)/.test(hash) ) { - return hash; - } + if (!/^(#.+)/.test(hash)) { + return hash; + } - url = helper.createLink(doclet); - url = url.replace(/(#.+|$)/, hash); + url = helper.createLink(doclet); + url = url.replace(/(#.+|$)/, hash); - return `${hash}`; + return `${hash}`; } -function needsSignature({kind, type, meta}) { - let needsSig = false; +function needsSignature({ kind, type, meta }) { + let needsSig = false; - // function and class definitions always get a signature - if (kind === 'function' || kind === 'class') { - needsSig = true; - } - // typedefs that contain functions get a signature, too - else if (kind === 'typedef' && type && type.names && - type.names.length) { - for (let i = 0, l = type.names.length; i < l; i++) { - if (type.names[i].toLowerCase() === 'function') { - needsSig = true; - break; - } - } - } - // and namespaces that are functions get a signature (but finding them is a - // bit messy) - else if (kind === 'namespace' && meta && meta.code && - meta.code.type && meta.code.type.match(/[Ff]unction/)) { + // function and class definitions always get a signature + if (kind === 'function' || kind === 'class') { + needsSig = true; + } + // typedefs that contain functions get a signature, too + else if (kind === 'typedef' && type && type.names && type.names.length) { + for (let i = 0, l = type.names.length; i < l; i++) { + if (type.names[i].toLowerCase() === 'function') { needsSig = true; + break; + } } + } + // and namespaces that are functions get a signature (but finding them is a + // bit messy) + else if ( + kind === 'namespace' && + meta && + meta.code && + meta.code.type && + meta.code.type.match(/[Ff]unction/) + ) { + needsSig = true; + } - return needsSig; + return needsSig; } -function getSignatureAttributes({optional, nullable}) { - const attributes = []; +function getSignatureAttributes({ optional, nullable }) { + const attributes = []; - if (optional) { - attributes.push('opt'); - } + if (optional) { + attributes.push('opt'); + } - if (nullable === true) { - attributes.push('nullable'); - } - else if (nullable === false) { - attributes.push('non-null'); - } + if (nullable === true) { + attributes.push('nullable'); + } else if (nullable === false) { + attributes.push('non-null'); + } - return attributes; + return attributes; } function updateItemName(item) { - const attributes = getSignatureAttributes(item); - let itemName = item.name || ''; + const attributes = getSignatureAttributes(item); + let itemName = item.name || ''; - if (item.variable) { - itemName = `…${itemName}`; - } + if (item.variable) { + itemName = `…${itemName}`; + } - if (attributes && attributes.length) { - itemName = `${itemName}${attributes.join(', ')}`; - } + if (attributes && attributes.length) { + itemName = `${itemName}${attributes.join(', ')}`; + } - return itemName; + return itemName; } function addParamAttributes(params) { - return params.filter(({name}) => name && !name.includes('.')).map(updateItemName); + return params.filter(({ name }) => name && !name.includes('.')).map(updateItemName); } function buildItemTypeStrings(item) { - const types = []; + const types = []; - if (item && item.type && item.type.names) { - item.type.names.forEach(name => { - types.push( linkto(name, htmlsafe(name)) ); - }); - } + if (item && item.type && item.type.names) { + item.type.names.forEach((name) => { + types.push(linkto(name, htmlsafe(name))); + }); + } - return types; + return types; } function buildAttribsString(attribs) { - let attribsString = ''; + let attribsString = ''; - if (attribs && attribs.length) { - htmlsafe(`(${attribs.join(', ')}) `); - } + if (attribs && attribs.length) { + htmlsafe(`(${attribs.join(', ')}) `); + } - return attribsString; + return attribsString; } function addNonParamAttributes(items) { - let types = []; + let types = []; - items.forEach(item => { - types = types.concat( buildItemTypeStrings(item) ); - }); + items.forEach((item) => { + types = types.concat(buildItemTypeStrings(item)); + }); - return types; + return types; } function addSignatureParams(f) { - const params = f.params ? addParamAttributes(f.params) : []; + const params = f.params ? addParamAttributes(f.params) : []; - f.signature = `${f.signature || ''}(${params.join(', ')})`; + f.signature = `${f.signature || ''}(${params.join(', ')})`; } function addSignatureReturns(f) { - const attribs = []; - let attribsString = ''; - let returnTypes = []; - let returnTypesString = ''; - const source = f.yields || f.returns; + const attribs = []; + let attribsString = ''; + let returnTypes = []; + let returnTypesString = ''; + const source = f.yields || f.returns; - // jam all the return-type attributes into an array. this could create odd results (for example, - // if there are both nullable and non-nullable return types), but let's assume that most people - // who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa. - if (source) { - source.forEach(item => { - helper.getAttribs(item).forEach(attrib => { - if (!attribs.includes(attrib)) { - attribs.push(attrib); - } - }); - }); + // jam all the return-type attributes into an array. this could create odd results (for example, + // if there are both nullable and non-nullable return types), but let's assume that most people + // who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa. + if (source) { + source.forEach((item) => { + helper.getAttribs(item).forEach((attrib) => { + if (!attribs.includes(attrib)) { + attribs.push(attrib); + } + }); + }); - attribsString = buildAttribsString(attribs); - } + attribsString = buildAttribsString(attribs); + } - if (source) { - returnTypes = addNonParamAttributes(source); - } - if (returnTypes.length) { - returnTypesString = ` → ${attribsString}{${returnTypes.join('|')}}`; - } + if (source) { + returnTypes = addNonParamAttributes(source); + } + if (returnTypes.length) { + returnTypesString = ` → ${attribsString}{${returnTypes.join('|')}}`; + } - f.signature = `${f.signature || ''}` + - `${returnTypesString}`; + f.signature = + `${f.signature || ''}` + + `${returnTypesString}`; } function addSignatureTypes(f) { - const types = f.type ? buildItemTypeStrings(f) : []; + const types = f.type ? buildItemTypeStrings(f) : []; - f.signature = `${f.signature || ''}` + - `${types.length ? ` :${types.join('|')}` : ''}`; + f.signature = + `${f.signature || ''}` + + `${types.length ? ` :${types.join('|')}` : ''}`; } function addAttribs(f) { - const attribs = helper.getAttribs(f); - const attribsString = buildAttribsString(attribs); + const attribs = helper.getAttribs(f); + const attribsString = buildAttribsString(attribs); - f.attribs = `${attribsString}`; + f.attribs = `${attribsString}`; } function shortenPaths(files, commonPrefix) { - Object.keys(files).forEach(file => { - files[file].shortened = files[file].resolved.replace(commonPrefix, '') - // always use forward slashes - .replace(/\\/g, '/'); - }); + Object.keys(files).forEach((file) => { + files[file].shortened = files[file].resolved + .replace(commonPrefix, '') + // always use forward slashes + .replace(/\\/g, '/'); + }); - return files; + return files; } -function getPathFromDoclet({meta}) { - if (!meta) { - return null; - } +function getPathFromDoclet({ meta }) { + if (!meta) { + return null; + } - return meta.path && meta.path !== 'null' ? - path.join(meta.path, meta.filename) : - meta.filename; + return meta.path && meta.path !== 'null' ? path.join(meta.path, meta.filename) : meta.filename; } function generate(title, docs, filename, resolveLinks) { - let docData; - let html; - let outpath; + let docData; + let html; + let outpath; - resolveLinks = resolveLinks !== false; + resolveLinks = resolveLinks !== false; - docData = { - env: env, - title: title, - docs: docs - }; + docData = { + env: env, + title: title, + docs: docs, + }; - outpath = path.join(outdir, filename); - html = view.render('container.tmpl', docData); + outpath = path.join(outdir, filename); + html = view.render('container.tmpl', docData); - if (resolveLinks) { - html = helper.resolveLinks(html); // turn {@link foo} into foo - } + if (resolveLinks) { + html = helper.resolveLinks(html); // turn {@link foo} into foo + } - fs.writeFileSync(outpath, html, 'utf8'); + fs.writeFileSync(outpath, html, 'utf8'); } function generateSourceFiles(sourceFiles, encoding = 'utf8') { - Object.keys(sourceFiles).forEach(file => { - let source; - // links are keyed to the shortened path in each doclet's `meta.shortpath` property - const sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened); + Object.keys(sourceFiles).forEach((file) => { + let source; + // links are keyed to the shortened path in each doclet's `meta.shortpath` property + const sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened); - helper.registerLink(sourceFiles[file].shortened, sourceOutfile); + helper.registerLink(sourceFiles[file].shortened, sourceOutfile); - try { - source = { - kind: 'source', - code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) ) - }; - } - catch (e) { - log.error(`Error while generating source file ${file}: ${e.message}`); - } + try { + source = { + kind: 'source', + code: helper.htmlsafe(fs.readFileSync(sourceFiles[file].resolved, encoding)), + }; + } catch (e) { + log.error(`Error while generating source file ${file}: ${e.message}`); + } - generate(`Source: ${sourceFiles[file].shortened}`, [source], sourceOutfile, - false); - }); + generate(`Source: ${sourceFiles[file].shortened}`, [source], sourceOutfile, false); + }); } /** @@ -286,67 +283,69 @@ function generateSourceFiles(sourceFiles, encoding = 'utf8') { * @param {Array.} modules - The array of module doclets to search. */ function attachModuleSymbols(doclets, modules) { - const symbols = {}; + const symbols = {}; - // build a lookup table - doclets.forEach(symbol => { - symbols[symbol.longname] = symbols[symbol.longname] || []; - symbols[symbol.longname].push(symbol); - }); + // build a lookup table + doclets.forEach((symbol) => { + symbols[symbol.longname] = symbols[symbol.longname] || []; + symbols[symbol.longname].push(symbol); + }); - modules.forEach(module => { - if (symbols[module.longname]) { - module.modules = symbols[module.longname] - // Only show symbols that have a description. Make an exception for classes, because - // we want to show the constructor-signature heading no matter what. - .filter(({description, kind}) => description || kind === 'class') - .map(symbol => { - symbol = _.cloneDeep(symbol); + modules.forEach((module) => { + if (symbols[module.longname]) { + module.modules = symbols[module.longname] + // Only show symbols that have a description. Make an exception for classes, because + // we want to show the constructor-signature heading no matter what. + .filter(({ description, kind }) => description || kind === 'class') + .map((symbol) => { + symbol = _.cloneDeep(symbol); - if (symbol.kind === 'class' || symbol.kind === 'function') { - symbol.name = `${symbol.name.replace('module:', '(require("')}"))`; - } + if (symbol.kind === 'class' || symbol.kind === 'function') { + symbol.name = `${symbol.name.replace('module:', '(require("')}"))`; + } - return symbol; - }); - } - }); + return symbol; + }); + } + }); } function buildMemberNav(items, itemHeading, itemsSeen, linktoFn) { - let nav = ''; + let nav = ''; - if (items.length) { - let itemsNav = ''; + if (items.length) { + let itemsNav = ''; - items.forEach(item => { - let displayName; + items.forEach((item) => { + let displayName; - if ( !hasOwnProp.call(item, 'longname') ) { - itemsNav += `
  • ${linktoFn('', item.name)}
  • `; - } - else if ( !hasOwnProp.call(itemsSeen, item.longname) ) { - if (env.conf.templates.default.useLongnameInNav) { - displayName = item.longname; - } else { - displayName = item.name; - } - itemsNav += `
  • ${linktoFn(item.longname, displayName.replace(/\b(module|event):/g, ''))}
  • `; - - itemsSeen[item.longname] = true; - } - }); - - if (itemsNav !== '') { - nav += `

    ${itemHeading}

      ${itemsNav}
    `; + if (!hasOwnProp.call(item, 'longname')) { + itemsNav += `
  • ${linktoFn('', item.name)}
  • `; + } else if (!hasOwnProp.call(itemsSeen, item.longname)) { + if (env.conf.templates.default.useLongnameInNav) { + displayName = item.longname; + } else { + displayName = item.name; } - } + itemsNav += `
  • ${linktoFn( + item.longname, + displayName.replace(/\b(module|event):/g, '') + )}
  • `; - return nav; + itemsSeen[item.longname] = true; + } + }); + + if (itemsNav !== '') { + nav += `

    ${itemHeading}

      ${itemsNav}
    `; + } + } + + return nav; } function linktoExternal(longName, name) { - return linkto(longName, name.replace(/(^"|"$)/g, '')); + return linkto(longName, name.replace(/(^"|"$)/g, '')); } /** @@ -363,44 +362,43 @@ function linktoExternal(longName, name) { * @return {string} The HTML for the navigation sidebar. */ function buildNav(members) { - let globalNav; - let nav = '

    Home

    '; - const seen = {}; + let globalNav; + let nav = '

    Home

    '; + const seen = {}; - nav += buildMemberNav(members.modules, 'Modules', {}, linkto); - nav += buildMemberNav(members.externals, 'Externals', seen, linktoExternal); - nav += buildMemberNav(members.namespaces, 'Namespaces', seen, linkto); - nav += buildMemberNav(members.classes, 'Classes', seen, linkto); - nav += buildMemberNav(members.interfaces, 'Interfaces', seen, linkto); - nav += buildMemberNav(members.events, 'Events', seen, linkto); - nav += buildMemberNav(members.mixins, 'Mixins', seen, linkto); + nav += buildMemberNav(members.modules, 'Modules', {}, linkto); + nav += buildMemberNav(members.externals, 'Externals', seen, linktoExternal); + nav += buildMemberNav(members.namespaces, 'Namespaces', seen, linkto); + nav += buildMemberNav(members.classes, 'Classes', seen, linkto); + nav += buildMemberNav(members.interfaces, 'Interfaces', seen, linkto); + nav += buildMemberNav(members.events, 'Events', seen, linkto); + nav += buildMemberNav(members.mixins, 'Mixins', seen, linkto); - if (members.globals.length) { - globalNav = ''; + if (members.globals.length) { + globalNav = ''; - members.globals.forEach(({kind, longname, name}) => { - if ( kind !== 'typedef' && !hasOwnProp.call(seen, longname) ) { - globalNav += `
  • ${linkto(longname, name)}
  • `; - } - seen[longname] = true; - }); + members.globals.forEach(({ kind, longname, name }) => { + if (kind !== 'typedef' && !hasOwnProp.call(seen, longname)) { + globalNav += `
  • ${linkto(longname, name)}
  • `; + } + seen[longname] = true; + }); - if (!globalNav) { - // turn the heading into a link so you can actually get to the global page - nav += `

    ${linkto('global', 'Global')}

    `; - } - else { - nav += `

    Global

      ${globalNav}
    `; - } + if (!globalNav) { + // turn the heading into a link so you can actually get to the global page + nav += `

    ${linkto('global', 'Global')}

    `; + } else { + nav += `

    Global

      ${globalNav}
    `; } + } - return nav; + return nav; } function sourceToDestination(parentDir, sourcePath, destDir) { - const relativeSource = path.relative(parentDir, sourcePath); + const relativeSource = path.relative(parentDir, sourcePath); - return path.resolve(path.join(destDir, relativeSource)); + return path.resolve(path.join(destDir, relativeSource)); } /** @@ -408,307 +406,306 @@ function sourceToDestination(parentDir, sourcePath, destDir) { @param {object} opts */ exports.publish = (taffyData, opts) => { - let classes; - let conf; - let cwd; - let externals; - let files; - let fromDir; - let globalUrl; - let indexUrl; - let interfaces; - let members; - let mixins; - let modules; - let namespaces; - let outputSourceFiles; - let packageInfo; - let packages; - const sourceFilePaths = []; - let sourceFiles = {}; - let staticFileFilter; - let staticFilePaths; - let staticFiles; - let staticFileScanner; - let templatePath; + let classes; + let conf; + let cwd; + let externals; + let files; + let fromDir; + let globalUrl; + let indexUrl; + let interfaces; + let members; + let mixins; + let modules; + let namespaces; + let outputSourceFiles; + let packageInfo; + let packages; + const sourceFilePaths = []; + let sourceFiles = {}; + let staticFileFilter; + let staticFilePaths; + let staticFiles; + let staticFileScanner; + let templatePath; - data = taffyData; + data = taffyData; - conf = env.conf.templates || {}; - conf.default = conf.default || {}; + conf = env.conf.templates || {}; + conf.default = conf.default || {}; - templatePath = path.normalize(opts.template); - view = new template.Template( path.join(templatePath, 'tmpl') ); + templatePath = path.normalize(opts.template); + view = new template.Template(path.join(templatePath, 'tmpl')); - // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness - // doesn't try to hand them out later - indexUrl = helper.getUniqueFilename('index'); - // don't call registerLink() on this one! 'index' is also a valid longname + // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness + // doesn't try to hand them out later + indexUrl = helper.getUniqueFilename('index'); + // don't call registerLink() on this one! 'index' is also a valid longname - globalUrl = helper.getUniqueFilename('global'); - helper.registerLink('global', globalUrl); + globalUrl = helper.getUniqueFilename('global'); + helper.registerLink('global', globalUrl); - // set up templating - view.layout = conf.default.layoutFile ? - path.resolve(conf.default.layoutFile) : - 'layout.tmpl'; + // set up templating + view.layout = conf.default.layoutFile ? path.resolve(conf.default.layoutFile) : 'layout.tmpl'; - data = helper.prune(data); - data.sort('longname, version, since'); - helper.addEventListeners(data); + data = helper.prune(data); + data.sort('longname, version, since'); + helper.addEventListeners(data); - data().each(doclet => { - let sourcePath; + data().each((doclet) => { + let sourcePath; - doclet.attribs = ''; + doclet.attribs = ''; - if (doclet.examples) { - doclet.examples = doclet.examples.map(example => { - let caption; - let code; + if (doclet.examples) { + doclet.examples = doclet.examples.map((example) => { + let caption; + let code; - if (example.match(/^\s*([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { - caption = RegExp.$1; - code = RegExp.$3; - } - - return { - caption: caption || '', - code: code || example - }; - }); - } - if (doclet.see) { - doclet.see.forEach((seeItem, i) => { - doclet.see[i] = hashToLink(doclet, seeItem); - }); + if (example.match(/^\s*([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { + caption = RegExp.$1; + code = RegExp.$3; } - // build a list of source files - if (doclet.meta) { - sourcePath = getPathFromDoclet(doclet); - sourceFiles[sourcePath] = { - resolved: sourcePath, - shortened: null - }; - if (!sourceFilePaths.includes(sourcePath)) { - sourceFilePaths.push(sourcePath); - } - } - }); - - // update outdir if necessary, then create outdir - packageInfo = ( find({kind: 'package'}) || [] )[0]; - if (packageInfo && packageInfo.name) { - outdir = path.join( outdir, packageInfo.name, (packageInfo.version || '') ); + return { + caption: caption || '', + code: code || example, + }; + }); + } + if (doclet.see) { + doclet.see.forEach((seeItem, i) => { + doclet.see[i] = hashToLink(doclet, seeItem); + }); } - mkdirpSync(outdir); - // copy the template's static files to outdir - fromDir = path.join(templatePath, 'static'); - staticFiles = lsSync(fromDir); + // build a list of source files + if (doclet.meta) { + sourcePath = getPathFromDoclet(doclet); + sourceFiles[sourcePath] = { + resolved: sourcePath, + shortened: null, + }; + if (!sourceFilePaths.includes(sourcePath)) { + sourceFilePaths.push(sourcePath); + } + } + }); - staticFiles.forEach(fileName => { + // update outdir if necessary, then create outdir + packageInfo = (find({ kind: 'package' }) || [])[0]; + if (packageInfo && packageInfo.name) { + outdir = path.join(outdir, packageInfo.name, packageInfo.version || ''); + } + mkdirpSync(outdir); + + // copy the template's static files to outdir + fromDir = path.join(templatePath, 'static'); + staticFiles = lsSync(fromDir); + + staticFiles.forEach((fileName) => { + const toPath = sourceToDestination(fromDir, fileName, outdir); + + mkdirpSync(path.dirname(toPath)); + fs.copyFileSync(fileName, toPath); + }); + + // copy the fonts used by the template to outdir + staticFiles = lsSync(path.join(require.resolve('open-sans-fonts'), '..', 'open-sans')); + + staticFiles.forEach((fileName) => { + const toPath = path.join(outdir, 'fonts', path.basename(fileName)); + + if (FONT_NAMES.includes(path.parse(fileName).name)) { + mkdirpSync(path.dirname(toPath)); + fs.copyFileSync(fileName, toPath); + } + }); + + // copy the prettify script to outdir + PRETTIFIER_SCRIPT_FILES.forEach((fileName) => { + const toPath = path.join(outdir, 'scripts', path.basename(fileName)); + + fs.copyFileSync(path.join(require.resolve('code-prettify'), '..', fileName), toPath); + }); + + // copy the prettify CSS to outdir + PRETTIFIER_CSS_FILES.forEach((fileName) => { + const toPath = path.join(outdir, 'styles', path.basename(fileName)); + + fs.copyFileSync( + // `require.resolve()` has trouble with this package, so we use an extra-hacky way to + // get the filepath. + path.join( + templatePath, + '..', + '..', + 'node_modules', + 'color-themes-for-google-code-prettify', + 'dist', + 'themes', + fileName + ), + toPath + ); + }); + + // copy user-specified static files to outdir + if (conf.default.staticFiles) { + // The canonical property name is `include`. We accept `paths` for backwards compatibility + // with a bug in JSDoc 3.2.x. + staticFilePaths = conf.default.staticFiles.include || conf.default.staticFiles.paths || []; + staticFileFilter = new (require('jsdoc/src/filter').Filter)(conf.default.staticFiles); + staticFileScanner = new (require('jsdoc/src/scanner').Scanner)(); + cwd = process.cwd(); + + staticFilePaths.forEach((filePath) => { + let extraStaticFiles; + + filePath = path.resolve(cwd, filePath); + extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); + + extraStaticFiles.forEach((fileName) => { const toPath = sourceToDestination(fromDir, fileName, outdir); mkdirpSync(path.dirname(toPath)); fs.copyFileSync(fileName, toPath); + }); }); + } - // copy the fonts used by the template to outdir - staticFiles = lsSync(path.join(require.resolve('open-sans-fonts'), '..', 'open-sans')); + if (sourceFilePaths.length) { + sourceFiles = shortenPaths(sourceFiles, commonPathPrefix(sourceFilePaths)); + } + data().each((doclet) => { + let docletPath; + const url = helper.createLink(doclet); - staticFiles.forEach(fileName => { - const toPath = path.join(outdir, 'fonts', path.basename(fileName)); + helper.registerLink(doclet.longname, url); - if (FONT_NAMES.includes(path.parse(fileName).name)) { - mkdirpSync(path.dirname(toPath)); - fs.copyFileSync(fileName, toPath); - } - }); + // add a shortened version of the full path + if (doclet.meta) { + docletPath = getPathFromDoclet(doclet); + docletPath = sourceFiles[docletPath].shortened; + if (docletPath) { + doclet.meta.shortpath = docletPath; + } + } + }); - // copy the prettify script to outdir - PRETTIFIER_SCRIPT_FILES.forEach(fileName => { - const toPath = path.join(outdir, 'scripts', path.basename(fileName)); + data().each((doclet) => { + const url = helper.longnameToUrl[doclet.longname]; - fs.copyFileSync( - path.join(require.resolve('code-prettify'), '..', fileName), - toPath - ); - }); - - // copy the prettify CSS to outdir - PRETTIFIER_CSS_FILES.forEach(fileName => { - const toPath = path.join(outdir, 'styles', path.basename(fileName)); - - fs.copyFileSync( - // `require.resolve()` has trouble with this package, so we use an extra-hacky way to - // get the filepath. - path.join( - templatePath, - '..', - '..', - 'node_modules', - 'color-themes-for-google-code-prettify', - 'dist', - 'themes', - fileName - ), - toPath - ); - }); - - // copy user-specified static files to outdir - if (conf.default.staticFiles) { - // The canonical property name is `include`. We accept `paths` for backwards compatibility - // with a bug in JSDoc 3.2.x. - staticFilePaths = conf.default.staticFiles.include || - conf.default.staticFiles.paths || - []; - staticFileFilter = new (require('jsdoc/src/filter').Filter)(conf.default.staticFiles); - staticFileScanner = new (require('jsdoc/src/scanner').Scanner)(); - cwd = process.cwd(); - - staticFilePaths.forEach(filePath => { - let extraStaticFiles; - - filePath = path.resolve(cwd, filePath); - extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); - - extraStaticFiles.forEach(fileName => { - const toPath = sourceToDestination(fromDir, fileName, outdir); - - mkdirpSync(path.dirname(toPath)); - fs.copyFileSync(fileName, toPath); - }); - }); + if (url.includes('#')) { + doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); + } else { + doclet.id = doclet.name; } - if (sourceFilePaths.length) { - sourceFiles = shortenPaths( sourceFiles, commonPathPrefix(sourceFilePaths) ); + if (needsSignature(doclet)) { + addSignatureParams(doclet); + addSignatureReturns(doclet); + addAttribs(doclet); } - data().each(doclet => { - let docletPath; - const url = helper.createLink(doclet); + }); - helper.registerLink(doclet.longname, url); + // do this after the urls have all been generated + data().each((doclet) => { + doclet.ancestors = getAncestorLinks(doclet); - // add a shortened version of the full path - if (doclet.meta) { - docletPath = getPathFromDoclet(doclet); - docletPath = sourceFiles[docletPath].shortened; - if (docletPath) { - doclet.meta.shortpath = docletPath; - } - } - }); - - data().each(doclet => { - const url = helper.longnameToUrl[doclet.longname]; - - if (url.includes('#')) { - doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); - } - else { - doclet.id = doclet.name; - } - - if ( needsSignature(doclet) ) { - addSignatureParams(doclet); - addSignatureReturns(doclet); - addAttribs(doclet); - } - }); - - // do this after the urls have all been generated - data().each(doclet => { - doclet.ancestors = getAncestorLinks(doclet); - - if (doclet.kind === 'member') { - addSignatureTypes(doclet); - addAttribs(doclet); - } - - if (doclet.kind === 'constant') { - addSignatureTypes(doclet); - addAttribs(doclet); - doclet.kind = 'member'; - } - }); - - members = helper.getMembers(data); - - // output pretty-printed source files by default - outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false; - - // add template helpers - view.find = find; - view.linkto = linkto; - view.resolveAuthorLinks = resolveAuthorLinks; - view.htmlsafe = htmlsafe; - view.outputSourceFiles = outputSourceFiles; - - // once for all - view.nav = buildNav(members); - attachModuleSymbols( find({ longname: {left: 'module:'} }), members.modules ); - - // generate the pretty-printed source files first so other pages can link to them - if (outputSourceFiles) { - generateSourceFiles(sourceFiles, opts.encoding); + if (doclet.kind === 'member') { + addSignatureTypes(doclet); + addAttribs(doclet); } - if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } + if (doclet.kind === 'constant') { + addSignatureTypes(doclet); + addAttribs(doclet); + doclet.kind = 'member'; + } + }); - // index page displays information from package.json and lists files - files = find({kind: 'file'}); - packages = find({kind: 'package'}); + members = helper.getMembers(data); - generate('Home', - packages.concat( - [{ - kind: 'mainpage', - longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page' - }] - ).concat(files), indexUrl); + // output pretty-printed source files by default + outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false; - // set up the lists that we'll use to generate pages - classes = taffy(members.classes); - modules = taffy(members.modules); - namespaces = taffy(members.namespaces); - mixins = taffy(members.mixins); - externals = taffy(members.externals); - interfaces = taffy(members.interfaces); + // add template helpers + view.find = find; + view.linkto = linkto; + view.resolveAuthorLinks = resolveAuthorLinks; + view.htmlsafe = htmlsafe; + view.outputSourceFiles = outputSourceFiles; - Object.keys(helper.longnameToUrl).forEach(longname => { - const myClasses = helper.find(classes, {longname: longname}); - const myExternals = helper.find(externals, {longname: longname}); - const myInterfaces = helper.find(interfaces, {longname: longname}); - const myMixins = helper.find(mixins, {longname: longname}); - const myModules = helper.find(modules, {longname: longname}); - const myNamespaces = helper.find(namespaces, {longname: longname}); + // once for all + view.nav = buildNav(members); + attachModuleSymbols(find({ longname: { left: 'module:' } }), members.modules); - if (myModules.length) { - generate(`Module: ${myModules[0].name}`, myModules, helper.longnameToUrl[longname]); - } + // generate the pretty-printed source files first so other pages can link to them + if (outputSourceFiles) { + generateSourceFiles(sourceFiles, opts.encoding); + } - if (myClasses.length) { - generate(`Class: ${myClasses[0].name}`, myClasses, helper.longnameToUrl[longname]); - } + if (members.globals.length) { + generate('Global', [{ kind: 'globalobj' }], globalUrl); + } - if (myNamespaces.length) { - generate(`Namespace: ${myNamespaces[0].name}`, myNamespaces, helper.longnameToUrl[longname]); - } + // index page displays information from package.json and lists files + files = find({ kind: 'file' }); + packages = find({ kind: 'package' }); - if (myMixins.length) { - generate(`Mixin: ${myMixins[0].name}`, myMixins, helper.longnameToUrl[longname]); - } + generate( + 'Home', + packages + .concat([ + { + kind: 'mainpage', + longname: opts.mainpagetitle ? opts.mainpagetitle : 'Main Page', + }, + ]) + .concat(files), + indexUrl + ); - if (myExternals.length) { - generate(`External: ${myExternals[0].name}`, myExternals, helper.longnameToUrl[longname]); - } + // set up the lists that we'll use to generate pages + classes = taffy(members.classes); + modules = taffy(members.modules); + namespaces = taffy(members.namespaces); + mixins = taffy(members.mixins); + externals = taffy(members.externals); + interfaces = taffy(members.interfaces); - if (myInterfaces.length) { - generate(`Interface: ${myInterfaces[0].name}`, myInterfaces, helper.longnameToUrl[longname]); - } - }); + Object.keys(helper.longnameToUrl).forEach((longname) => { + const myClasses = helper.find(classes, { longname: longname }); + const myExternals = helper.find(externals, { longname: longname }); + const myInterfaces = helper.find(interfaces, { longname: longname }); + const myMixins = helper.find(mixins, { longname: longname }); + const myModules = helper.find(modules, { longname: longname }); + const myNamespaces = helper.find(namespaces, { longname: longname }); + + if (myModules.length) { + generate(`Module: ${myModules[0].name}`, myModules, helper.longnameToUrl[longname]); + } + + if (myClasses.length) { + generate(`Class: ${myClasses[0].name}`, myClasses, helper.longnameToUrl[longname]); + } + + if (myNamespaces.length) { + generate(`Namespace: ${myNamespaces[0].name}`, myNamespaces, helper.longnameToUrl[longname]); + } + + if (myMixins.length) { + generate(`Mixin: ${myMixins[0].name}`, myMixins, helper.longnameToUrl[longname]); + } + + if (myExternals.length) { + generate(`External: ${myExternals[0].name}`, myExternals, helper.longnameToUrl[longname]); + } + + if (myInterfaces.length) { + generate(`Interface: ${myInterfaces[0].name}`, myInterfaces, helper.longnameToUrl[longname]); + } + }); }; diff --git a/packages/jsdoc/templates/default/static/scripts/linenumber.js b/packages/jsdoc/templates/default/static/scripts/linenumber.js index bdc5b4a8..f355ce24 100644 --- a/packages/jsdoc/templates/default/static/scripts/linenumber.js +++ b/packages/jsdoc/templates/default/static/scripts/linenumber.js @@ -1,25 +1,25 @@ /* global document */ (() => { - const source = document.getElementsByClassName('prettyprint source linenums'); - let i = 0; - let lineNumber = 0; - let lineId; - let lines; - let totalLines; - let anchorHash; + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; - if (source && source[0]) { - anchorHash = document.location.hash.substring(1); - lines = source[0].getElementsByTagName('li'); - totalLines = lines.length; + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; - for (; i < totalLines; i++) { - lineNumber++; - lineId = `line${lineNumber}`; - lines[i].id = lineId; - if (lineId === anchorHash) { - lines[i].className += ' selected'; - } - } + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } } + } })(); diff --git a/packages/jsdoc/templates/default/static/styles/jsdoc-default.css b/packages/jsdoc/templates/default/static/styles/jsdoc-default.css index 9ecc3faf..2cdb5e1b 100644 --- a/packages/jsdoc/templates/default/static/styles/jsdoc-default.css +++ b/packages/jsdoc/templates/default/static/styles/jsdoc-default.css @@ -1,341 +1,362 @@ @font-face { - font-family: 'Open Sans'; - font-weight: normal; - font-style: normal; - src: url('../fonts/OpenSans-Regular.woff2') format('woff2'), - url('../fonts/OpenSans-Regular.woff') format('woff'), - url('../fonts/OpenSans-Regular.ttf') format('truetype'), - url('../fonts/OpenSans-Regular.svg#OpenSansRegular') format('svg'); + font-family: 'Open Sans'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Regular.woff2') format('woff2'), + url('../fonts/OpenSans-Regular.woff') format('woff'), + url('../fonts/OpenSans-Regular.ttf') format('truetype'), + url('../fonts/OpenSans-Regular.svg#OpenSansRegular') format('svg'); } @font-face { - font-family: 'Open Sans'; - font-weight: bold; - font-style: normal; - src: url('../fonts/OpenSans-Bold.woff2') format('woff2'), - url('../fonts/OpenSans-Bold.woff') format('woff'), - url('../fonts/OpenSans-Bold.ttf') format('truetype'), - url('../fonts/OpenSans-Bold.svg#OpenSansBold') format('svg'); + font-family: 'Open Sans'; + font-weight: bold; + font-style: normal; + src: url('../fonts/OpenSans-Bold.woff2') format('woff2'), + url('../fonts/OpenSans-Bold.woff') format('woff'), + url('../fonts/OpenSans-Bold.ttf') format('truetype'), + url('../fonts/OpenSans-Bold.svg#OpenSansBold') format('svg'); } @font-face { - font-family: 'Open Sans'; - font-weight: normal; - font-style: italic; - src: url('../fonts/OpenSans-Italic.woff2') format('woff2'), - url('../fonts/OpenSans-Italic.woff') format('woff'), - url('../fonts/OpenSans-Italic.ttf') format('truetype'), - url('../fonts/OpenSans-Italic.svg#OpenSansItalic') format('svg'); + font-family: 'Open Sans'; + font-weight: normal; + font-style: italic; + src: url('../fonts/OpenSans-Italic.woff2') format('woff2'), + url('../fonts/OpenSans-Italic.woff') format('woff'), + url('../fonts/OpenSans-Italic.ttf') format('truetype'), + url('../fonts/OpenSans-Italic.svg#OpenSansItalic') format('svg'); } @font-face { - font-family: 'Open Sans'; - font-weight: bold; - font-style: italic; - src: url('../fonts/OpenSans-BoldItalic.woff2') format('woff2'), - url('../fonts/OpenSans-BoldItalic.woff') format('woff'), - url('../fonts/OpenSans-BoldItalic.ttf') format('truetype'), - url('../fonts/OpenSans-BoldItalic.svg#OpenSansBoldItalic') format('svg'); + font-family: 'Open Sans'; + font-weight: bold; + font-style: italic; + src: url('../fonts/OpenSans-BoldItalic.woff2') format('woff2'), + url('../fonts/OpenSans-BoldItalic.woff') format('woff'), + url('../fonts/OpenSans-BoldItalic.ttf') format('truetype'), + url('../fonts/OpenSans-BoldItalic.svg#OpenSansBoldItalic') format('svg'); } @font-face { - font-family: 'Open Sans Light'; - font-weight: normal; - font-style: normal; - src: url('../fonts/OpenSans-Light.woff2') format('woff2'), - url('../fonts/OpenSans-Light.woff') format('woff'), - url('../fonts/OpenSans-Light.ttf') format('truetype'), - url('../fonts/OpenSans-Light.svg#OpenSansLight') format('svg'); + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: normal; + src: url('../fonts/OpenSans-Light.woff2') format('woff2'), + url('../fonts/OpenSans-Light.woff') format('woff'), + url('../fonts/OpenSans-Light.ttf') format('truetype'), + url('../fonts/OpenSans-Light.svg#OpenSansLight') format('svg'); } @font-face { - font-family: 'Open Sans Light'; - font-weight: normal; - font-style: italic; - src: url('../fonts/OpenSans-LightItalic.woff2') format('woff2'), - url('../fonts/OpenSans-LightItalic.woff') format('woff'), - url('../fonts/OpenSans-LightItalic.ttf') format('truetype'), - url('../fonts/OpenSans-LightItalic.svg#OpenSansLightItalic') format('svg'); + font-family: 'Open Sans Light'; + font-weight: normal; + font-style: italic; + src: url('../fonts/OpenSans-LightItalic.woff2') format('woff2'), + url('../fonts/OpenSans-LightItalic.woff') format('woff'), + url('../fonts/OpenSans-LightItalic.ttf') format('truetype'), + url('../fonts/OpenSans-LightItalic.svg#OpenSansLightItalic') format('svg'); } -html -{ - overflow: auto; - background-color: #fff; - font-size: 14px; +html { + overflow: auto; + background-color: #fff; + font-size: 14px; } -body -{ - font-family: 'Open Sans', sans-serif; - line-height: 1.5; - color: #4d4e53; - background-color: white; +body { + font-family: 'Open Sans', sans-serif; + line-height: 1.5; + color: #4d4e53; + background-color: white; } -a, a:visited, a:active { - color: #0095dd; - text-decoration: none; +a, +a:visited, +a:active { + color: #0095dd; + text-decoration: none; } a:hover { - text-decoration: underline; + text-decoration: underline; } -header -{ - display: block; - padding: 0px 4px; +header { + display: block; + padding: 0px 4px; } -tt, code, kbd, samp { - font-family: Consolas, Monaco, 'Andale Mono', monospace; +tt, +code, +kbd, +samp { + font-family: Consolas, Monaco, 'Andale Mono', monospace; } .class-description { - font-size: 130%; - line-height: 140%; - margin-bottom: 1em; - margin-top: 1em; + font-size: 130%; + line-height: 140%; + margin-bottom: 1em; + margin-top: 1em; } .class-description:empty { - margin: 0; + margin: 0; } #main { - float: left; - width: 70%; + float: left; + width: 70%; } article dl { - margin-bottom: 40px; + margin-bottom: 40px; } article img { max-width: 100%; } -section -{ - display: block; - background-color: #fff; - padding: 12px 24px; - border-bottom: 1px solid #ccc; - margin-right: 30px; +section { + display: block; + background-color: #fff; + padding: 12px 24px; + border-bottom: 1px solid #ccc; + margin-right: 30px; } .variation { - display: none; + display: none; } .signature-attributes { - font-size: 60%; - color: #aaa; - font-style: italic; - font-weight: lighter; + font-size: 60%; + color: #aaa; + font-style: italic; + font-weight: lighter; } -nav -{ - display: block; - float: right; - margin-top: 28px; - width: 30%; - box-sizing: border-box; - border-left: 1px solid #ccc; - padding-left: 16px; +nav { + display: block; + float: right; + margin-top: 28px; + width: 30%; + box-sizing: border-box; + border-left: 1px solid #ccc; + padding-left: 16px; } nav ul { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; - font-size: 100%; - line-height: 17px; - padding: 0; - margin: 0; - list-style-type: none; + font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; + font-size: 100%; + line-height: 17px; + padding: 0; + margin: 0; + list-style-type: none; } -nav ul a, nav ul a:visited, nav ul a:active { - font-family: Consolas, Monaco, 'Andale Mono', monospace; - line-height: 18px; - color: #4D4E53; +nav ul a, +nav ul a:visited, +nav ul a:active { + font-family: Consolas, Monaco, 'Andale Mono', monospace; + line-height: 18px; + color: #4d4e53; } nav h3 { - margin-top: 12px; + margin-top: 12px; } nav li { - margin-top: 6px; + margin-top: 6px; } footer { - display: block; - padding: 6px; - margin-top: 12px; - font-style: italic; - font-size: 90%; + display: block; + padding: 6px; + margin-top: 12px; + font-style: italic; + font-size: 90%; } -h1, h2, h3, h4 { - font-weight: 200; - margin: 0; +h1, +h2, +h3, +h4 { + font-weight: 200; + margin: 0; } -h1 -{ - font-family: 'Open Sans Light', sans-serif; - font-size: 48px; - letter-spacing: -2px; - margin: 12px 24px 20px; +h1 { + font-family: 'Open Sans Light', sans-serif; + font-size: 48px; + letter-spacing: -2px; + margin: 12px 24px 20px; } -h2, h3.subsection-title -{ - font-size: 30px; - font-weight: 700; - letter-spacing: -1px; - margin-bottom: 12px; +h2, +h3.subsection-title { + font-size: 30px; + font-weight: 700; + letter-spacing: -1px; + margin-bottom: 12px; } -h3 -{ - font-size: 24px; - letter-spacing: -0.5px; - margin-bottom: 12px; +h3 { + font-size: 24px; + letter-spacing: -0.5px; + margin-bottom: 12px; } -h4 -{ - font-size: 18px; - letter-spacing: -0.33px; - margin-bottom: 12px; - color: #4d4e53; +h4 { + font-size: 18px; + letter-spacing: -0.33px; + margin-bottom: 12px; + color: #4d4e53; } -h5, .container-overview .subsection-title -{ - font-size: 120%; - font-weight: bold; - letter-spacing: -0.01em; - margin: 8px 0 3px 0; +h5, +.container-overview .subsection-title { + font-size: 120%; + font-weight: bold; + letter-spacing: -0.01em; + margin: 8px 0 3px 0; } -h6 -{ - font-size: 100%; - letter-spacing: -0.01em; - margin: 6px 0 3px 0; - font-style: italic; +h6 { + font-size: 100%; + letter-spacing: -0.01em; + margin: 6px 0 3px 0; + font-style: italic; } -table -{ - border-spacing: 0; - border: 0; - border-collapse: collapse; +table { + border-spacing: 0; + border: 0; + border-collapse: collapse; } -td, th -{ - border: 1px solid #ddd; - margin: 0px; - text-align: left; - vertical-align: top; - padding: 4px 6px; - display: table-cell; +td, +th { + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; } -thead tr -{ - background-color: #ddd; - font-weight: bold; +thead tr { + background-color: #ddd; + font-weight: bold; } -th { border-right: 1px solid #aaa; } -tr > th:last-child { border-right: 1px solid #ddd; } - -.ancestors, .attribs { color: #999; } -.ancestors a, .attribs a -{ - color: #999 !important; - text-decoration: none; +th { + border-right: 1px solid #aaa; +} +tr > th:last-child { + border-right: 1px solid #ddd; } -.clear -{ - clear: both; +.ancestors, +.attribs { + color: #999; +} +.ancestors a, +.attribs a { + color: #999 !important; + text-decoration: none; } -.important -{ - font-weight: bold; - color: #950B02; +.clear { + clear: both; +} + +.important { + font-weight: bold; + color: #950b02; } .yes-def { - text-indent: -1000px; + text-indent: -1000px; } .type-signature { - color: #aaa; + color: #aaa; } -.name, .signature { - font-family: Consolas, Monaco, 'Andale Mono', monospace; +.name, +.signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; } -.details { margin-top: 14px; border-left: 2px solid #DDD; } -.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } -.details dd { margin-left: 70px; } -.details ul { margin: 0; } -.details ul { list-style-type: none; } -.details li { margin-left: 30px; padding-top: 6px; } -.details pre.prettyprint { margin: 0 } -.details .object-value { padding-top: 0; } +.details { + margin-top: 14px; + border-left: 2px solid #ddd; +} +.details dt { + width: 120px; + float: left; + padding-left: 10px; + padding-top: 6px; +} +.details dd { + margin-left: 70px; +} +.details ul { + margin: 0; +} +.details ul { + list-style-type: none; +} +.details li { + margin-left: 30px; + padding-top: 6px; +} +.details pre.prettyprint { + margin: 0; +} +.details .object-value { + padding-top: 0; +} .description { - margin-bottom: 1em; - margin-top: 1em; + margin-bottom: 1em; + margin-top: 1em; } -.code-caption -{ - font-style: italic; - font-size: 107%; - margin: 0; +.code-caption { + font-style: italic; + font-size: 107%; + margin: 0; } -.source -{ - border: 1px solid #ddd; - width: 80%; - overflow: auto; +.source { + border: 1px solid #ddd; + width: 80%; + overflow: auto; } .prettyprint.source { - width: inherit; + width: inherit; } -.source code -{ - font-size: 100%; - line-height: 18px; - display: block; - padding: 4px 12px; - margin: 0; - background-color: #fff; - color: #4D4E53; +.source code { + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4d4e53; } -.prettyprint code span.line -{ +.prettyprint code span.line { display: inline-block; } -.prettyprint.linenums -{ +.prettyprint.linenums { padding-left: 70px; -webkit-user-select: none; -moz-user-select: none; @@ -343,50 +364,46 @@ tr > th:last-child { border-right: 1px solid #ddd; } user-select: none; } -.prettyprint.linenums ol -{ +.prettyprint.linenums ol { padding-left: 0; } -.prettyprint.linenums li -{ +.prettyprint.linenums li { border-left: 3px #ddd solid; } .prettyprint.linenums li.selected, -.prettyprint.linenums li.selected * -{ +.prettyprint.linenums li.selected * { background-color: lightyellow; } -.prettyprint.linenums li * -{ +.prettyprint.linenums li * { -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; } -.params .name, .props .name, .name code { - color: #4D4E53; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 100%; +.params .name, +.props .name, +.name code { + color: #4d4e53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; } .params td.description > p:first-child, -.props td.description > p:first-child -{ - margin-top: 0; - padding-top: 0; +.props td.description > p:first-child { + margin-top: 0; + padding-top: 0; } .params td.description > p:last-child, -.props td.description > p:last-child -{ - margin-bottom: 0; - padding-bottom: 0; +.props td.description > p:last-child { + margin-bottom: 0; + padding-bottom: 0; } .disabled { - color: #454545; + color: #454545; } diff --git a/packages/jsdoc/templates/silent/README.md b/packages/jsdoc/templates/silent/README.md index d33e0fdf..ef5d9b40 100644 --- a/packages/jsdoc/templates/silent/README.md +++ b/packages/jsdoc/templates/silent/README.md @@ -1,11 +1,9 @@ -OVERVIEW -======== +# OVERVIEW -The `silent` template outputs nothing at all. Why would that be useful? Primarily for running JSDoc as a linter to check for syntax errors and unrecognized tags in documentation comments, although it may also be useful for testing or benchmarking purposes. +The `silent` template outputs nothing at all. Why would that be useful? Primarily for running JSDoc as a linter to check for syntax errors and unrecognized tags in documentation comments, although it may also be useful for testing or benchmarking purposes. -USAGE -===== +# USAGE ./jsdoc myscript.js -t templates/silent -a all --pedantic -This command exits with a non-zero exit code if any errors are encountered. It writes nothing to disk and the only output it produces is any error messages written to `stderr`. This command can also be used to warn about tags which are unknown to JSDoc by setting `"allowUnknownTags": false` in a configuration file. +This command exits with a non-zero exit code if any errors are encountered. It writes nothing to disk and the only output it produces is any error messages written to `stderr`. This command can also be used to warn about tags which are unknown to JSDoc by setting `"allowUnknownTags": false` in a configuration file. diff --git a/packages/jsdoc/test/.eslintrc.js b/packages/jsdoc/test/.eslintrc.js index cc9e75af..df8cf4eb 100644 --- a/packages/jsdoc/test/.eslintrc.js +++ b/packages/jsdoc/test/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = { - globals: { - jsdoc: 'readonly' - } + globals: { + jsdoc: 'readonly', + }, }; diff --git a/packages/jsdoc/test/README.md b/packages/jsdoc/test/README.md index 9425d78b..62c2d99c 100644 --- a/packages/jsdoc/test/README.md +++ b/packages/jsdoc/test/README.md @@ -14,7 +14,7 @@ Clone the GitHub repository; change to its directory; and run the following comm You can write tests for all of the following: -+ **JSDoc itself**. See the `test` directory. Test specs are in `test/specs`, and fixtures used by -the tests are in `test/fixtures`. -+ **Plugins**. See the `plugins/test` directory. -+ **Packages**. See the `packages/**/test` directories. +- **JSDoc itself**. See the `test` directory. Test specs are in `test/specs`, and fixtures used by + the tests are in `test/fixtures`. +- **Plugins**. See the `plugins/test` directory. +- **Packages**. See the `packages/**/test` directories. diff --git a/packages/jsdoc/test/fixtures/es6.js b/packages/jsdoc/test/fixtures/es6.js index 355d2c47..71c7f4b9 100644 --- a/packages/jsdoc/test/fixtures/es6.js +++ b/packages/jsdoc/test/fixtures/es6.js @@ -30,9 +30,6 @@ export {Socket}; // ImportDeclaration, ImportSpecifier import {Packet} from 'lib/data'; -// ModuleDeclaration -module util from 'lib/util'; - // SpreadElement function logItems(...items) { items.forEach(function(item) { diff --git a/packages/jsdoc/test/helpers/jsdoc.js b/packages/jsdoc/test/helpers/jsdoc.js index 1b68dd57..179bec42 100644 --- a/packages/jsdoc/test/helpers/jsdoc.js +++ b/packages/jsdoc/test/helpers/jsdoc.js @@ -12,73 +12,73 @@ const bus = new EventBus('jsdoc'); const originalDictionaries = env.conf.tags.dictionaries.slice(); const parseResults = []; -const helpers = global.jsdoc = { - addParseResults: (filename, doclets) => { - parseResults.push({ - filename: filename, - doclets: doclets - }); - }, - createParser, - didLog: (fn, level) => { - const events = []; +const helpers = (global.jsdoc = { + addParseResults: (filename, doclets) => { + parseResults.push({ + filename: filename, + doclets: doclets, + }); + }, + createParser, + didLog: (fn, level) => { + const events = []; - function listener(e) { - events.push(e); - } - - bus.on(`logger:${level}`, listener); - fn(); - bus.off(`logger:${level}`, listener); - - return events.length !== 0; - }, - getDocSetFromFile: (filename, parser, shouldValidate, augment) => { - let doclets; - - const sourceCode = fs.readFileSync(path.join(env.dirname, filename), 'utf8'); - const testParser = parser || helpers.createParser(); - - handlers.attachTo(testParser); - - /* eslint-disable no-script-url */ - doclets = testParser.parse(`javascript:${sourceCode}`); - /* eslint-enable no-script-url */ - - if (augment !== false) { - augmentAll(doclets); - } - - // tests assume that borrows have not yet been resolved - - if (shouldValidate !== false) { - helpers.addParseResults(filename, doclets); - } - - return { - doclets: doclets, - getByLongname(longname) { - return doclets.filter(doclet => (doclet.longname || doclet.name) === longname); - } - }; - }, - getParseResults: () => parseResults, - replaceTagDictionary: dictionaryNames => { - let dict; - - if (!Array.isArray(dictionaryNames)) { - dictionaryNames = [dictionaryNames]; - } - - env.conf.tags.dictionaries = dictionaryNames; - - dict = Dictionary.fromConfig(env); - dict.Dictionary = Dictionary; - _replaceDictionary(dict); - - env.conf.tags.dictionaries = originalDictionaries; - }, - restoreTagDictionary: () => { - _replaceDictionary(Dictionary.fromConfig(env)); + function listener(e) { + events.push(e); } -}; + + bus.on(`logger:${level}`, listener); + fn(); + bus.off(`logger:${level}`, listener); + + return events.length !== 0; + }, + getDocSetFromFile: (filename, parser, shouldValidate, augment) => { + let doclets; + + const sourceCode = fs.readFileSync(path.join(env.dirname, filename), 'utf8'); + const testParser = parser || helpers.createParser(); + + handlers.attachTo(testParser); + + /* eslint-disable no-script-url */ + doclets = testParser.parse(`javascript:${sourceCode}`); + /* eslint-enable no-script-url */ + + if (augment !== false) { + augmentAll(doclets); + } + + // tests assume that borrows have not yet been resolved + + if (shouldValidate !== false) { + helpers.addParseResults(filename, doclets); + } + + return { + doclets: doclets, + getByLongname(longname) { + return doclets.filter((doclet) => (doclet.longname || doclet.name) === longname); + }, + }; + }, + getParseResults: () => parseResults, + replaceTagDictionary: (dictionaryNames) => { + let dict; + + if (!Array.isArray(dictionaryNames)) { + dictionaryNames = [dictionaryNames]; + } + + env.conf.tags.dictionaries = dictionaryNames; + + dict = Dictionary.fromConfig(env); + dict.Dictionary = Dictionary; + _replaceDictionary(dict); + + env.conf.tags.dictionaries = originalDictionaries; + }, + restoreTagDictionary: () => { + _replaceDictionary(Dictionary.fromConfig(env)); + }, +}); diff --git a/packages/jsdoc/test/index.js b/packages/jsdoc/test/index.js index 6aa09156..77f27f04 100644 --- a/packages/jsdoc/test/index.js +++ b/packages/jsdoc/test/index.js @@ -4,47 +4,43 @@ const Jasmine = require('jasmine'); const SCHEMA_SPEC = 'packages/jsdoc/test/specs/jsdoc/schema.js'; const SPEC_FILES = [ - `!${SCHEMA_SPEC}`, - '!node_modules', - 'packages/**/test/specs/**/*.js', - SCHEMA_SPEC + `!${SCHEMA_SPEC}`, + '!node_modules', + 'packages/**/test/specs/**/*.js', + SCHEMA_SPEC, ]; module.exports = () => { - const jasmine = new Jasmine(); - const matcher = env.opts.matcher; - /* eslint-disable no-empty-function */ - const promise = new Promise(() => {}); - /* eslint-enable no-empty-function */ - const reporter = new ConsoleReporter({ - beep: false, - verbosity: { - disabled: false, - pending: false, - specs: false, - summary: true - } - }); + const jasmine = new Jasmine(); + const matcher = env.opts.matcher; + /* eslint-disable no-empty-function */ + const promise = new Promise(() => {}); + /* eslint-enable no-empty-function */ + const reporter = new ConsoleReporter({ + beep: false, + verbosity: { + disabled: false, + pending: false, + specs: false, + summary: true, + }, + }); - // Treat an unhandled promise rejection as an error. - process.on('unhandledRejection', e => { - throw e; - }); + // Treat an unhandled promise rejection as an error. + process.on('unhandledRejection', (e) => { + throw e; + }); - jasmine.loadConfig({ - helpers: [ - 'node_modules/@jsdoc/test-matchers', - 'packages/jsdoc/test/helpers/**/*.js' - ], - random: false, - stopSpecOnExpectationFailure: false - }); - jasmine.env.clearReporters(); - jasmine.addReporter(reporter); + jasmine.loadConfig({ + helpers: ['node_modules/@jsdoc/test-matchers', 'packages/jsdoc/test/helpers/**/*.js'], + random: false, + stopSpecOnExpectationFailure: false, + }); + jasmine.env.clearReporters(); + jasmine.addReporter(reporter); - jasmine.onComplete(() => promise.resolve()); - jasmine.execute(SPEC_FILES, matcher); + jasmine.onComplete(() => promise.resolve()); + jasmine.execute(SPEC_FILES, matcher); - return promise; + return promise; }; - diff --git a/packages/jsdoc/test/specs/documentation/alias.js b/packages/jsdoc/test/specs/documentation/alias.js index cd28119e..57b93ae5 100644 --- a/packages/jsdoc/test/specs/documentation/alias.js +++ b/packages/jsdoc/test/specs/documentation/alias.js @@ -1,119 +1,121 @@ describe('aliases', () => { - describe('standard', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias.js'); - const found = docSet.getByLongname('myObject').filter(({undocumented}) => !(undocumented)); - const foundMember = docSet.getByLongname('myObject.myProperty'); + describe('standard', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias.js'); + const found = docSet.getByLongname('myObject').filter(({ undocumented }) => !undocumented); + const foundMember = docSet.getByLongname('myObject.myProperty'); - it('When a symbol is given an alias it is documented as if the name is the alias value.', () => { - expect(found[0].longname).toBe('myObject'); - }); - - it('When a symbol is a member of an alias it is documented as if the memberof is the alias value.', () => { - expect(foundMember[0].longname).toBe('myObject.myProperty'); - expect(foundMember[0].memberof).toBe('myObject'); - }); + it('When a symbol is given an alias it is documented as if the name is the alias value.', () => { + expect(found[0].longname).toBe('myObject'); }); - it('When a symbol is a member of an alias of a nested name it is documented as if the memberof is the nested alias value.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias2.js'); - const foundMember = docSet.getByLongname('ns.Myclass#myProperty'); + it('When a symbol is a member of an alias it is documented as if the memberof is the alias value.', () => { + expect(foundMember[0].longname).toBe('myObject.myProperty'); + expect(foundMember[0].memberof).toBe('myObject'); + }); + }); - expect(foundMember[0].longname).toBe('ns.Myclass#myProperty'); - expect(foundMember[0].name).toBe('myProperty'); - expect(foundMember[0].memberof).toBe('ns.Myclass'); - expect(foundMember[0].scope).toBe('instance'); + it('When a symbol is a member of an alias of a nested name it is documented as if the memberof is the nested alias value.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias2.js'); + const foundMember = docSet.getByLongname('ns.Myclass#myProperty'); + + expect(foundMember[0].longname).toBe('ns.Myclass#myProperty'); + expect(foundMember[0].name).toBe('myProperty'); + expect(foundMember[0].memberof).toBe('ns.Myclass'); + expect(foundMember[0].scope).toBe('instance'); + }); + + it('When a symbol is a member of an aliased class, a this-variable is documented as if it were a member that class.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias3.js'); + const tcmValue = docSet.getByLongname('trackr.CookieManager#value')[0]; + + expect(tcmValue.memberof).toBe('trackr.CookieManager'); + }); + + it('When a symbol is a function expression that has an alias, the symbol should get the correct longname', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias4.js'); + const jacketClass = docSet + .getByLongname('module:jacket') + .filter(({ kind }) => kind === 'class'); + + expect(jacketClass.length).toBe(1); + expect(jacketClass[0].longname).toBe('module:jacket'); + }); + + describe('formats', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias5.js'); + const toast = docSet.getByLongname('Toaster#toast')[0]; + const getInstance = docSet.getByLongname('Toaster.getInstance')[0]; + const clean = docSet.getByLongname('Toaster#clean')[0]; + + it('should work when the alias value specifies an instance member', () => { + expect(toast).toBeObject(); + expect(toast.name).toBe('toast'); + expect(toast.memberof).toBe('Toaster'); + expect(toast.scope).toBe('instance'); }); - it('When a symbol is a member of an aliased class, a this-variable is documented as if it were a member that class.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias3.js'); - const tcmValue = docSet.getByLongname('trackr.CookieManager#value')[0]; - - expect(tcmValue.memberof).toBe('trackr.CookieManager'); + it('should work when the alias value specifies a static member', () => { + expect(getInstance).toBeObject(); + expect(getInstance.name).toBe('getInstance'); + expect(getInstance.memberof).toBe('Toaster'); + expect(getInstance.scope).toBe('static'); }); - it('When a symbol is a function expression that has an alias, the symbol should get the correct longname', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias4.js'); - const jacketClass = docSet.getByLongname('module:jacket').filter(({kind}) => kind === 'class'); + it('should work when the alias value only specifies the short name', () => { + expect(clean).toBeObject(); + expect(clean.name).toBe('clean'); + expect(clean.memberof).toBe('Toaster'); + expect(clean.scope).toBe('instance'); + }); + }); - expect(jacketClass.length).toBe(1); - expect(jacketClass[0].longname).toBe('module:jacket'); + it('When a symbol is a constructor of a class with an alias, the constructor should get the correct longname', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias6.js'); + const constructor = docSet.getByLongname('module:example')[2]; + + expect(constructor.undocumented).toBe(true); + expect(constructor.name).toBe('module:example'); + expect(constructor.alias).toBe('module:example'); + }); + + it('When a symbol is documented as a static member of , its scope is "global" and not "static".', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasglobal.js'); + const log = docSet.getByLongname('log')[0]; + + expect(log.scope).toBe('global'); + }); + + it('When a symbol is documented as an instance member of , its scope is "instance" and not "static".', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasglobal2.js'); + const run = docSet.getByLongname('Test#run')[0]; + + expect(run.scope).toBe('instance'); + expect(run.memberof).toBe('Test'); + }); + + describe('resolving', () => { + it('When a local reference has alias, put all members into aliased definition. Local modifications should be visible to outside.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasresolve.js'); + const method = docSet.getByLongname('A.F.method'); + + expect(method).toBeArrayOfSize(1); }); - describe('formats', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias5.js'); - const toast = docSet.getByLongname('Toaster#toast')[0]; - const getInstance = docSet.getByLongname('Toaster.getInstance')[0]; - const clean = docSet.getByLongname('Toaster#clean')[0]; + it('When a reference in an outer scope has alias, put all members into aliased definition. Local modifications are visible to outside.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasresolve2.js'); + const method = docSet.getByLongname('A.F.method'); - it('should work when the alias value specifies an instance member', () => { - expect(toast).toBeObject(); - expect(toast.name).toBe('toast'); - expect(toast.memberof).toBe('Toaster'); - expect(toast.scope).toBe('instance'); - }); - - it('should work when the alias value specifies a static member', () => { - expect(getInstance).toBeObject(); - expect(getInstance.name).toBe('getInstance'); - expect(getInstance.memberof).toBe('Toaster'); - expect(getInstance.scope).toBe('static'); - }); - - it('should work when the alias value only specifies the short name', () => { - expect(clean).toBeObject(); - expect(clean.name).toBe('clean'); - expect(clean.memberof).toBe('Toaster'); - expect(clean.scope).toBe('instance'); - }); + expect(method).toBeArrayOfSize(1); }); + }); - it('When a symbol is a constructor of a class with an alias, the constructor should get the correct longname', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias6.js'); - const constructor = docSet.getByLongname('module:example')[2]; + describe('class with constructor exported from module', () => { + it('When an exported class with a constructor has an alias, the exported class has the correct scope.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasexports.js'); + const klass = docSet.getByLongname('module:foo.Bar').filter((d) => !d.undocumented); - expect(constructor.undocumented).toBe(true); - expect(constructor.name).toBe('module:example'); - expect(constructor.alias).toBe('module:example'); - }); - - it('When a symbol is documented as a static member of , its scope is "global" and not "static".', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasglobal.js'); - const log = docSet.getByLongname('log')[0]; - - expect(log.scope).toBe('global'); - }); - - it('When a symbol is documented as an instance member of , its scope is "instance" and not "static".', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasglobal2.js'); - const run = docSet.getByLongname('Test#run')[0]; - - expect(run.scope).toBe('instance'); - expect(run.memberof).toBe('Test'); - }); - - describe('resolving', () => { - it('When a local reference has alias, put all members into aliased definition. Local modifications should be visible to outside.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasresolve.js'); - const method = docSet.getByLongname('A.F.method'); - - expect(method).toBeArrayOfSize(1); - }); - - it('When a reference in an outer scope has alias, put all members into aliased definition. Local modifications are visible to outside.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasresolve2.js'); - const method = docSet.getByLongname('A.F.method'); - - expect(method).toBeArrayOfSize(1); - }); - }); - - describe('class with constructor exported from module', () => { - it('When an exported class with a constructor has an alias, the exported class has the correct scope.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/aliasexports.js'); - const klass = docSet.getByLongname('module:foo.Bar').filter(d => !d.undocumented); - - expect(klass).toBeArrayOfSize(1); - expect(klass[0].scope).toBe('static'); - }); + expect(klass).toBeArrayOfSize(1); + expect(klass[0].scope).toBe('static'); }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/also.js b/packages/jsdoc/test/specs/documentation/also.js index e8f74493..eedb516a 100644 --- a/packages/jsdoc/test/specs/documentation/also.js +++ b/packages/jsdoc/test/specs/documentation/also.js @@ -1,59 +1,74 @@ const env = require('jsdoc/env'); describe('multiple doclets per symbol', () => { - function undocumented($) { - return !($.undocumented); + function undocumented($) { + return !$.undocumented; + } + + const docSet = jsdoc.getDocSetFromFile('test/fixtures/also.js'); + const name = docSet.getByLongname('Asset#name').filter(undocumented); + const shape = docSet.getByLongname('Asset#shape').filter(undocumented); + + it('When a symbol has multiple adjacent JSDoc comments, both apply to the symbol.', () => { + expect(name).toBeArrayOfSize(2); + expect(shape).toBeArrayOfSize(3); + }); + + it( + 'When a symbol has multiple adjacent JSDoc comments that are not identical, the doclets ' + + 'have different comments.', + () => { + expect(name[0].comment).not.toBe(name[1].comment); + expect(shape[0].comment).not.toBe(shape[1].comment); + expect(shape[1].comment).not.toBe(shape[2].comment); } + ); - const docSet = jsdoc.getDocSetFromFile('test/fixtures/also.js'); - const name = docSet.getByLongname('Asset#name').filter(undocumented); - const shape = docSet.getByLongname('Asset#shape').filter(undocumented); + it( + 'When a symbol has multiple adjacent JSDoc comments with different descriptions, ' + + 'the doclets have different descriptions.', + () => { + expect(name[0].description).not.toBe(name[1].description); + expect(shape[0].description).not.toBe(shape[1].description); + expect(shape[1].description).not.toBe(shape[2].description); + } + ); - it('When a symbol has multiple adjacent JSDoc comments, both apply to the symbol.', () => { - expect(name).toBeArrayOfSize(2); - expect(shape).toBeArrayOfSize(3); - }); + it( + 'When a symbol has multiple adjacent JSDoc comments with different numbers of ' + + '@param tags, the doclets have different parameter lists.', + () => { + expect(name[0].params).not.toEqual(name[1].params); + expect(shape[0].params).not.toEqual(shape[1].params); + expect(shape[1].params).not.toEqual(shape[2].params); + } + ); - it('When a symbol has multiple adjacent JSDoc comments that are not identical, the doclets ' + - 'have different comments.', () => { - expect(name[0].comment).not.toBe(name[1].comment); - expect(shape[0].comment).not.toBe(shape[1].comment); - expect(shape[1].comment).not.toBe(shape[2].comment); - }); + it( + 'When a symbol has multiple adjacent JSDoc comments with different numbers of ' + + '@returns tags, the doclets have different lists of return values.', + () => { + expect(name[0].returns).not.toEqual(name[1].returns); + // Neither shape[0] nor shape[1] returns a value. + expect(shape[0].returns).toBeUndefined(); + expect(shape[1].returns).toBeUndefined(); + expect(shape[2].returns).toBeArray(); + } + ); - it('When a symbol has multiple adjacent JSDoc comments with different descriptions, ' + - 'the doclets have different descriptions.', () => { - expect(name[0].description).not.toBe(name[1].description); - expect(shape[0].description).not.toBe(shape[1].description); - expect(shape[1].description).not.toBe(shape[2].description); - }); + it( + 'When a file contains a JSDoc comment with an @also tag, and the "tags.allowUnknownTags" ' + + 'option is set to false, the file can be parsed without errors.', + () => { + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); - it('When a symbol has multiple adjacent JSDoc comments with different numbers of ' + - '@param tags, the doclets have different parameter lists.', () => { - expect(name[0].params).not.toEqual(name[1].params); - expect(shape[0].params).not.toEqual(shape[1].params); - expect(shape[1].params).not.toEqual(shape[2].params); - }); + function getDocSet() { + env.conf.tags.allowUnknownTags = false; + jsdoc.getDocSetFromFile('test/fixtures/also2.js'); + env.conf.tags.allowUnknownTags = allowUnknownTags; + } - it('When a symbol has multiple adjacent JSDoc comments with different numbers of ' + - '@returns tags, the doclets have different lists of return values.', () => { - expect(name[0].returns).not.toEqual(name[1].returns); - // Neither shape[0] nor shape[1] returns a value. - expect(shape[0].returns).toBeUndefined(); - expect(shape[1].returns).toBeUndefined(); - expect(shape[2].returns).toBeArray(); - }); - - it('When a file contains a JSDoc comment with an @also tag, and the "tags.allowUnknownTags" ' + - 'option is set to false, the file can be parsed without errors.', () => { - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); - - function getDocSet() { - env.conf.tags.allowUnknownTags = false; - jsdoc.getDocSetFromFile('test/fixtures/also2.js'); - env.conf.tags.allowUnknownTags = allowUnknownTags; - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/anonymousclass.js b/packages/jsdoc/test/specs/documentation/anonymousclass.js index 931aa7c0..86d82c61 100644 --- a/packages/jsdoc/test/specs/documentation/anonymousclass.js +++ b/packages/jsdoc/test/specs/documentation/anonymousclass.js @@ -1,23 +1,23 @@ describe('anonymous class', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/anonymousclass.js'); - const klass = docSet.getByLongname('module:test').filter(({undocumented}) => !undocumented)[1]; - const foo = docSet.getByLongname('module:test#foo')[0]; - const klassTest = docSet.getByLongname('module:test#test')[0]; - const klassStaticTest = docSet.getByLongname('module:test.staticTest')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/anonymousclass.js'); + const klass = docSet.getByLongname('module:test').filter(({ undocumented }) => !undocumented)[1]; + const foo = docSet.getByLongname('module:test#foo')[0]; + const klassTest = docSet.getByLongname('module:test#test')[0]; + const klassStaticTest = docSet.getByLongname('module:test.staticTest')[0]; - it('should merge the constructor docs with the class docs', () => { - expect(klass.description).toBe('Test constructor'); - }); + it('should merge the constructor docs with the class docs', () => { + expect(klass.description).toBe('Test constructor'); + }); - it('should use the correct longname for instance properties', () => { - expect(foo.description).toBe('Test member'); - }); + it('should use the correct longname for instance properties', () => { + expect(foo.description).toBe('Test member'); + }); - it('should use the correct longname for instance methods', () => { - expect(klassTest.description).toBe('Test method'); - }); + it('should use the correct longname for instance methods', () => { + expect(klassTest.description).toBe('Test method'); + }); - it('should use the correct longname for static methods', () => { - expect(klassStaticTest.description).toBe('Test static method'); - }); + it('should use the correct longname for static methods', () => { + expect(klassStaticTest.description).toBe('Test static method'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/anonymousclassparam.js b/packages/jsdoc/test/specs/documentation/anonymousclassparam.js index aef79f70..6ecac3bf 100644 --- a/packages/jsdoc/test/specs/documentation/anonymousclassparam.js +++ b/packages/jsdoc/test/specs/documentation/anonymousclassparam.js @@ -1,9 +1,9 @@ describe('anonymous class passed as a parameter', () => { - it('should not crash JSDoc', () => { - function loadFile() { - jsdoc.getDocSetFromFile('test/fixtures/anonymousclassparam.js'); - } + it('should not crash JSDoc', () => { + function loadFile() { + jsdoc.getDocSetFromFile('test/fixtures/anonymousclassparam.js'); + } - expect(loadFile).not.toThrow(); - }); + expect(loadFile).not.toThrow(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/arrowfunction.js b/packages/jsdoc/test/specs/documentation/arrowfunction.js index 9e5c34b3..24c6014e 100644 --- a/packages/jsdoc/test/specs/documentation/arrowfunction.js +++ b/packages/jsdoc/test/specs/documentation/arrowfunction.js @@ -1,29 +1,28 @@ describe('arrow functions', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/arrowfunction.js'); - const increment = docSet.getByLongname('increment')[0]; - const print = docSet.getByLongname('print')[0]; - const name = docSet.getByLongname('#name'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/arrowfunction.js'); + const increment = docSet.getByLongname('increment')[0]; + const print = docSet.getByLongname('print')[0]; + const name = docSet.getByLongname('#name'); - it('should use the correct name and longname', () => { - expect(increment).toBeObject(); - expect(increment.name).toBe('increment'); - }); + it('should use the correct name and longname', () => { + expect(increment).toBeObject(); + expect(increment.name).toBe('increment'); + }); - it('should allow function parameters to be documented', () => { - expect(increment.params).toBeArrayOfSize(1); - expect(increment.params[0].name).toBe('n'); - }); + it('should allow function parameters to be documented', () => { + expect(increment.params).toBeArrayOfSize(1); + expect(increment.params[0].name).toBe('n'); + }); - it('should support inline comments on parameters', () => { - expect(print.params).toBeArrayOfSize(1); - expect(print.params[0].type.names[0]).toBe('*'); - }); + it('should support inline comments on parameters', () => { + expect(print.params).toBeArrayOfSize(1); + expect(print.params[0].type.names[0]).toBe('*'); + }); - // TODO: we currently use the wrong longname in this case; see - // `module:@jsdoc/parse.astNode.nodeToValue` and the comment on `case Syntax.MethodDefinition` - // for details - xit('should use the correct longname for members of a class returned by an arrow function', - () => { - expect(name).toBeArrayOfSize(2); - }); + // TODO: we currently use the wrong longname in this case; see + // `module:@jsdoc/parse.astNode.nodeToValue` and the comment on `case Syntax.MethodDefinition` + // for details + xit('should use the correct longname for members of a class returned by an arrow function', () => { + expect(name).toBeArrayOfSize(2); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/asyncfunction.js b/packages/jsdoc/test/specs/documentation/asyncfunction.js index d0a420c7..24a515dd 100644 --- a/packages/jsdoc/test/specs/documentation/asyncfunction.js +++ b/packages/jsdoc/test/specs/documentation/asyncfunction.js @@ -1,18 +1,18 @@ describe('async functions', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/asyncfunction.js'); - const add = docSet.getByLongname('add')[0]; - const subtract = docSet.getByLongname('subtract')[0]; - const adderAdd = docSet.getByLongname('Adder#add')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/asyncfunction.js'); + const add = docSet.getByLongname('add')[0]; + const subtract = docSet.getByLongname('subtract')[0]; + const adderAdd = docSet.getByLongname('Adder#add')[0]; - it('should automatically document async functions as async', () => { - expect(add.async).toBeTrue(); - }); + it('should automatically document async functions as async', () => { + expect(add.async).toBeTrue(); + }); - it('should work when the async function is assigned to a variable', () => { - expect(subtract.async).toBeTrue(); - }); + it('should work when the async function is assigned to a variable', () => { + expect(subtract.async).toBeTrue(); + }); - it('should work when the async function is a method definition', () => { - expect(adderAdd.async).toBeTrue(); - }); + it('should work when the async function is a method definition', () => { + expect(adderAdd.async).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/callback.js b/packages/jsdoc/test/specs/documentation/callback.js index 2a079628..128453d3 100644 --- a/packages/jsdoc/test/specs/documentation/callback.js +++ b/packages/jsdoc/test/specs/documentation/callback.js @@ -1,25 +1,25 @@ describe('callback tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/callbacktag.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/callbacktag.js'); - function callbackTests(callback) { - expect(callback).toBeObject(); + function callbackTests(callback) { + expect(callback).toBeObject(); - expect(callback.type).toBeObject(); + expect(callback.type).toBeObject(); - expect(callback.type.names).toBeArrayOfSize(1); + expect(callback.type.names).toBeArrayOfSize(1); - expect(callback.type.names[0]).toBe('function'); - } + expect(callback.type.names[0]).toBe('function'); + } - it('correctly handles callbacks that do not define a {type}', () => { - const callback = docSet.getByLongname('requestResponseCallback')[0]; + it('correctly handles callbacks that do not define a {type}', () => { + const callback = docSet.getByLongname('requestResponseCallback')[0]; - callbackTests(callback); - }); + callbackTests(callback); + }); - it('correctly handles callbacks that define an incorrect {type}', () => { - const callback = docSet.getByLongname('wrongTypeCallback')[0]; + it('correctly handles callbacks that define an incorrect {type}', () => { + const callback = docSet.getByLongname('wrongTypeCallback')[0]; - callbackTests(callback); - }); + callbackTests(callback); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/classproperties.js b/packages/jsdoc/test/specs/documentation/classproperties.js index 393e823f..02c153db 100644 --- a/packages/jsdoc/test/specs/documentation/classproperties.js +++ b/packages/jsdoc/test/specs/documentation/classproperties.js @@ -1,27 +1,33 @@ describe('class properties', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/classproperties.js'); - const b = docSet.getByLongname('A#b')[0]; - const c = docSet.getByLongname('A#c')[0]; - const d = docSet.getByLongname('A#d')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/classproperties.js'); + const b = docSet.getByLongname('A#b')[0]; + const c = docSet.getByLongname('A#c')[0]; + const d = docSet.getByLongname('A#d')[0]; - it('should assign the correct name, memberof, and scope to class properties', () => { - expect(b.name).toBe('b'); - expect(b.memberof).toBe('A'); - expect(b.scope).toBe('instance'); - }); + it('should assign the correct name, memberof, and scope to class properties', () => { + expect(b.name).toBe('b'); + expect(b.memberof).toBe('A'); + expect(b.scope).toBe('instance'); + }); - it('should assign the correct name, memberof, scope, and access type to class private ' + - 'properties', () => { - expect(c.name).toBe('c'); - expect(c.memberof).toBe('A'); - expect(c.scope).toBe('instance'); - expect(c.access).toBe('private'); - }); + it( + 'should assign the correct name, memberof, scope, and access type to class private ' + + 'properties', + () => { + expect(c.name).toBe('c'); + expect(c.memberof).toBe('A'); + expect(c.scope).toBe('instance'); + expect(c.access).toBe('private'); + } + ); - it('should assign the correct name, memberof, and scope to class properties with no value ' + - 'assigned', () => { - expect(d.name).toBe('d'); - expect(d.memberof).toBe('A'); - expect(d.scope).toBe('instance'); - }); + it( + 'should assign the correct name, memberof, and scope to class properties with no value ' + + 'assigned', + () => { + expect(d.name).toBe('d'); + expect(d.memberof).toBe('A'); + expect(d.scope).toBe('instance'); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/classwithoutname.js b/packages/jsdoc/test/specs/documentation/classwithoutname.js index 2fa81407..9a69c59a 100644 --- a/packages/jsdoc/test/specs/documentation/classwithoutname.js +++ b/packages/jsdoc/test/specs/documentation/classwithoutname.js @@ -1,11 +1,12 @@ describe('class without a name', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/classwithoutname.js').doclets - .filter(({name}) => name === ''); + const docSet = jsdoc + .getDocSetFromFile('test/fixtures/classwithoutname.js') + .doclets.filter(({ name }) => name === ''); - it('When the doclet for a class has an empty name, it should also have an empty longname', () => { - expect(docSet).toBeArray(); - expect(docSet.length).toBe(1); - expect(docSet[0].description).toBe('Create an instance of MyClass.'); - expect(docSet[0].longname).toBe(''); - }); + it('When the doclet for a class has an empty name, it should also have an empty longname', () => { + expect(docSet).toBeArray(); + expect(docSet.length).toBe(1); + expect(docSet[0].description).toBe('Create an instance of MyClass.'); + expect(docSet[0].longname).toBe(''); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/const.js b/packages/jsdoc/test/specs/documentation/const.js index 1f7e818d..85a814b6 100644 --- a/packages/jsdoc/test/specs/documentation/const.js +++ b/packages/jsdoc/test/specs/documentation/const.js @@ -1,17 +1,17 @@ describe('const declarations', () => { - it('should automatically set the doclet.kind to "constant" for const declarations', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constanttag.js'); - const myPocket = docSet.getByLongname('myPocket')[0]; + it('should automatically set the doclet.kind to "constant" for const declarations', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constanttag.js'); + const myPocket = docSet.getByLongname('myPocket')[0]; - expect(myPocket.kind).toBe('constant'); - }); - - describe('ES 2015 only', () => { - it('should not override kind="class" when a const is autodetected', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constanttag2.js'); - const foo = docSet.getByLongname('Foo')[0]; - - expect(foo.kind).toBe('class'); - }); + expect(myPocket.kind).toBe('constant'); + }); + + describe('ES 2015 only', () => { + it('should not override kind="class" when a const is autodetected', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constanttag2.js'); + const foo = docSet.getByLongname('Foo')[0]; + + expect(foo.kind).toBe('class'); }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/defaultparams.js b/packages/jsdoc/test/specs/documentation/defaultparams.js index 8846e963..843fd88a 100644 --- a/packages/jsdoc/test/specs/documentation/defaultparams.js +++ b/packages/jsdoc/test/specs/documentation/defaultparams.js @@ -1,64 +1,64 @@ describe('default parameters', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/defaultparams.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/defaultparams.js'); - const setActive = docSet.getByLongname('setActive')[0]; - const setBirthYear = docSet.getByLongname('setBirthYear')[0]; - const setDogName = docSet.getByLongname('setDogName')[0]; - const setFirstName = docSet.getByLongname('setFirstName')[0]; - const setIsNinja = docSet.getByLongname('setIsNinja')[0]; - const setLastName = docSet.getByLongname('setLastName')[0]; - const setName = docSet.getByLongname('setName')[0]; - const setPizzaToppings = docSet.getByLongname('setPizzaToppings')[0]; + const setActive = docSet.getByLongname('setActive')[0]; + const setBirthYear = docSet.getByLongname('setBirthYear')[0]; + const setDogName = docSet.getByLongname('setDogName')[0]; + const setFirstName = docSet.getByLongname('setFirstName')[0]; + const setIsNinja = docSet.getByLongname('setIsNinja')[0]; + const setLastName = docSet.getByLongname('setLastName')[0]; + const setName = docSet.getByLongname('setName')[0]; + const setPizzaToppings = docSet.getByLongname('setPizzaToppings')[0]; - it('should automatically add string-literal values as defaults when no default value is documented', () => { - expect(setFirstName.params[0].defaultvalue).toBe('Buster'); - }); - - it('should not automatically mark parameters with default values as optional', () => { - expect(setFirstName.params[0].optional).toBeUndefined(); - }); - - it('should not automatically mark parameters with default values as nullable', () => { - expect(setFirstName.params[0].nullable).toBeUndefined(); - }); - - it('should not override documented default values', () => { - expect(setLastName.params[0].defaultvalue).toBe('Braun'); - }); - - it('should work when some parameters have default values and others do not', () => { - expect(setName.params[0].defaultvalue).toBeUndefined(); - expect(setName.params[1].defaultvalue).toBe('Bluster'); - expect(setName.params[2].defaultvalue).toBe('Brown'); - }); - - it('should ignore empty strings', () => { - expect(setDogName.params[0].defaultvalue).toBeUndefined(); - }); - - it('should work with boolean literals', () => { - expect(setActive.params[0].defaultvalue).toBeTrue(); - }); - - it('should work with numeric literals', () => { - expect(setBirthYear.params[0].defaultvalue).toBe(3000); - }); - - it('should ignore non-literal default values, such as variable identifiers', () => { - expect(setPizzaToppings.params[0].defaultvalue).toBeUndefined(); - }); - - it('should work when the function is assigned to a variable', () => { - expect(setIsNinja.params[0].defaultvalue).toBeTrue(); - }); - - describe('ES2015 methods', () => { - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/defaultparams2.js'); - - const setSardines = docSet2.getByLongname('PizzaToppings#setSardines')[0]; - - it('should autodetect default parameters', () => { - expect(setSardines.params[0].defaultvalue).toBeTrue(); - }); + it('should automatically add string-literal values as defaults when no default value is documented', () => { + expect(setFirstName.params[0].defaultvalue).toBe('Buster'); + }); + + it('should not automatically mark parameters with default values as optional', () => { + expect(setFirstName.params[0].optional).toBeUndefined(); + }); + + it('should not automatically mark parameters with default values as nullable', () => { + expect(setFirstName.params[0].nullable).toBeUndefined(); + }); + + it('should not override documented default values', () => { + expect(setLastName.params[0].defaultvalue).toBe('Braun'); + }); + + it('should work when some parameters have default values and others do not', () => { + expect(setName.params[0].defaultvalue).toBeUndefined(); + expect(setName.params[1].defaultvalue).toBe('Bluster'); + expect(setName.params[2].defaultvalue).toBe('Brown'); + }); + + it('should ignore empty strings', () => { + expect(setDogName.params[0].defaultvalue).toBeUndefined(); + }); + + it('should work with boolean literals', () => { + expect(setActive.params[0].defaultvalue).toBeTrue(); + }); + + it('should work with numeric literals', () => { + expect(setBirthYear.params[0].defaultvalue).toBe(3000); + }); + + it('should ignore non-literal default values, such as variable identifiers', () => { + expect(setPizzaToppings.params[0].defaultvalue).toBeUndefined(); + }); + + it('should work when the function is assigned to a variable', () => { + expect(setIsNinja.params[0].defaultvalue).toBeTrue(); + }); + + describe('ES2015 methods', () => { + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/defaultparams2.js'); + + const setSardines = docSet2.getByLongname('PizzaToppings#setSardines')[0]; + + it('should autodetect default parameters', () => { + expect(setSardines.params[0].defaultvalue).toBeTrue(); }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/emptycomments.js b/packages/jsdoc/test/specs/documentation/emptycomments.js index b48abadf..55d57cb3 100644 --- a/packages/jsdoc/test/specs/documentation/emptycomments.js +++ b/packages/jsdoc/test/specs/documentation/emptycomments.js @@ -1,9 +1,9 @@ describe('empty JSDoc comments', () => { - it('should not report an error when a JSDoc comment contains only whitespace', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/emptycomments.js'); - } + it('should not report an error when a JSDoc comment contains only whitespace', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/emptycomments.js'); + } - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/exportclass.js b/packages/jsdoc/test/specs/documentation/exportclass.js index 87a40eda..4e3ebe91 100644 --- a/packages/jsdoc/test/specs/documentation/exportclass.js +++ b/packages/jsdoc/test/specs/documentation/exportclass.js @@ -1,13 +1,13 @@ describe('export class', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportclass.js'); - const bar = docSet.getByLongname('module:foo.Bar')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportclass.js'); + const bar = docSet.getByLongname('module:foo.Bar')[0]; - it('should name exported classes correctly', () => { - expect(bar).toBeObject(); - expect(bar.name).toBe('Bar'); - }); + it('should name exported classes correctly', () => { + expect(bar).toBeObject(); + expect(bar.name).toBe('Bar'); + }); - it('should merge the class description with the doclet for the class', () => { - expect(bar.classdesc).toBe('Class description'); - }); + it('should merge the class description with the doclet for the class', () => { + expect(bar.classdesc).toBe('Class description'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/exportdefault.js b/packages/jsdoc/test/specs/documentation/exportdefault.js index 5511014e..c4b887e4 100644 --- a/packages/jsdoc/test/specs/documentation/exportdefault.js +++ b/packages/jsdoc/test/specs/documentation/exportdefault.js @@ -1,9 +1,9 @@ describe('export default', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportdefault.js'); - const member = docSet.getByLongname('module:test')[1]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportdefault.js'); + const member = docSet.getByLongname('module:test')[1]; - it('should use the correct kind and description for the default export', () => { - expect(member.kind).toBe('member'); - expect(member.description).toBe('Test value'); - }); + it('should use the correct kind and description for the default export', () => { + expect(member.kind).toBe('member'); + expect(member.description).toBe('Test value'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/exportdefaultclass.js b/packages/jsdoc/test/specs/documentation/exportdefaultclass.js index 5ec8d6ed..8ac7e3b3 100644 --- a/packages/jsdoc/test/specs/documentation/exportdefaultclass.js +++ b/packages/jsdoc/test/specs/documentation/exportdefaultclass.js @@ -1,9 +1,9 @@ describe('export default class', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportdefaultclass.js'); - const klass = docSet.getByLongname('module:test').filter(({undocumented}) => !undocumented)[1]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportdefaultclass.js'); + const klass = docSet.getByLongname('module:test').filter(({ undocumented }) => !undocumented)[1]; - it('should combine the classdesc and constructor description into a single doclet', () => { - expect(klass.classdesc).toBe('Test class'); - expect(klass.description).toBe('Test constructor'); - }); + it('should combine the classdesc and constructor description into a single doclet', () => { + expect(klass.classdesc).toBe('Test class'); + expect(klass.description).toBe('Test constructor'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/exports.js b/packages/jsdoc/test/specs/documentation/exports.js index 74c12675..11660b1f 100644 --- a/packages/jsdoc/test/specs/documentation/exports.js +++ b/packages/jsdoc/test/specs/documentation/exports.js @@ -1,19 +1,25 @@ describe("'exports' symbol in modules", () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exports.js'); - const sayHello = docSet.getByLongname('module:hello/world.sayHello')[0]; - const sayGoodbye = docSet.getByLongname('module:hello/world.sayGoodbye')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exports.js'); + const sayHello = docSet.getByLongname('module:hello/world.sayHello')[0]; + const sayGoodbye = docSet.getByLongname('module:hello/world.sayGoodbye')[0]; - it('When a symbol starts with the special name "exports" and is in a file with a ' + - '@module tag, the symbol is documented as a member of that module.', () => { - expect(sayHello).toBeObject(); - expect(sayHello.kind).toBe('function'); - expect(sayHello.memberof).toBe('module:hello/world'); - }); + it( + 'When a symbol starts with the special name "exports" and is in a file with a ' + + '@module tag, the symbol is documented as a member of that module.', + () => { + expect(sayHello).toBeObject(); + expect(sayHello.kind).toBe('function'); + expect(sayHello.memberof).toBe('module:hello/world'); + } + ); - it('When a symbol starts with the special name "module.exports" and is in a file with a ' + - '@module tag, the symbol is documented as a member of that module.', () => { - expect(sayGoodbye).toBeObject(); - expect(sayGoodbye.kind).toBe('function'); - expect(sayGoodbye.memberof).toBe('module:hello/world'); - }); + it( + 'When a symbol starts with the special name "module.exports" and is in a file with a ' + + '@module tag, the symbol is documented as a member of that module.', + () => { + expect(sayGoodbye).toBeObject(); + expect(sayGoodbye.kind).toBe('function'); + expect(sayGoodbye.memberof).toBe('module:hello/world'); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/funcExpression.js b/packages/jsdoc/test/specs/documentation/funcExpression.js index 2caf60a9..d2df46ba 100644 --- a/packages/jsdoc/test/specs/documentation/funcExpression.js +++ b/packages/jsdoc/test/specs/documentation/funcExpression.js @@ -1,28 +1,28 @@ describe('function expressions', () => { - function checkLongnames(docSet, namespace) { - const memberName = `${namespace || ''}Foo#member1`; - const variableName = `${namespace || ''}Foo~var1`; - const fooMember = docSet.getByLongname(memberName)[0]; - const fooVariable = docSet.getByLongname(variableName)[0]; + function checkLongnames(docSet, namespace) { + const memberName = `${namespace || ''}Foo#member1`; + const variableName = `${namespace || ''}Foo~var1`; + const fooMember = docSet.getByLongname(memberName)[0]; + const fooVariable = docSet.getByLongname(variableName)[0]; - it('should assign the correct longname to members of a function expression', () => { - expect(fooMember.longname).toBe(memberName); - }); - - it('should assign the correct longname to variables in a function expression', () => { - expect(fooVariable.longname).toBe(variableName); - }); - } - - describe('standard', () => { - checkLongnames( jsdoc.getDocSetFromFile('test/fixtures/funcExpression.js') ); + it('should assign the correct longname to members of a function expression', () => { + expect(fooMember.longname).toBe(memberName); }); - describe('global', () => { - checkLongnames( jsdoc.getDocSetFromFile('test/fixtures/funcExpression2.js') ); + it('should assign the correct longname to variables in a function expression', () => { + expect(fooVariable.longname).toBe(variableName); }); + } - describe('as object literal property', () => { - checkLongnames( jsdoc.getDocSetFromFile('test/fixtures/funcExpression3.js'), 'ns.' ); - }); + describe('standard', () => { + checkLongnames(jsdoc.getDocSetFromFile('test/fixtures/funcExpression.js')); + }); + + describe('global', () => { + checkLongnames(jsdoc.getDocSetFromFile('test/fixtures/funcExpression2.js')); + }); + + describe('as object literal property', () => { + checkLongnames(jsdoc.getDocSetFromFile('test/fixtures/funcExpression3.js'), 'ns.'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/generators.js b/packages/jsdoc/test/specs/documentation/generators.js index d5283fb3..0e8c8aea 100644 --- a/packages/jsdoc/test/specs/documentation/generators.js +++ b/packages/jsdoc/test/specs/documentation/generators.js @@ -1,18 +1,18 @@ describe('generator functions', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/generators.js'); - const startsAt0 = docSet.getByLongname('startsAt0')[0]; - const startsAt1 = docSet.getByLongname('startsAt1')[0]; - const startsAt2 = docSet.getByLongname('Generator#startsAt2')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/generators.js'); + const startsAt0 = docSet.getByLongname('startsAt0')[0]; + const startsAt1 = docSet.getByLongname('startsAt1')[0]; + const startsAt2 = docSet.getByLongname('Generator#startsAt2')[0]; - it('should flag generator functions', () => { - expect(startsAt0.generator).toBeTrue(); - }); + it('should flag generator functions', () => { + expect(startsAt0.generator).toBeTrue(); + }); - it('should flag generator functions assigned to variables', () => { - expect(startsAt1.generator).toBeTrue(); - }); + it('should flag generator functions assigned to variables', () => { + expect(startsAt1.generator).toBeTrue(); + }); - it('should flag generator functions that are method definitions', () => { - expect(startsAt2.generator).toBeTrue(); - }); + it('should flag generator functions that are method definitions', () => { + expect(startsAt2.generator).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/getset.js b/packages/jsdoc/test/specs/documentation/getset.js index 814175eb..01bd8bcb 100644 --- a/packages/jsdoc/test/specs/documentation/getset.js +++ b/packages/jsdoc/test/specs/documentation/getset.js @@ -1,55 +1,55 @@ describe('When a getter or setter is part of a class', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/getset.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/getset.js'); - describe('in an object literal', () => { - const name = docSet.getByLongname('Person#name'); - const age = docSet.getByLongname('Person#age'); + describe('in an object literal', () => { + const name = docSet.getByLongname('Person#name'); + const age = docSet.getByLongname('Person#age'); - it('should have a doclet with the correct longname', () => { - expect(name).toBeArrayOfSize(2); - expect(age).toBeArrayOfSize(1); - }); - - it('should have a doclet with the correct name', () => { - expect(name[0].name).toBe('name'); - expect(name[1].name).toBe('name'); - expect(age[0].name).toBe('age'); - }); - - it('should have a doclet with the correct kind', () => { - expect(name[0].kind).toBe('member'); - expect(name[1].kind).toBe('member'); - expect(age[0].kind).toBe('member'); - }); - - it('should have a doclet with the correct memberof', () => { - expect(name[0].memberof).toBe('Person'); - expect(name[1].memberof).toBe('Person'); - expect(age[0].memberof).toBe('Person'); - }); + it('should have a doclet with the correct longname', () => { + expect(name).toBeArrayOfSize(2); + expect(age).toBeArrayOfSize(1); }); - describe('in an ES 2015 class', () => { - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/getset2.js'); - const location = docSet2.getByLongname('Employee#location'); - - it('should have a doclet with the correct longname', () => { - expect(location).toBeArrayOfSize(2); - }); - - it('should have a doclet with the correct name', () => { - expect(location[0].name).toBe('location'); - expect(location[1].name).toBe('location'); - }); - - it('should have a doclet with the correct kind', () => { - expect(location[0].kind).toBe('member'); - expect(location[1].kind).toBe('member'); - }); - - it('should have a doclet with the correct memberof', () => { - expect(location[0].memberof).toBe('Employee'); - expect(location[1].memberof).toBe('Employee'); - }); + it('should have a doclet with the correct name', () => { + expect(name[0].name).toBe('name'); + expect(name[1].name).toBe('name'); + expect(age[0].name).toBe('age'); }); + + it('should have a doclet with the correct kind', () => { + expect(name[0].kind).toBe('member'); + expect(name[1].kind).toBe('member'); + expect(age[0].kind).toBe('member'); + }); + + it('should have a doclet with the correct memberof', () => { + expect(name[0].memberof).toBe('Person'); + expect(name[1].memberof).toBe('Person'); + expect(age[0].memberof).toBe('Person'); + }); + }); + + describe('in an ES 2015 class', () => { + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/getset2.js'); + const location = docSet2.getByLongname('Employee#location'); + + it('should have a doclet with the correct longname', () => { + expect(location).toBeArrayOfSize(2); + }); + + it('should have a doclet with the correct name', () => { + expect(location[0].name).toBe('location'); + expect(location[1].name).toBe('location'); + }); + + it('should have a doclet with the correct kind', () => { + expect(location[0].kind).toBe('member'); + expect(location[1].kind).toBe('member'); + }); + + it('should have a doclet with the correct memberof', () => { + expect(location[0].memberof).toBe('Employee'); + expect(location[1].memberof).toBe('Employee'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/inlinecomment.js b/packages/jsdoc/test/specs/documentation/inlinecomment.js index f36ac173..98b2282c 100644 --- a/packages/jsdoc/test/specs/documentation/inlinecomment.js +++ b/packages/jsdoc/test/specs/documentation/inlinecomment.js @@ -1,13 +1,16 @@ describe('inline comments', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/inlinecomment.js'); - const t = docSet.getByLongname('test'); - const t2 = docSet.getByLongname('test2'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/inlinecomment.js'); + const t = docSet.getByLongname('test'); + const t2 = docSet.getByLongname('test2'); - it('When there is an inline comment on a line ending with no semicolon, ' + - 'that comment and the next comment are still captured', () => { - // Inline comment on line without semicolon is captured - expect(t).toBeArrayOfSize(1); - // Inline comment on line after line without semicolon is captured - expect(t2).toBeArrayOfSize(1); - }); + it( + 'When there is an inline comment on a line ending with no semicolon, ' + + 'that comment and the next comment are still captured', + () => { + // Inline comment on line without semicolon is captured + expect(t).toBeArrayOfSize(1); + // Inline comment on line after line without semicolon is captured + expect(t2).toBeArrayOfSize(1); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/inlineparamcomment.js b/packages/jsdoc/test/specs/documentation/inlineparamcomment.js index 45213076..ae3c4d7c 100644 --- a/packages/jsdoc/test/specs/documentation/inlineparamcomment.js +++ b/packages/jsdoc/test/specs/documentation/inlineparamcomment.js @@ -1,25 +1,28 @@ describe('inline comments on function parameters', () => { - it('should not crash when multiple parameters have inline comments that do not contain any' + - 'JSDoc tags', () => { - function loadDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/inlineparamcomment.js'); - } + it( + 'should not crash when multiple parameters have inline comments that do not contain any' + + 'JSDoc tags', + () => { + function loadDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/inlineparamcomment.js'); + } - expect(loadDocSet).not.toThrow(); + expect(loadDocSet).not.toThrow(); + } + ); + + describe('ES 2015 only', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/inlineparamcomment2.js'); + const foo = docSet.getByLongname('ns.foo')[0]; + + it('should attach inline comments to default parameters', () => { + expect(foo.params[0].type.names).toBeArrayOfSize(1); + expect(foo.params[0].type.names[0]).toBe('string'); }); - describe('ES 2015 only', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/inlineparamcomment2.js'); - const foo = docSet.getByLongname('ns.foo')[0]; - - it('should attach inline comments to default parameters', () => { - expect(foo.params[0].type.names).toBeArrayOfSize(1); - expect(foo.params[0].type.names[0]).toBe('string'); - }); - - it('should attach inline comments to rest parameters', () => { - expect(foo.params[1].type.names).toBeArrayOfSize(1); - expect(foo.params[1].type.names[0]).toBe('number'); - }); + it('should attach inline comments to rest parameters', () => { + expect(foo.params[1].type.names).toBeArrayOfSize(1); + expect(foo.params[1].type.names[0]).toBe('number'); }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/inner.js b/packages/jsdoc/test/specs/documentation/inner.js index 2d8202c0..a0fb4ba9 100644 --- a/packages/jsdoc/test/specs/documentation/inner.js +++ b/packages/jsdoc/test/specs/documentation/inner.js @@ -1,24 +1,24 @@ describe('when a documented var memeber is inside a named function', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/inner.js'); - const found1 = docSet.getByLongname('sendMessage~encoding'); - const found2 = docSet.getByLongname('sendMessage~encrypt'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/inner.js'); + const found1 = docSet.getByLongname('sendMessage~encoding'); + const found2 = docSet.getByLongname('sendMessage~encrypt'); - it('A doclet with the correct longname should be found', () => { - expect(found1).toBeArrayOfSize(1); - expect(found2).toBeArrayOfSize(1); - }); + it('A doclet with the correct longname should be found', () => { + expect(found1).toBeArrayOfSize(1); + expect(found2).toBeArrayOfSize(1); + }); - it('The short name should be correct', () => { - expect(found1[0].name).toBe('encoding'); - expect(found2[0].name).toBe('encrypt'); - }); + it('The short name should be correct', () => { + expect(found1[0].name).toBe('encoding'); + expect(found2[0].name).toBe('encrypt'); + }); - it('The memberof should be correct', () => { - expect(found1[0].memberof).toBe('sendMessage'); - expect(found2[0].memberof).toBe('sendMessage'); - }); - it('The scope should default to "inner"', () => { - expect(found1[0].scope).toBe('inner'); - expect(found2[0].scope).toBe('inner'); - }); + it('The memberof should be correct', () => { + expect(found1[0].memberof).toBe('sendMessage'); + expect(found2[0].memberof).toBe('sendMessage'); + }); + it('The scope should default to "inner"', () => { + expect(found1[0].scope).toBe('inner'); + expect(found2[0].scope).toBe('inner'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/innerscope.js b/packages/jsdoc/test/specs/documentation/innerscope.js index 7eb2d5f5..00a1a2ed 100644 --- a/packages/jsdoc/test/specs/documentation/innerscope.js +++ b/packages/jsdoc/test/specs/documentation/innerscope.js @@ -1,39 +1,39 @@ describe('inner scope', () => { - describe('Outer~inner.member cases', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/innerscope.js'); - const to = docSet.getByLongname('Message~headers.to'); - const from = docSet.getByLongname('Message~headers.from'); - const response = docSet.getByLongname('Message~response.code'); + describe('Outer~inner.member cases', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/innerscope.js'); + const to = docSet.getByLongname('Message~headers.to'); + const from = docSet.getByLongname('Message~headers.from'); + const response = docSet.getByLongname('Message~response.code'); - it('should occur when a member of a var member is documented.', () => { - expect(to).toBeArrayOfSize(1); - }); - - it('should occur when a second member of a var member is documented.', () => { - expect(response).toBeArrayOfSize(1); - }); - - it('should occur when a deeply nested member of a var member is documented.', () => { - expect(from).toBeArrayOfSize(1); - }); + it('should occur when a member of a var member is documented.', () => { + expect(to).toBeArrayOfSize(1); }); - describe('other cases', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/innerscope2.js'); - const from = docSet.getByLongname('~headers.from'); - const cache = docSet.getByLongname('~headers.cache'); - - it('When a var is declared in a function, It is like Inner~member', () => { - expect(cache).toBeArrayOfSize(1); - }); - - it('When a var is masked by an inner var and a member of the inner is documented, it is like Inner~inner.member', () => { - expect(from).toBeArrayOfSize(1); - }); - - it('When a documented member is assigned to a var that masks an outer var.', () => { - expect(from[0].name).toBe('from'); - expect(from[0].memberof).toBe('~headers'); - }); + it('should occur when a second member of a var member is documented.', () => { + expect(response).toBeArrayOfSize(1); }); + + it('should occur when a deeply nested member of a var member is documented.', () => { + expect(from).toBeArrayOfSize(1); + }); + }); + + describe('other cases', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/innerscope2.js'); + const from = docSet.getByLongname('~headers.from'); + const cache = docSet.getByLongname('~headers.cache'); + + it('When a var is declared in a function, It is like Inner~member', () => { + expect(cache).toBeArrayOfSize(1); + }); + + it('When a var is masked by an inner var and a member of the inner is documented, it is like Inner~inner.member', () => { + expect(from).toBeArrayOfSize(1); + }); + + it('When a documented member is assigned to a var that masks an outer var.', () => { + expect(from[0].name).toBe('from'); + expect(from[0].memberof).toBe('~headers'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/instanceproperty.js b/packages/jsdoc/test/specs/documentation/instanceproperty.js index 4e5913dd..7c7c65b4 100644 --- a/packages/jsdoc/test/specs/documentation/instanceproperty.js +++ b/packages/jsdoc/test/specs/documentation/instanceproperty.js @@ -1,10 +1,10 @@ describe('Properties documented in instance methods', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/instanceproperty.js'); - const bar = docSet.getByLongname('Foo#bar')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/instanceproperty.js'); + const bar = docSet.getByLongname('Foo#bar')[0]; - it('should set the correct longname when a property is documented in an instance method', () => { - expect(bar).toBeObject(); - expect(bar.name).toBe('bar'); - expect(bar.kind).toBe('member'); - }); + it('should set the correct longname when a property is documented in an instance method', () => { + expect(bar).toBeObject(); + expect(bar.name).toBe('bar'); + expect(bar.kind).toBe('member'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/jsx.js b/packages/jsdoc/test/specs/documentation/jsx.js index 429160cd..d8b25452 100644 --- a/packages/jsdoc/test/specs/documentation/jsx.js +++ b/packages/jsdoc/test/specs/documentation/jsx.js @@ -1,10 +1,10 @@ describe('JSX support', () => { - it('should parse JSX files without errors', () => { - function parseJsx() { - return jsdoc.getDocSetFromFile('test/fixtures/jsx.js'); - } + it('should parse JSX files without errors', () => { + function parseJsx() { + return jsdoc.getDocSetFromFile('test/fixtures/jsx.js'); + } - expect(parseJsx).not.toThrow(); - expect(jsdoc.didLog(parseJsx, 'error')).toBeFalse(); - }); + expect(parseJsx).not.toThrow(); + expect(jsdoc.didLog(parseJsx, 'error')).toBeFalse(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/lends.js b/packages/jsdoc/test/specs/documentation/lends.js index d138374a..6e8a8581 100644 --- a/packages/jsdoc/test/specs/documentation/lends.js +++ b/packages/jsdoc/test/specs/documentation/lends.js @@ -1,133 +1,133 @@ describe('lends', () => { - describe('when a documented member is inside an object literal associated with a @lends tag', () => { - function removeUndocumented({undocumented}) { - return !(undocumented); - } + describe('when a documented member is inside an object literal associated with a @lends tag', () => { + function removeUndocumented({ undocumented }) { + return !undocumented; + } - describe('standard case', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends.js'); - const init = docSet.getByLongname('Person#initialize'); - const name = docSet.getByLongname('Person#name'); + describe('standard case', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends.js'); + const init = docSet.getByLongname('Person#initialize'); + const name = docSet.getByLongname('Person#name'); - it('The member should be documented as a member of the lendee', () => { - expect(init).toBeArrayOfSize(1); - }); + it('The member should be documented as a member of the lendee', () => { + expect(init).toBeArrayOfSize(1); + }); - it('The this member should be documented as a member of the lendee', () => { - expect(name).toBeArrayOfSize(1); - }); - }); - - describe('case containing constructor', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends2.js'); - const person = docSet.getByLongname('Person').filter(removeUndocumented); - const name = docSet.getByLongname('Person#name'); - - it('A tag with a @constructs tag is documented as a constructor.', () => { - expect(person[0].description).toBe('Construct a Person.'); - }); - - it('The member should be documented as a member of the lendee', () => { - expect(person).toBeArrayOfSize(1); - }); - - it('The this member should be documented as a member of the lendee', () => { - expect(name).toBeArrayOfSize(1); - }); - }); - - describe('case that uses @lends in a multiline doclet', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends3.js'); - const init = docSet.getByLongname('Person#initialize'); - const name = docSet.getByLongname('Person#name'); - - it('The member should be documented as a member of the lendee', () => { - expect(init).toBeArrayOfSize(1); - }); - - it('The this member should be documented as a member of the lendee', () => { - expect(name).toBeArrayOfSize(1); - }); - }); - - describe('case that uses @lends within a closure', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends4.js'); - const person = docSet.getByLongname('Person'); - const say = docSet.getByLongname('Person#say'); - - it('The class constructor should be documented with the name of the lendee', () => { - expect(person).toBeArrayOfSize(1); - expect(person[0].name).toBe('Person'); - expect(person[0].kind).toBe('class'); - }); - - it('A class\' instance method should be documented as a member of the lendee', () => { - expect(say).toBeArrayOfSize(1); - }); - }); - - describe('case that uses @lends within nested function calls', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends5.js'); - const person = docSet.getByLongname('Person').filter(removeUndocumented)[0]; - const say = docSet.getByLongname('Person#say').filter(removeUndocumented)[0]; - - it('The class constructor should be documented with the name of the lendee', () => { - expect(person).toBeObject(); - expect(person.name).toBe('Person'); - expect(person.kind).toBe('class'); - }); - - it('A class\' instance method should be documented as a member of the lendee', () => { - expect(say).toBeObject(); - }); - }); - - describe('case that uses @lends twice within a closure', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends6.js'); - - it('The first class with a @lends tag should appear in the parse results', () => { - const person = docSet.getByLongname('Person').filter(removeUndocumented)[0]; - const say = docSet.getByLongname('Person#say').filter(removeUndocumented)[0]; - - expect(person).toBeObject(); - expect(person.name).toBe('Person'); - expect(person.kind).toBe('class'); - - expect(say).toBeObject(); - expect(say.name).toBe('say'); - expect(say.kind).toBe('function'); - }); - - it('The second class with a @lends tag should appear in the parse results', () => { - const robot = docSet.getByLongname('Robot').filter(removeUndocumented)[0]; - const emote = docSet.getByLongname('Robot#emote').filter(removeUndocumented)[0]; - - expect(robot).toBeObject(); - expect(robot.name).toBe('Robot'); - expect(robot.kind).toBe('class'); - - expect(emote).toBeObject(); - expect(emote.name).toBe('emote'); - expect(emote.kind).toBe('function'); - }); - }); + it('The this member should be documented as a member of the lendee', () => { + expect(name).toBeArrayOfSize(1); + }); }); - describe('when a documented member is inside an objlit associated with a @lends tag that has no value.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/lendsglobal.js'); - const testf = docSet.getByLongname('test')[0]; - const test12 = docSet.getByLongname('test1.test2')[0]; + describe('case containing constructor', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends2.js'); + const person = docSet.getByLongname('Person').filter(removeUndocumented); + const name = docSet.getByLongname('Person#name'); - it('The members of the objlit are not members of any symbol', () => { - expect(testf.memberof).toBeUndefined(); - }); + it('A tag with a @constructs tag is documented as a constructor.', () => { + expect(person[0].description).toBe('Construct a Person.'); + }); - it('The members of the objlit are documented as global.', () => { - expect(testf.longname).toBe('test'); - }); + it('The member should be documented as a member of the lendee', () => { + expect(person).toBeArrayOfSize(1); + }); - it('The nested members of the objlit are members of a global symbol', () => { - expect(test12.memberof).toBe('test1'); - }); + it('The this member should be documented as a member of the lendee', () => { + expect(name).toBeArrayOfSize(1); + }); }); + + describe('case that uses @lends in a multiline doclet', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends3.js'); + const init = docSet.getByLongname('Person#initialize'); + const name = docSet.getByLongname('Person#name'); + + it('The member should be documented as a member of the lendee', () => { + expect(init).toBeArrayOfSize(1); + }); + + it('The this member should be documented as a member of the lendee', () => { + expect(name).toBeArrayOfSize(1); + }); + }); + + describe('case that uses @lends within a closure', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends4.js'); + const person = docSet.getByLongname('Person'); + const say = docSet.getByLongname('Person#say'); + + it('The class constructor should be documented with the name of the lendee', () => { + expect(person).toBeArrayOfSize(1); + expect(person[0].name).toBe('Person'); + expect(person[0].kind).toBe('class'); + }); + + it("A class' instance method should be documented as a member of the lendee", () => { + expect(say).toBeArrayOfSize(1); + }); + }); + + describe('case that uses @lends within nested function calls', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends5.js'); + const person = docSet.getByLongname('Person').filter(removeUndocumented)[0]; + const say = docSet.getByLongname('Person#say').filter(removeUndocumented)[0]; + + it('The class constructor should be documented with the name of the lendee', () => { + expect(person).toBeObject(); + expect(person.name).toBe('Person'); + expect(person.kind).toBe('class'); + }); + + it("A class' instance method should be documented as a member of the lendee", () => { + expect(say).toBeObject(); + }); + }); + + describe('case that uses @lends twice within a closure', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/lends6.js'); + + it('The first class with a @lends tag should appear in the parse results', () => { + const person = docSet.getByLongname('Person').filter(removeUndocumented)[0]; + const say = docSet.getByLongname('Person#say').filter(removeUndocumented)[0]; + + expect(person).toBeObject(); + expect(person.name).toBe('Person'); + expect(person.kind).toBe('class'); + + expect(say).toBeObject(); + expect(say.name).toBe('say'); + expect(say.kind).toBe('function'); + }); + + it('The second class with a @lends tag should appear in the parse results', () => { + const robot = docSet.getByLongname('Robot').filter(removeUndocumented)[0]; + const emote = docSet.getByLongname('Robot#emote').filter(removeUndocumented)[0]; + + expect(robot).toBeObject(); + expect(robot.name).toBe('Robot'); + expect(robot.kind).toBe('class'); + + expect(emote).toBeObject(); + expect(emote.name).toBe('emote'); + expect(emote.kind).toBe('function'); + }); + }); + }); + + describe('when a documented member is inside an objlit associated with a @lends tag that has no value.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/lendsglobal.js'); + const testf = docSet.getByLongname('test')[0]; + const test12 = docSet.getByLongname('test1.test2')[0]; + + it('The members of the objlit are not members of any symbol', () => { + expect(testf.memberof).toBeUndefined(); + }); + + it('The members of the objlit are documented as global.', () => { + expect(testf.longname).toBe('test'); + }); + + it('The nested members of the objlit are members of a global symbol', () => { + expect(test12.memberof).toBe('test1'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/letkeyword.js b/packages/jsdoc/test/specs/documentation/letkeyword.js index bfc48923..102cf4fc 100644 --- a/packages/jsdoc/test/specs/documentation/letkeyword.js +++ b/packages/jsdoc/test/specs/documentation/letkeyword.js @@ -1,23 +1,23 @@ describe('let keyword', () => { - function getDocSet() { - return jsdoc.getDocSetFromFile('test/fixtures/letkeyword.js'); - } + function getDocSet() { + return jsdoc.getDocSetFromFile('test/fixtures/letkeyword.js'); + } - it('should be able to compile JS files that contain the "let" keyword', () => { - expect(getDocSet).not.toThrow(); - }); + it('should be able to compile JS files that contain the "let" keyword', () => { + expect(getDocSet).not.toThrow(); + }); - it('should correctly recognize a module defined with the "let" keyword', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/letkeyword.js'); - const exampleModule = docSet.getByLongname('module:exampleModule'); + it('should correctly recognize a module defined with the "let" keyword', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/letkeyword.js'); + const exampleModule = docSet.getByLongname('module:exampleModule'); - expect(exampleModule).toBeArrayOfSize(1); - }); + expect(exampleModule).toBeArrayOfSize(1); + }); - it('should correctly recognize members of a module defined with the "let" keyword', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/letkeyword.js'); - const exampleMethod = docSet.getByLongname('module:exampleModule.exampleMethod'); + it('should correctly recognize members of a module defined with the "let" keyword', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/letkeyword.js'); + const exampleMethod = docSet.getByLongname('module:exampleModule.exampleMethod'); - expect(exampleMethod).toBeArrayOfSize(1); - }); + expect(exampleMethod).toBeArrayOfSize(1); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/methoddefinition.js b/packages/jsdoc/test/specs/documentation/methoddefinition.js index e3c162f1..63b480c8 100644 --- a/packages/jsdoc/test/specs/documentation/methoddefinition.js +++ b/packages/jsdoc/test/specs/documentation/methoddefinition.js @@ -1,15 +1,15 @@ describe('method definition inside a class declaration', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/methoddefinition.js'); - const runMethod = docSet.getByLongname('Test#run')[0]; - const staticRunMethod = docSet.getByLongname('Test.run')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/methoddefinition.js'); + const runMethod = docSet.getByLongname('Test#run')[0]; + const staticRunMethod = docSet.getByLongname('Test.run')[0]; - it('methods should have documentation comments', () => { - expect(runMethod).toBeObject(); - expect(runMethod.description).toBe('Document me.'); - expect(runMethod.kind).toBe('function'); + it('methods should have documentation comments', () => { + expect(runMethod).toBeObject(); + expect(runMethod.description).toBe('Document me.'); + expect(runMethod.kind).toBe('function'); - expect(staticRunMethod).toBeObject(); - expect(staticRunMethod.description).toBe('Static document me.'); - expect(staticRunMethod.kind).toBe('function'); - }); + expect(staticRunMethod).toBeObject(); + expect(staticRunMethod.description).toBe('Static document me.'); + expect(staticRunMethod.kind).toBe('function'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/mixins.js b/packages/jsdoc/test/specs/documentation/mixins.js index 3be6c852..5f1a8103 100644 --- a/packages/jsdoc/test/specs/documentation/mixins.js +++ b/packages/jsdoc/test/specs/documentation/mixins.js @@ -2,48 +2,48 @@ const augment = require('jsdoc/augment'); const { SCOPE } = require('@jsdoc/core').name; describe('mixins', () => { - describe('doclet augmentation', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag2.js'); + describe('doclet augmentation', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag2.js'); - augment.augmentAll(docSet.doclets); + augment.augmentAll(docSet.doclets); - it('should create doclets for mixed-in symbols', () => { - const objectBMethod = docSet.getByLongname('module:mixy.ObjectB.method')[0]; + it('should create doclets for mixed-in symbols', () => { + const objectBMethod = docSet.getByLongname('module:mixy.ObjectB.method')[0]; - expect(objectBMethod).toBeObject(); - expect(objectBMethod.memberof).toBe('module:mixy.ObjectB'); - }); - - it('should set the "mixes" property correctly on first-generation mixers', () => { - const objectBMethod = docSet.getByLongname('module:mixy.ObjectB.method')[0]; - - expect(objectBMethod.mixes).toBeArrayOfSize(1); - expect(objectBMethod.mixes[0]).toBe('module:mixy.ObjectA.method'); - }); - - it('should set the "mixes" property correctly on second-generation mixers', () => { - const objectCMethod = docSet.getByLongname('module:mixy.ObjectC.method')[0]; - - expect(objectCMethod.mixes).toBeArrayOfSize(1); - expect(objectCMethod.mixes[0]).toBe('module:mixy.ObjectB.method'); - }); - - it('should work with mixed-in doclets whose names are specified in the comment', () => { - const superSweetStatic = docSet.getByLongname('module:mixy.ObjectC.superSweet')[0]; - const superSweetInstance = docSet.getByLongname('module:mixy.ClassB#superSweet')[0]; - - expect(superSweetInstance).toBeObject(); - expect(superSweetInstance.comment).toBe(superSweetStatic.comment); - }); - - describe('classes and mixins', () => { - it('should define symbols mixed into a class as instance members', () => { - const classAMethod = docSet.getByLongname('module:mixy.ClassA#method')[0]; - - expect(classAMethod).toBeObject(); - expect(classAMethod.scope).toBe(SCOPE.NAMES.INSTANCE); - expect(classAMethod.memberof).toBe('module:mixy.ClassA'); - }); - }); + expect(objectBMethod).toBeObject(); + expect(objectBMethod.memberof).toBe('module:mixy.ObjectB'); }); + + it('should set the "mixes" property correctly on first-generation mixers', () => { + const objectBMethod = docSet.getByLongname('module:mixy.ObjectB.method')[0]; + + expect(objectBMethod.mixes).toBeArrayOfSize(1); + expect(objectBMethod.mixes[0]).toBe('module:mixy.ObjectA.method'); + }); + + it('should set the "mixes" property correctly on second-generation mixers', () => { + const objectCMethod = docSet.getByLongname('module:mixy.ObjectC.method')[0]; + + expect(objectCMethod.mixes).toBeArrayOfSize(1); + expect(objectCMethod.mixes[0]).toBe('module:mixy.ObjectB.method'); + }); + + it('should work with mixed-in doclets whose names are specified in the comment', () => { + const superSweetStatic = docSet.getByLongname('module:mixy.ObjectC.superSweet')[0]; + const superSweetInstance = docSet.getByLongname('module:mixy.ClassB#superSweet')[0]; + + expect(superSweetInstance).toBeObject(); + expect(superSweetInstance.comment).toBe(superSweetStatic.comment); + }); + + describe('classes and mixins', () => { + it('should define symbols mixed into a class as instance members', () => { + const classAMethod = docSet.getByLongname('module:mixy.ClassA#method')[0]; + + expect(classAMethod).toBeObject(); + expect(classAMethod.scope).toBe(SCOPE.NAMES.INSTANCE); + expect(classAMethod.memberof).toBe('module:mixy.ClassA'); + }); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/moduleclasses.js b/packages/jsdoc/test/specs/documentation/moduleclasses.js index 56767cd3..327895c5 100644 --- a/packages/jsdoc/test/specs/documentation/moduleclasses.js +++ b/packages/jsdoc/test/specs/documentation/moduleclasses.js @@ -1,33 +1,33 @@ -function filter({undocumented}) { - return !undocumented; +function filter({ undocumented }) { + return !undocumented; } describe('module classes', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleclasses.js'); - const bar = docSet.getByLongname('module:foo~Bar').filter(filter)[0]; - const barBar = docSet.getByLongname('module:foo~Bar#bar')[0]; - const baz = docSet.getByLongname('module:foo.Baz').filter(filter)[0]; - const bazBaz = docSet.getByLongname('module:foo.Baz#baz')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleclasses.js'); + const bar = docSet.getByLongname('module:foo~Bar').filter(filter)[0]; + const barBar = docSet.getByLongname('module:foo~Bar#bar')[0]; + const baz = docSet.getByLongname('module:foo.Baz').filter(filter)[0]; + const bazBaz = docSet.getByLongname('module:foo.Baz#baz')[0]; - describe('inner classes', () => { - it('should merge the constructor doclet with the class doclet', () => { - expect(bar.description).toBe('Construct a Bar.'); - expect(bar.classdesc).toBe('Bar class.'); - }); - - it('should correctly mark the scope of instance properties', () => { - expect(barBar.scope).toBe('instance'); - }); + describe('inner classes', () => { + it('should merge the constructor doclet with the class doclet', () => { + expect(bar.description).toBe('Construct a Bar.'); + expect(bar.classdesc).toBe('Bar class.'); }); - describe('exported classes', () => { - it('should merge the constructor doclet with the class doclet', () => { - expect(baz.description).toBe('Construct a Baz.'); - expect(baz.classdesc).toBe('Baz class.'); - }); - - it('should correctly mark the scope of instance properties', () => { - expect(bazBaz.scope).toBe('instance'); - }); + it('should correctly mark the scope of instance properties', () => { + expect(barBar.scope).toBe('instance'); }); + }); + + describe('exported classes', () => { + it('should merge the constructor doclet with the class doclet', () => { + expect(baz.description).toBe('Construct a Baz.'); + expect(baz.classdesc).toBe('Baz class.'); + }); + + it('should correctly mark the scope of instance properties', () => { + expect(bazBaz.scope).toBe('instance'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/moduleinner.js b/packages/jsdoc/test/specs/documentation/moduleinner.js index 5ee0e76c..51603aba 100644 --- a/packages/jsdoc/test/specs/documentation/moduleinner.js +++ b/packages/jsdoc/test/specs/documentation/moduleinner.js @@ -1,13 +1,13 @@ describe('inner scope for modules', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleinner.js'); - const fooIn = docSet.getByLongname('module:my/module~fooIn')[0]; - const fooOut = docSet.getByLongname('module:my/module~fooOut')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleinner.js'); + const fooIn = docSet.getByLongname('module:my/module~fooIn')[0]; + const fooOut = docSet.getByLongname('module:my/module~fooOut')[0]; - it('When a function appears in the topscope of a module, the symbol is documented as an inner member of that module.', () => { - expect(typeof fooOut).toBe('object'); - expect(fooOut.longname).toBe('module:my/module~fooOut'); + it('When a function appears in the topscope of a module, the symbol is documented as an inner member of that module.', () => { + expect(typeof fooOut).toBe('object'); + expect(fooOut.longname).toBe('module:my/module~fooOut'); - expect(typeof fooIn).toBe('object'); - expect(fooIn.longname).toBe('module:my/module~fooIn'); - }); + expect(typeof fooIn).toBe('object'); + expect(fooIn.longname).toBe('module:my/module~fooIn'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/moduleisconstructor.js b/packages/jsdoc/test/specs/documentation/moduleisconstructor.js index 1fd15eee..dd44a32a 100644 --- a/packages/jsdoc/test/specs/documentation/moduleisconstructor.js +++ b/packages/jsdoc/test/specs/documentation/moduleisconstructor.js @@ -1,89 +1,91 @@ describe('module that exports a constructor', () => { - describe('pre-ES2015 module', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleisconstructor.js'); - const modules = docSet.doclets.filter(({kind}) => kind === 'module'); - const classes = docSet.doclets.filter(({kind}) => kind === 'class'); - const getId = docSet.getByLongname('module:mymodule/config#getId')[0]; - const id = docSet.getByLongname('module:mymodule/config#id')[0]; + describe('pre-ES2015 module', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleisconstructor.js'); + const modules = docSet.doclets.filter(({ kind }) => kind === 'module'); + const classes = docSet.doclets.filter(({ kind }) => kind === 'class'); + const getId = docSet.getByLongname('module:mymodule/config#getId')[0]; + const id = docSet.getByLongname('module:mymodule/config#id')[0]; - it('should include one doclet whose kind is "module"', () => { - expect(modules).toBeArrayOfSize(1); - expect(modules[0].kind).toBe('module'); - }); - - it('should include one doclet whose kind is "class"', () => { - expect(classes).toBeArrayOfSize(1); - expect(classes[0].kind).toBe('class'); - }); - - describe('class doclet', () => { - it('should include a "description" property that contains the constructor description', () => { - expect(classes[0].description).toEqual('Create a new configuration.'); - }); - - it('should include a "classdesc" property', () => { - expect(classes[0].classdesc).toEqual('Describe the class here.'); - }); - }); - - describe('module doclet', () => { - it('should include a "description" property that contains the module description', () => { - expect(modules[0].description).toEqual('Describe the module here.'); - }); - }); - - describe('instance members', () => { - it('should use the correct longname for instance properties', () => { - expect(id.description).toBe('Document me.'); - }); - - it('should use the correct longname for instance methods', () => { - expect(getId.description).toBe('Get the configuration ID.'); - }); - }); + it('should include one doclet whose kind is "module"', () => { + expect(modules).toBeArrayOfSize(1); + expect(modules[0].kind).toBe('module'); }); - describe('ES2015 module', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleisconstructor2.js'); - const modules = docSet.doclets.filter(({kind}) => kind === 'module'); - const classes = docSet.doclets.filter(({kind, classdesc, description}) => kind === 'class' && classdesc && description); - const getId = docSet.getByLongname('module:mymodule/config#getId')[0]; - const id = docSet.getByLongname('module:mymodule/config#id')[0]; - - it('should include one doclet whose kind is "module"', () => { - expect(modules).toBeArrayOfSize(1); - expect(modules[0].kind).toBe('module'); - }); - - it('should include one complete class doclet', () => { - expect(classes).toBeArrayOfSize(1); - expect(classes[0].kind).toBe('class'); - }); - - describe('class doclet', () => { - it('should include a "description" property that contains the constructor description', () => { - expect(classes[0].description).toEqual('Create a new configuration.'); - }); - - it('should include a "classdesc" property', () => { - expect(classes[0].classdesc).toEqual('Describe the class here.'); - }); - }); - - describe('module doclet', () => { - it('should include a "description" property that contains the module description', () => { - expect(modules[0].description).toEqual('Describe the module here.'); - }); - }); - - describe('instance members', () => { - it('should use the correct longname for instance properties', () => { - expect(id.description).toBe('Document me.'); - }); - - it('should use the correct longname for instance methods', () => { - expect(getId.description).toBe('Get the configuration ID.'); - }); - }); + it('should include one doclet whose kind is "class"', () => { + expect(classes).toBeArrayOfSize(1); + expect(classes[0].kind).toBe('class'); }); + + describe('class doclet', () => { + it('should include a "description" property that contains the constructor description', () => { + expect(classes[0].description).toEqual('Create a new configuration.'); + }); + + it('should include a "classdesc" property', () => { + expect(classes[0].classdesc).toEqual('Describe the class here.'); + }); + }); + + describe('module doclet', () => { + it('should include a "description" property that contains the module description', () => { + expect(modules[0].description).toEqual('Describe the module here.'); + }); + }); + + describe('instance members', () => { + it('should use the correct longname for instance properties', () => { + expect(id.description).toBe('Document me.'); + }); + + it('should use the correct longname for instance methods', () => { + expect(getId.description).toBe('Get the configuration ID.'); + }); + }); + }); + + describe('ES2015 module', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleisconstructor2.js'); + const modules = docSet.doclets.filter(({ kind }) => kind === 'module'); + const classes = docSet.doclets.filter( + ({ kind, classdesc, description }) => kind === 'class' && classdesc && description + ); + const getId = docSet.getByLongname('module:mymodule/config#getId')[0]; + const id = docSet.getByLongname('module:mymodule/config#id')[0]; + + it('should include one doclet whose kind is "module"', () => { + expect(modules).toBeArrayOfSize(1); + expect(modules[0].kind).toBe('module'); + }); + + it('should include one complete class doclet', () => { + expect(classes).toBeArrayOfSize(1); + expect(classes[0].kind).toBe('class'); + }); + + describe('class doclet', () => { + it('should include a "description" property that contains the constructor description', () => { + expect(classes[0].description).toEqual('Create a new configuration.'); + }); + + it('should include a "classdesc" property', () => { + expect(classes[0].classdesc).toEqual('Describe the class here.'); + }); + }); + + describe('module doclet', () => { + it('should include a "description" property that contains the module description', () => { + expect(modules[0].description).toEqual('Describe the module here.'); + }); + }); + + describe('instance members', () => { + it('should use the correct longname for instance properties', () => { + expect(id.description).toBe('Document me.'); + }); + + it('should use the correct longname for instance methods', () => { + expect(getId.description).toBe('Get the configuration ID.'); + }); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/moduleisfunction.js b/packages/jsdoc/test/specs/documentation/moduleisfunction.js index 32af437c..84780eff 100644 --- a/packages/jsdoc/test/specs/documentation/moduleisfunction.js +++ b/packages/jsdoc/test/specs/documentation/moduleisfunction.js @@ -1,19 +1,19 @@ describe('module that exports a function that is not a constructor', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleisfunction.js'); - const functions = docSet.doclets.filter(({kind}) => kind === 'function'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduleisfunction.js'); + const functions = docSet.doclets.filter(({ kind }) => kind === 'function'); - it('should include one doclet whose kind is "function"', () => { - expect(functions).toBeArrayOfSize(1); - expect(functions[0].kind).toBe('function'); + it('should include one doclet whose kind is "function"', () => { + expect(functions).toBeArrayOfSize(1); + expect(functions[0].kind).toBe('function'); + }); + + describe('function doclet', () => { + it('should not include a "scope" property', () => { + expect(functions[0].scope).not.toBeDefined(); }); - describe('function doclet', () => { - it('should not include a "scope" property', () => { - expect(functions[0].scope).not.toBeDefined(); - }); - - it('should not include a "memberof" property', () => { - expect(functions[0].memberof).not.toBeDefined(); - }); + it('should not include a "memberof" property', () => { + expect(functions[0].memberof).not.toBeDefined(); }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/modules.js b/packages/jsdoc/test/specs/documentation/modules.js index 4e853cb4..12474108 100644 --- a/packages/jsdoc/test/specs/documentation/modules.js +++ b/packages/jsdoc/test/specs/documentation/modules.js @@ -1,57 +1,55 @@ describe('module names', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let doclets; - let srcParser = null; + let doclets; + let srcParser = null; - beforeEach(() => { - env.opts._ = [path.normalize(`${__dirname}/../../fixtures/modules/data`)]; - env.sourceFiles = []; - srcParser = jsdoc.createParser(); - require('jsdoc/src/handlers').attachTo(srcParser); + beforeEach(() => { + env.opts._ = [path.normalize(`${__dirname}/../../fixtures/modules/data`)]; + env.sourceFiles = []; + srcParser = jsdoc.createParser(); + require('jsdoc/src/handlers').attachTo(srcParser); + }); + + it('should create a name from the file path when no documented module name exists', () => { + const filename = path.resolve(env.dirname, 'test/fixtures/modules/data/mod-1.js'); + + env.sourceFiles.push(filename); + doclets = srcParser.parse(filename); + + expect(doclets.length).toBeGreaterThan(1); + expect(doclets[0].longname).toBe('module:mod-1'); + }); + + // Windows-specific test + if (/^win/.test(require('os').platform())) { + it('should always use forward slashes when creating a name from the file path', () => { + const { Doclet } = require('jsdoc/doclet'); + let doclet; + + env.sourceFiles = [ + 'C:\\Users\\Jane Smith\\myproject\\index.js', + 'C:\\Users\\Jane Smith\\myproject\\lib\\mymodule.js', + ]; + env.opts._ = []; + + doclet = new Doclet('/** @module */', { + lineno: 1, + filename: 'C:\\Users\\Jane Smith\\myproject\\lib\\mymodule.js', + }); + + expect(doclet.name).toBe('lib/mymodule'); }); + } - it('should create a name from the file path when no documented module name exists', () => { - const filename = path.resolve(env.dirname, 'test/fixtures/modules/data/mod-1.js'); + it('should use the documented module name if available', () => { + const filename = 'test/fixtures/modules/data/mod-2.js'; - env.sourceFiles.push(filename); - doclets = srcParser.parse(filename); + env.sourceFiles.push(filename); + doclets = srcParser.parse(path.normalize(path.join(env.dirname, filename))); - expect(doclets.length).toBeGreaterThan(1); - expect(doclets[0].longname).toBe('module:mod-1'); - }); - - // Windows-specific test - if ( /^win/.test(require('os').platform()) ) { - it('should always use forward slashes when creating a name from the file path', () => { - const { Doclet } = require('jsdoc/doclet'); - let doclet; - - env.sourceFiles = [ - 'C:\\Users\\Jane Smith\\myproject\\index.js', - 'C:\\Users\\Jane Smith\\myproject\\lib\\mymodule.js' - ]; - env.opts._ = []; - - doclet = new Doclet('/** @module */', { - lineno: 1, - filename: 'C:\\Users\\Jane Smith\\myproject\\lib\\mymodule.js' - }); - - expect(doclet.name).toBe('lib/mymodule'); - }); - } - - it('should use the documented module name if available', () => { - const filename = 'test/fixtures/modules/data/mod-2.js'; - - env.sourceFiles.push(filename); - doclets = srcParser.parse( - path.normalize( path.join(env.dirname, filename) ) - ); - - expect(doclets.length).toBeGreaterThan(1); - expect(doclets[0].longname).toBe('module:my/module/name'); - }); + expect(doclets.length).toBeGreaterThan(1); + expect(doclets[0].longname).toBe('module:my/module/name'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/objectkeys.js b/packages/jsdoc/test/specs/documentation/objectkeys.js index 56f06722..3d7c24b7 100644 --- a/packages/jsdoc/test/specs/documentation/objectkeys.js +++ b/packages/jsdoc/test/specs/documentation/objectkeys.js @@ -1,10 +1,10 @@ describe('object keys', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectkeys.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectkeys.js'); - it('should assign the correct longname and memberof to object keys after the first key', () => { - const bar = docSet.getByLongname('myObject.bar')[0]; + it('should assign the correct longname and memberof to object keys after the first key', () => { + const bar = docSet.getByLongname('myObject.bar')[0]; - expect(bar).toBeObject(); - expect(bar.memberof).toBe('myObject'); - }); + expect(bar).toBeObject(); + expect(bar.memberof).toBe('myObject'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/objectlit.js b/packages/jsdoc/test/specs/documentation/objectlit.js index c872bf94..8ec3c5c2 100644 --- a/packages/jsdoc/test/specs/documentation/objectlit.js +++ b/packages/jsdoc/test/specs/documentation/objectlit.js @@ -1,67 +1,67 @@ describe('object literals', () => { - describe('When a child of an objlit has no @name or @memberof tags', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectlit.js'); - const found = docSet.getByLongname('tools.serialiser.value'); + describe('When a child of an objlit has no @name or @memberof tags', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectlit.js'); + const found = docSet.getByLongname('tools.serialiser.value'); - it('should have a doclet with the correct longname', () => { - expect(found).toBeArrayOfSize(1); - }); - - it('should have a doclet with the correct name', () => { - expect(found[0].name).toBe('value'); - }); - - it('should have the correct memberof', () => { - expect(found[0].memberof).toBe('tools.serialiser'); - }); - - it('should have a static scope', () => { - expect(found[0].scope).toBe('static'); - }); + it('should have a doclet with the correct longname', () => { + expect(found).toBeArrayOfSize(1); }); - describe('When a parent of an objlit has no documentation', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectlit2.js'); - const found = docSet.getByLongname('position.axis.x'); - - it('should have a doclet with the correct longname', () => { - expect(found).toBeArrayOfSize(1); - }); - - it('should have a doclet with the correct name', () => { - expect(found[0].name).toBe('x'); - }); - - it('should have the correct memberof', () => { - expect(found[0].memberof).toBe('position.axis'); - }); - - it('should have a static scope', () => { - expect(found[0].scope).toBe('static'); - }); + it('should have a doclet with the correct name', () => { + expect(found[0].name).toBe('value'); }); - describe('When an object literal\'s property names must be escaped in a regexp', () => { - function loadDocSet() { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectlit3.js'); - - return docSet.getByLongname('tokens."(".before'); - } - - it('should not throw an error when creating a doclet', () => { - expect(loadDocSet).not.toThrow(); - }); - - it('should have a doclet with the correct name', () => { - const found = loadDocSet(); - - expect(found[0].name).toBe('before'); - }); - - it('should have a doclet with the correct memberof', () => { - const found = loadDocSet(); - - expect(found[0].memberof).toBe('tokens."("'); - }); + it('should have the correct memberof', () => { + expect(found[0].memberof).toBe('tools.serialiser'); }); + + it('should have a static scope', () => { + expect(found[0].scope).toBe('static'); + }); + }); + + describe('When a parent of an objlit has no documentation', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectlit2.js'); + const found = docSet.getByLongname('position.axis.x'); + + it('should have a doclet with the correct longname', () => { + expect(found).toBeArrayOfSize(1); + }); + + it('should have a doclet with the correct name', () => { + expect(found[0].name).toBe('x'); + }); + + it('should have the correct memberof', () => { + expect(found[0].memberof).toBe('position.axis'); + }); + + it('should have a static scope', () => { + expect(found[0].scope).toBe('static'); + }); + }); + + describe("When an object literal's property names must be escaped in a regexp", () => { + function loadDocSet() { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/objectlit3.js'); + + return docSet.getByLongname('tokens."(".before'); + } + + it('should not throw an error when creating a doclet', () => { + expect(loadDocSet).not.toThrow(); + }); + + it('should have a doclet with the correct name', () => { + const found = loadDocSet(); + + expect(found[0].name).toBe('before'); + }); + + it('should have a doclet with the correct memberof', () => { + const found = loadDocSet(); + + expect(found[0].memberof).toBe('tokens."("'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/objectpropertykeys.js b/packages/jsdoc/test/specs/documentation/objectpropertykeys.js index 88b78030..01499ca0 100644 --- a/packages/jsdoc/test/specs/documentation/objectpropertykeys.js +++ b/packages/jsdoc/test/specs/documentation/objectpropertykeys.js @@ -1,9 +1,9 @@ describe('using existing Object properties as object literal keys', () => { - function loadDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/objectpropertykeys.js'); - } + function loadDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/objectpropertykeys.js'); + } - it('should not crash', () => { - expect(loadDocSet).not.toThrow(); - }); + it('should not crash', () => { + expect(loadDocSet).not.toThrow(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/paramtagsametype.js b/packages/jsdoc/test/specs/documentation/paramtagsametype.js index 73e863cb..a76bd769 100644 --- a/packages/jsdoc/test/specs/documentation/paramtagsametype.js +++ b/packages/jsdoc/test/specs/documentation/paramtagsametype.js @@ -1,28 +1,28 @@ const env = require('jsdoc/env'); describe('multiple @param tags with the same type expression', () => { - const debug = Boolean(env.opts.debug); + const debug = Boolean(env.opts.debug); - afterEach(() => { - env.opts.debug = debug; - }); + afterEach(() => { + env.opts.debug = debug; + }); - it('does not have circular references when type.parsedType is enumerable', () => { - let docSet; - let params; - let stringified; + it('does not have circular references when type.parsedType is enumerable', () => { + let docSet; + let params; + let stringified; - // Force type.parsedType to be enumerable. - env.opts.debug = true; - docSet = jsdoc.getDocSetFromFile('test/fixtures/paramtagsametype.js'); - params = docSet.getByLongname('foo.bar.Baz').filter(d => !d.undocumented)[0].params; - stringified = JSON.stringify(params); + // Force type.parsedType to be enumerable. + env.opts.debug = true; + docSet = jsdoc.getDocSetFromFile('test/fixtures/paramtagsametype.js'); + params = docSet.getByLongname('foo.bar.Baz').filter((d) => !d.undocumented)[0].params; + stringified = JSON.stringify(params); - expect(stringified).toContain('"parsedType":'); - expect(stringified).not.toContain(''); + expect(stringified).toContain('"parsedType":'); + expect(stringified).not.toContain(''); - // Prevent the schema validator from complaining about `parsedType`. (The schema _should_ - // allow that property, but for some reason, that doesn't work correctly.) - params.forEach(p => delete p.type.parsedType); - }); + // Prevent the schema validator from complaining about `parsedType`. (The schema _should_ + // allow that property, but for some reason, that doesn't work correctly.) + params.forEach((p) => delete p.type.parsedType); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/quotename.js b/packages/jsdoc/test/specs/documentation/quotename.js index 6c643f99..c9a7adf3 100644 --- a/packages/jsdoc/test/specs/documentation/quotename.js +++ b/packages/jsdoc/test/specs/documentation/quotename.js @@ -1,21 +1,21 @@ describe('quoted names', () => { - describe('when found in square brackets', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/quotename.js'); - const found1 = docSet.getByLongname('chat."#channel".open')[0]; + describe('when found in square brackets', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/quotename.js'); + const found1 = docSet.getByLongname('chat."#channel".open')[0]; - it('should have correct name and memberof', () => { - expect(found1.name).toBe('open'); - expect(found1.memberof).toBe('chat."#channel"'); - }); + it('should have correct name and memberof', () => { + expect(found1.name).toBe('open'); + expect(found1.memberof).toBe('chat."#channel"'); }); + }); - describe('when found in an object literal', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/quotename2.js'); - const found1 = docSet.getByLongname('contacts."say-\\"hello\\"@example.com".username')[0]; + describe('when found in an object literal', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/quotename2.js'); + const found1 = docSet.getByLongname('contacts."say-\\"hello\\"@example.com".username')[0]; - it('should have correct name and memberof', () => { - expect(found1.name).toBe('username'); - expect(found1.memberof).toBe('contacts."say-\\"hello\\"@example.com"'); - }); + it('should have correct name and memberof', () => { + expect(found1.name).toBe('username'); + expect(found1.memberof).toBe('contacts."say-\\"hello\\"@example.com"'); }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/restparams.js b/packages/jsdoc/test/specs/documentation/restparams.js index f09d929b..07c5cf44 100644 --- a/packages/jsdoc/test/specs/documentation/restparams.js +++ b/packages/jsdoc/test/specs/documentation/restparams.js @@ -1,36 +1,36 @@ describe('rest parameters', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/restparams.js'); - const setAdmins = docSet.getByLongname('setAdmins')[0]; - const setManagers = docSet.getByLongname('setManagers')[0]; - const setWidgetAccess = docSet.getByLongname('setWidgetAccess')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/restparams.js'); + const setAdmins = docSet.getByLongname('setAdmins')[0]; + const setManagers = docSet.getByLongname('setManagers')[0]; + const setWidgetAccess = docSet.getByLongname('setWidgetAccess')[0]; - it('should automatically mark standalone rest parameters as repeatable', () => { - const restParam = setAdmins.params[0]; + it('should automatically mark standalone rest parameters as repeatable', () => { + const restParam = setAdmins.params[0]; - expect(restParam.name).toBe('users'); - expect(restParam.variable).toBeTrue(); - }); - - it('should automatically mark rest parameters as repeatable when they are mixed with other params', () => { - const restParam = setWidgetAccess.params[1]; - - expect(restParam.name).toBe('users'); - expect(restParam.variable).toBeTrue(); - }); - - it('should automatically mark rest parameters as repeatable when the function is assigned to a variable', () => { - const restParam = setManagers.params[0]; - - expect(restParam.name).toBe('users'); - expect(restParam.variable).toBeTrue(); - }); - - describe('ES2015 methods', () => { - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/restparams2.js'); - const addUsers = docSet2.getByLongname('Widget#addUsers')[0]; - - it('should autodetect rest parameters', () => { - expect(addUsers.params[0].variable).toBeTrue(); - }); + expect(restParam.name).toBe('users'); + expect(restParam.variable).toBeTrue(); + }); + + it('should automatically mark rest parameters as repeatable when they are mixed with other params', () => { + const restParam = setWidgetAccess.params[1]; + + expect(restParam.name).toBe('users'); + expect(restParam.variable).toBeTrue(); + }); + + it('should automatically mark rest parameters as repeatable when the function is assigned to a variable', () => { + const restParam = setManagers.params[0]; + + expect(restParam.name).toBe('users'); + expect(restParam.variable).toBeTrue(); + }); + + describe('ES2015 methods', () => { + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/restparams2.js'); + const addUsers = docSet2.getByLongname('Widget#addUsers')[0]; + + it('should autodetect rest parameters', () => { + expect(addUsers.params[0].variable).toBeTrue(); }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/specialchars.js b/packages/jsdoc/test/specs/documentation/specialchars.js index 16a7c414..0d2fbd95 100644 --- a/packages/jsdoc/test/specs/documentation/specialchars.js +++ b/packages/jsdoc/test/specs/documentation/specialchars.js @@ -1,15 +1,21 @@ describe('longnames with special characters', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/specialchars.js'); - const portNumber = docSet.getByLongname('Socket#\'port#number\'')[0]; - const open = docSet.getByLongname('Socket#\'open~a.connection#now\'')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/specialchars.js'); + const portNumber = docSet.getByLongname("Socket#'port#number'")[0]; + const open = docSet.getByLongname("Socket#'open~a.connection#now'")[0]; - it('should use the correct longname for instance members of "this" whose names contain ' + - 'scope punctuation', () => { - expect(portNumber).toBeObject(); - }); + it( + 'should use the correct longname for instance members of "this" whose names contain ' + + 'scope punctuation', + () => { + expect(portNumber).toBeObject(); + } + ); - it('should use the correct longname for instance members of the prototype whose names ' + - 'contain scope punctuation', () => { - expect(open).toBeObject(); - }); + it( + 'should use the correct longname for instance members of the prototype whose names ' + + 'contain scope punctuation', + () => { + expect(open).toBeObject(); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/specialnames.js b/packages/jsdoc/test/specs/documentation/specialnames.js index 45e95856..1c6886b0 100644 --- a/packages/jsdoc/test/specs/documentation/specialnames.js +++ b/packages/jsdoc/test/specs/documentation/specialnames.js @@ -1,28 +1,28 @@ describe('documenting symbols with special names', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/specialnames.js'); - const construct = docSet.getByLongname('constructor')[0]; - const constructToString = docSet.getByLongname('constructor.toString')[0]; - const hasOwnProp = docSet.getByLongname('hasOwnProperty')[0]; - const proto = docSet.getByLongname('prototype')[0]; - const protoValueOf = docSet.getByLongname('prototype.valueOf')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/specialnames.js'); + const construct = docSet.getByLongname('constructor')[0]; + const constructToString = docSet.getByLongname('constructor.toString')[0]; + const hasOwnProp = docSet.getByLongname('hasOwnProperty')[0]; + const proto = docSet.getByLongname('prototype')[0]; + const protoValueOf = docSet.getByLongname('prototype.valueOf')[0]; - it('When a symbol is named "constructor", the symbol should appear in the docs.', () => { - expect(construct).toBeObject(); - }); + it('When a symbol is named "constructor", the symbol should appear in the docs.', () => { + expect(construct).toBeObject(); + }); - it('When a symbol is named "constructor", its members are resolved correctly.', () => { - expect(constructToString).toBeObject(); - }); + it('When a symbol is named "constructor", its members are resolved correctly.', () => { + expect(constructToString).toBeObject(); + }); - it('When a symbol is named "hasOwnProperty," the symbol should appear in the docs.', () => { - expect(hasOwnProp).toBeObject(); - }); + it('When a symbol is named "hasOwnProperty," the symbol should appear in the docs.', () => { + expect(hasOwnProp).toBeObject(); + }); - it('When a symbol is named "prototype", the symbol should appear in the docs.', () => { - expect(proto).toBeObject(); - }); + it('When a symbol is named "prototype", the symbol should appear in the docs.', () => { + expect(proto).toBeObject(); + }); - it('When a symbol is named "prototype", its members are resolved correctly.', () => { - expect(protoValueOf).toBeObject(); - }); + it('When a symbol is named "prototype", its members are resolved correctly.', () => { + expect(protoValueOf).toBeObject(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/starbangstar.js b/packages/jsdoc/test/specs/documentation/starbangstar.js index 66e99dfb..0be997df 100644 --- a/packages/jsdoc/test/specs/documentation/starbangstar.js +++ b/packages/jsdoc/test/specs/documentation/starbangstar.js @@ -1,13 +1,13 @@ describe('starbangstar', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/starbangstar.js'); - const mod = docSet.getByLongname('module:myscript/core')[0]; - const x = docSet.getByLongname('module:myscript/core.x')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/starbangstar.js'); + const mod = docSet.getByLongname('module:myscript/core')[0]; + const x = docSet.getByLongname('module:myscript/core.x')[0]; - it('should not treat a doclet starting with /*!* as a JSDoc comment.', () => { - expect(mod.description).toBe('Script that does something awesome'); - }); + it('should not treat a doclet starting with /*!* as a JSDoc comment.', () => { + expect(mod.description).toBe('Script that does something awesome'); + }); - it('should not treat a doclet starting with /*!** as a JSDoc comment.', () => { - expect(x).toBeUndefined(); - }); + it('should not treat a doclet starting with /*!** as a JSDoc comment.', () => { + expect(x).toBeUndefined(); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/this.js b/packages/jsdoc/test/specs/documentation/this.js index 653ad5ba..2ef4dd11 100644 --- a/packages/jsdoc/test/specs/documentation/this.js +++ b/packages/jsdoc/test/specs/documentation/this.js @@ -1,147 +1,147 @@ describe('this', () => { - describe('attaching members to "this"', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/this.js'); - const found1 = docSet.getByLongname('Singer#tralala'); - const found2 = docSet.getByLongname('Singer#isSinging'); + describe('attaching members to "this"', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/this.js'); + const found1 = docSet.getByLongname('Singer#tralala'); + const found2 = docSet.getByLongname('Singer#isSinging'); - describe('in a contructor', () => { - it('should have a longname like Constructor#member', () => { - expect(found1).toBeArrayOfSize(1); - }); + describe('in a contructor', () => { + it('should have a longname like Constructor#member', () => { + expect(found1).toBeArrayOfSize(1); + }); - it('should have a correct short name', () => { - expect(found1[0].name).toBe('tralala'); - }); + it('should have a correct short name', () => { + expect(found1[0].name).toBe('tralala'); + }); - it('should have a correct memberof', () => { - expect(found1[0].memberof).toBe('Singer'); - }); + it('should have a correct memberof', () => { + expect(found1[0].memberof).toBe('Singer'); + }); - it('should default to an "instance" scope', () => { - expect(found1[0].scope).toBe('instance'); - }); - }); - - describe('in a method of a constructor', () => { - it('should have a longname like Constructor#member', () => { - expect(found2).toBeArrayOfSize(1); - }); - - it('should have a correct short name', () => { - expect(found2[0].name).toBe('isSinging'); - }); - - it('should have a correct memberof', () => { - expect(found2[0].memberof).toBe('Singer'); - }); - - it('should default to an "instance" scope', () => { - expect(found2[0].scope).toBe('instance'); - }); - }); + it('should default to an "instance" scope', () => { + expect(found1[0].scope).toBe('instance'); + }); }); - describe('when a contructor is nested inside another constructor', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/this2.js'); - const found = docSet.getByLongname('TemplateBuilder#Template#rendered'); + describe('in a method of a constructor', () => { + it('should have a longname like Constructor#member', () => { + expect(found2).toBeArrayOfSize(1); + }); - it('should have a longname like Constructor#Constructor#member', () => { - expect(found).toBeArrayOfSize(1); - }); + it('should have a correct short name', () => { + expect(found2[0].name).toBe('isSinging'); + }); - it('should have a correct short name', () => { - expect(found[0].name).toBe('rendered'); - }); + it('should have a correct memberof', () => { + expect(found2[0].memberof).toBe('Singer'); + }); - it('should have a correct memberof', () => { - expect(found[0].memberof).toBe('TemplateBuilder#Template'); - }); + it('should default to an "instance" scope', () => { + expect(found2[0].scope).toBe('instance'); + }); + }); + }); - it('should default to an "instance" scope', () => { - expect(found[0].scope).toBe('instance'); - }); + describe('when a contructor is nested inside another constructor', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/this2.js'); + const found = docSet.getByLongname('TemplateBuilder#Template#rendered'); + + it('should have a longname like Constructor#Constructor#member', () => { + expect(found).toBeArrayOfSize(1); }); - describe('When a this is assigned to inside a non-constructor function', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/this3.js'); - const found = docSet.getByLongname('position'); - - it('should have a global member name like "member"', () => { - expect(found).toBeArrayOfSize(1); - }); - - it('should have a correct short name', () => { - expect(found[0].name).toBe('position'); - }); - - it('should have a correct memberof', () => { - expect(found[0].memberof).toBeUndefined(); - }); + it('should have a correct short name', () => { + expect(found[0].name).toBe('rendered'); }); - describe('When "this" is assigned inside an explicit definition of the class constructor', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/this4.js'); - const found = docSet.getByLongname('Template#render'); - - it('should have a longname like Constructor#member', () => { - expect(found).toBeArrayOfSize(1); - }); - - it('should have the correct name', () => { - expect(found[0].name).toBe('render'); - }); - - it('should have the correct memberof', () => { - expect(found[0].memberof).toBe('Template'); - }); + it('should have a correct memberof', () => { + expect(found[0].memberof).toBe('TemplateBuilder#Template'); }); - describe('When "this" is assigned in a chained declaration in a module', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/this5.js'); - const found = docSet.getByLongname('module:template.Template#view'); + it('should default to an "instance" scope', () => { + expect(found[0].scope).toBe('instance'); + }); + }); - it('should have a longname like Constructor#member', () => { - expect(found).toBeArrayOfSize(1); - }); + describe('When a this is assigned to inside a non-constructor function', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/this3.js'); + const found = docSet.getByLongname('position'); - it('should have the correct name', () => { - expect(found[0].name).toBe('view'); - }); - - it('should have the correct memberof', () => { - expect(found[0].memberof).toBe('module:template.Template'); - }); + it('should have a global member name like "member"', () => { + expect(found).toBeArrayOfSize(1); }); - describe('When `this` is within the constructor in a class that has an `@alias` tag within a module', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/this6.js'); - const someProperty = docSet.getByLongname('module:example#_someProperty')[0]; - - it('should have the correct longname, name, and scope', () => { - expect(someProperty).toBeObject(); - expect(someProperty.name).toBe('_someProperty'); - expect(someProperty.scope).toBe('instance'); - }); + it('should have a correct short name', () => { + expect(found[0].name).toBe('position'); }); - describe('When a member is nested inside an objectlit "this" property inside a constructor', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/this-and-objectlit.js'); - const found = docSet.getByLongname('Page#parts.body.heading'); - - it('should have a longname like Constructor#objlit.member', () => { - expect(found).toBeArrayOfSize(1); - }); - - it('should have a correct short name', () => { - expect(found[0].name).toBe('heading'); - }); - - it('should have a correct memberof', () => { - expect(found[0].memberof).toBe('Page#parts.body'); - }); - - it('should default to a "static" scope', () => { - expect(found[0].scope).toBe('static'); - }); + it('should have a correct memberof', () => { + expect(found[0].memberof).toBeUndefined(); }); + }); + + describe('When "this" is assigned inside an explicit definition of the class constructor', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/this4.js'); + const found = docSet.getByLongname('Template#render'); + + it('should have a longname like Constructor#member', () => { + expect(found).toBeArrayOfSize(1); + }); + + it('should have the correct name', () => { + expect(found[0].name).toBe('render'); + }); + + it('should have the correct memberof', () => { + expect(found[0].memberof).toBe('Template'); + }); + }); + + describe('When "this" is assigned in a chained declaration in a module', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/this5.js'); + const found = docSet.getByLongname('module:template.Template#view'); + + it('should have a longname like Constructor#member', () => { + expect(found).toBeArrayOfSize(1); + }); + + it('should have the correct name', () => { + expect(found[0].name).toBe('view'); + }); + + it('should have the correct memberof', () => { + expect(found[0].memberof).toBe('module:template.Template'); + }); + }); + + describe('When `this` is within the constructor in a class that has an `@alias` tag within a module', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/this6.js'); + const someProperty = docSet.getByLongname('module:example#_someProperty')[0]; + + it('should have the correct longname, name, and scope', () => { + expect(someProperty).toBeObject(); + expect(someProperty.name).toBe('_someProperty'); + expect(someProperty.scope).toBe('instance'); + }); + }); + + describe('When a member is nested inside an objectlit "this" property inside a constructor', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/this-and-objectlit.js'); + const found = docSet.getByLongname('Page#parts.body.heading'); + + it('should have a longname like Constructor#objlit.member', () => { + expect(found).toBeArrayOfSize(1); + }); + + it('should have a correct short name', () => { + expect(found[0].name).toBe('heading'); + }); + + it('should have a correct memberof', () => { + expect(found[0].memberof).toBe('Page#parts.body'); + }); + + it('should default to a "static" scope', () => { + expect(found[0].scope).toBe('static'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/trailingcomment.js b/packages/jsdoc/test/specs/documentation/trailingcomment.js index eaa87a06..db264611 100644 --- a/packages/jsdoc/test/specs/documentation/trailingcomment.js +++ b/packages/jsdoc/test/specs/documentation/trailingcomment.js @@ -1,17 +1,23 @@ describe('trailing comment', () => { - it('should not ignore trailing comments in a non-empty source file with a `use strict` ' + - 'declaration', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/trailingcomment.js'); - const foo = docSet.getByLongname('external:foo'); + it( + 'should not ignore trailing comments in a non-empty source file with a `use strict` ' + + 'declaration', + () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/trailingcomment.js'); + const foo = docSet.getByLongname('external:foo'); - expect(foo).toBeArrayOfSize(1); - }); + expect(foo).toBeArrayOfSize(1); + } + ); - it('should not ignore trailing comments in an empty source file with a `use strict` ' + - 'declaration', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/trailingcomment2.js'); - const foo = docSet.getByLongname('external:foo'); + it( + 'should not ignore trailing comments in an empty source file with a `use strict` ' + + 'declaration', + () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/trailingcomment2.js'); + const foo = docSet.getByLongname('external:foo'); - expect(foo).toBeArrayOfSize(1); - }); + expect(foo).toBeArrayOfSize(1); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/typetaginline.js b/packages/jsdoc/test/specs/documentation/typetaginline.js index 28a48e7d..311ebfc4 100644 --- a/packages/jsdoc/test/specs/documentation/typetaginline.js +++ b/packages/jsdoc/test/specs/documentation/typetaginline.js @@ -1,105 +1,113 @@ describe('@type tag inline with function parameters', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typetaginline.js'); - let info; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typetaginline.js'); + let info; - function checkParams({params}, paramInfo) { - expect(params).toBeDefined(); - expect(params.length).toBe(paramInfo.length); + function checkParams({ params }, paramInfo) { + expect(params).toBeDefined(); + expect(params.length).toBe(paramInfo.length); - params.forEach(({name, type, description}, i) => { - expect(name).toBe(paramInfo[i].name); - expect(type.names[0]).toBe(paramInfo[i].typeName); - if (paramInfo[i].description !== undefined) { - expect(description).toBe(paramInfo[i].description); - } - }); + params.forEach(({ name, type, description }, i) => { + expect(name).toBe(paramInfo[i].name); + expect(type.names[0]).toBe(paramInfo[i].typeName); + if (paramInfo[i].description !== undefined) { + expect(description).toBe(paramInfo[i].description); + } + }); + } + + beforeEach(() => { + info = []; + }); + + it('When a function parameter has an inline @type tag, the parameter type is documented', () => { + const dispense = docSet.getByLongname('dispense')[0]; + + info[0] = { + name: 'candy', + typeName: 'string', + }; + + checkParams(dispense, info); + }); + + it( + 'When a function parameter has a standard JSDoc comment and an inline @type tag, the docs ' + + 'reflect the standard JSDoc comment', + () => { + const Dispenser = docSet.getByLongname('Dispenser')[0]; + + info[0] = { + name: 'candyId', + typeName: 'number', + description: "The candy's identifier.", + }; + + checkParams(Dispenser, info); } + ); - beforeEach(() => { - info = []; - }); - - it('When a function parameter has an inline @type tag, the parameter type is documented', - () => { - const dispense = docSet.getByLongname('dispense')[0]; - - info[0] = { - name: 'candy', - typeName: 'string' - }; - - checkParams(dispense, info); - }); - - it('When a function parameter has a standard JSDoc comment and an inline @type tag, the docs ' + - 'reflect the standard JSDoc comment', () => { - const Dispenser = docSet.getByLongname('Dispenser')[0]; - - info[0] = { - name: 'candyId', - typeName: 'number', - description: 'The candy\'s identifier.' - }; - - checkParams(Dispenser, info); - }); - - it('When a function accepts multiple parameters, and only the first parameter is documented ' + - 'with an inline @type tag, the function parameters are documented in the correct order', + it( + 'When a function accepts multiple parameters, and only the first parameter is documented ' + + 'with an inline @type tag, the function parameters are documented in the correct order', () => { - const restock = docSet.getByLongname('restock')[0]; + const restock = docSet.getByLongname('restock')[0]; - info[0] = { - name: 'dispenser', - typeName: 'Dispenser' - }; - info[1] = { - name: 'item', - typeName: 'string' - }; + info[0] = { + name: 'dispenser', + typeName: 'Dispenser', + }; + info[1] = { + name: 'item', + typeName: 'string', + }; - checkParams(restock, info); - }); + checkParams(restock, info); + } + ); - it('When a function accepts multiple parameters, and only the last parameter is documented ' + - 'with an inline @type tag, the function parameters are documented in the correct order', + it( + 'When a function accepts multiple parameters, and only the last parameter is documented ' + + 'with an inline @type tag, the function parameters are documented in the correct order', () => { - const clean = docSet.getByLongname('clean')[0]; + const clean = docSet.getByLongname('clean')[0]; - info[0] = { - name: 'dispenser', - typeName: 'Dispenser' - }; - info[1] = { - name: 'cleaner', - typeName: 'string' - }; + info[0] = { + name: 'dispenser', + typeName: 'Dispenser', + }; + info[1] = { + name: 'cleaner', + typeName: 'string', + }; - checkParams(clean, info); - }); + checkParams(clean, info); + } + ); - it('When a function accepts multiple parameters, and a parameter in the middle is documented ' + - 'with an inline @type tag, the function parameters are documented in the correct order', + it( + 'When a function accepts multiple parameters, and a parameter in the middle is documented ' + + 'with an inline @type tag, the function parameters are documented in the correct order', () => { - const paint = docSet.getByLongname('paint')[0]; + const paint = docSet.getByLongname('paint')[0]; - info[0] = { - name: 'dispenser', - typeName: 'Dispenser' - }; - info[1] = { - name: 'color', - typeName: 'Color' - }; - info[2] = { - name: 'shade', - typeName: 'number' - }; - info[3] = { - name: 'brand', - typeName: 'string' - }; + info[0] = { + name: 'dispenser', + typeName: 'Dispenser', + }; + info[1] = { + name: 'color', + typeName: 'Color', + }; + info[2] = { + name: 'shade', + typeName: 'number', + }; + info[3] = { + name: 'brand', + typeName: 'string', + }; - checkParams(paint, info); - }); + checkParams(paint, info); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/typetagwithnewline.js b/packages/jsdoc/test/specs/documentation/typetagwithnewline.js index 45c16ad1..39583b30 100644 --- a/packages/jsdoc/test/specs/documentation/typetagwithnewline.js +++ b/packages/jsdoc/test/specs/documentation/typetagwithnewline.js @@ -1,26 +1,29 @@ describe('@type tag containing a newline character', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typetagwithnewline.js'); - const mini = docSet.getByLongname('Matryoshka.mini')[0]; - const mega = docSet.getByLongname('Matryoshka.mega')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typetagwithnewline.js'); + const mini = docSet.getByLongname('Matryoshka.mini')[0]; + const mega = docSet.getByLongname('Matryoshka.mega')[0]; - it('When the type expression for a @type tag contains a newline character and is not ' + - 'enclosed in braces, the type expression is parsed correctly.', () => { - expect(mini).toBeObject(); - expect(mini.type).toBeObject(); - expect(mini.type.names).toEqual([ - '!Array.', - '!Array.>' - ]); - }); + it( + 'When the type expression for a @type tag contains a newline character and is not ' + + 'enclosed in braces, the type expression is parsed correctly.', + () => { + expect(mini).toBeObject(); + expect(mini.type).toBeObject(); + expect(mini.type.names).toEqual(['!Array.', '!Array.>']); + } + ); - it('When the type expression for a @type tag contains a newline character and is enclosed ' + - 'in braces, the type expression is parsed correctly.', () => { - expect(mega).toBeObject(); - expect(mega.type).toBeObject(); - expect(mega.type.names).toEqual([ - '!Array.', - '!Array.>', - '!Array.>>' - ]); - }); + it( + 'When the type expression for a @type tag contains a newline character and is enclosed ' + + 'in braces, the type expression is parsed correctly.', + () => { + expect(mega).toBeObject(); + expect(mega.type).toBeObject(); + expect(mega.type.names).toEqual([ + '!Array.', + '!Array.>', + '!Array.>>', + ]); + } + ); }); diff --git a/packages/jsdoc/test/specs/documentation/var.js b/packages/jsdoc/test/specs/documentation/var.js index ffb17e85..5057424f 100644 --- a/packages/jsdoc/test/specs/documentation/var.js +++ b/packages/jsdoc/test/specs/documentation/var.js @@ -1,54 +1,54 @@ describe('var statements', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/var.js'); - const GREEN = docSet.getByLongname('GREEN')[0]; - const RED = docSet.getByLongname('RED')[0]; - const results = docSet.getByLongname('results')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/var.js'); + const GREEN = docSet.getByLongname('GREEN')[0]; + const RED = docSet.getByLongname('RED')[0]; + const results = docSet.getByLongname('results')[0]; - describe('when a series of constants is documented', () => { - it('should find the first constant', () => { - expect(GREEN).toBeObject(); - }); - - it('should attach the docs to the first constant', () => { - expect(GREEN.comment).toBe('/** document me */'); - }); - - it('should have the correct name', () => { - expect(GREEN.name).toBe('GREEN'); - }); - - it('should have the correct memberof', () => { - expect(GREEN.memberof).toBeUndefined(); - }); - - it('should give the constant a global scope', () => { - expect(GREEN.scope).toBe('global'); - }); - - it('should find the second constant', () => { - expect(RED).toBeObject(); - }); - - it('should not attach the docs to the second constant', () => { - expect(RED.undocumented).toBeTrue(); - }); + describe('when a series of constants is documented', () => { + it('should find the first constant', () => { + expect(GREEN).toBeObject(); }); - describe('when a member of a series of vars is documented', () => { - it('should attach the docs to the correct var', () => { - expect(results.comment).toBe('/** document me */'); - }); - - it('should have the correct name', () => { - expect(results.name).toBe('results'); - }); - - it('should leave memberof undefined', () => { - expect(results.memberof).toBeUndefined(); - }); - - it('should give the var a global scope', () => { - expect(results.scope).toBe('global'); - }); + it('should attach the docs to the first constant', () => { + expect(GREEN.comment).toBe('/** document me */'); }); + + it('should have the correct name', () => { + expect(GREEN.name).toBe('GREEN'); + }); + + it('should have the correct memberof', () => { + expect(GREEN.memberof).toBeUndefined(); + }); + + it('should give the constant a global scope', () => { + expect(GREEN.scope).toBe('global'); + }); + + it('should find the second constant', () => { + expect(RED).toBeObject(); + }); + + it('should not attach the docs to the second constant', () => { + expect(RED.undocumented).toBeTrue(); + }); + }); + + describe('when a member of a series of vars is documented', () => { + it('should attach the docs to the correct var', () => { + expect(results.comment).toBe('/** document me */'); + }); + + it('should have the correct name', () => { + expect(results.name).toBe('results'); + }); + + it('should leave memberof undefined', () => { + expect(results.memberof).toBeUndefined(); + }); + + it('should give the var a global scope', () => { + expect(results.scope).toBe('global'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/variations.js b/packages/jsdoc/test/specs/documentation/variations.js index 10939796..9a651350 100644 --- a/packages/jsdoc/test/specs/documentation/variations.js +++ b/packages/jsdoc/test/specs/documentation/variations.js @@ -1,20 +1,20 @@ describe('variations by name', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/variations.js'); - const fadein1 = docSet.getByLongname('anim.fadein(1)')[0]; - const fadein2 = docSet.getByLongname('anim.fadein(2)')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/variations.js'); + const fadein1 = docSet.getByLongname('anim.fadein(1)')[0]; + const fadein2 = docSet.getByLongname('anim.fadein(2)')[0]; - it('When a symbol has a name with a variation, the doclet has a variation property.', () => { - expect(fadein1.variation).toBe('1'); - expect(fadein2.variation).toBe('2'); - }); + it('When a symbol has a name with a variation, the doclet has a variation property.', () => { + expect(fadein1.variation).toBe('1'); + expect(fadein2.variation).toBe('2'); + }); - it('When a symbol has a name with a variation in the name, the doclet name has no variation in it.', () => { - expect(fadein1.name).toBe('fadein'); - expect(fadein2.name).toBe('fadein'); - }); + it('When a symbol has a name with a variation in the name, the doclet name has no variation in it.', () => { + expect(fadein1.name).toBe('fadein'); + expect(fadein2.name).toBe('fadein'); + }); - it('When a symbol has a name with a variation in the name, the doclet longname has the variation in it.', () => { - expect(fadein1.longname).toBe('anim.fadein(1)'); - expect(fadein2.longname).toBe('anim.fadein(2)'); - }); + it('When a symbol has a name with a variation in the name, the doclet longname has the variation in it.', () => { + expect(fadein1.longname).toBe('anim.fadein(1)'); + expect(fadein2.longname).toBe('anim.fadein(2)'); + }); }); diff --git a/packages/jsdoc/test/specs/documentation/virtual.js b/packages/jsdoc/test/specs/documentation/virtual.js index 7092c1e3..254590a0 100644 --- a/packages/jsdoc/test/specs/documentation/virtual.js +++ b/packages/jsdoc/test/specs/documentation/virtual.js @@ -1,49 +1,49 @@ describe('virtual symbols', () => { - describe('simple cases', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/virtual.js'); - const dimensions = docSet.getByLongname('dimensions'); - const width = docSet.getByLongname('width'); + describe('simple cases', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/virtual.js'); + const dimensions = docSet.getByLongname('dimensions'); + const width = docSet.getByLongname('width'); - it('should document virtual symbols', () => { - expect(dimensions).toBeArrayOfSize(1); - }); - - it('should document an undocumented symbol found after a comment for a virtual symbol', () => { - expect(width).toBeArrayOfSize(1); - }); + it('should document virtual symbols', () => { + expect(dimensions).toBeArrayOfSize(1); }); - describe('complex cases', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/virtual2.js'); - const say = docSet.getByLongname('Person#say')[0]; - const sayCallback = docSet.getByLongname('Person~sayCallback')[0]; + it('should document an undocumented symbol found after a comment for a virtual symbol', () => { + expect(width).toBeArrayOfSize(1); + }); + }); - it('should document virtual symbols inside an object literal', () => { - expect(sayCallback).toBeObject(); - expect(sayCallback.undocumented).toBeUndefined(); - }); + describe('complex cases', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/virtual2.js'); + const say = docSet.getByLongname('Person#say')[0]; + const sayCallback = docSet.getByLongname('Person~sayCallback')[0]; - it('should attach the comment to a documented symbol that follows a virtual symbol', () => { - expect(say).toBeObject(); - expect(say.undocumented).toBeUndefined(); - }); + it('should document virtual symbols inside an object literal', () => { + expect(sayCallback).toBeObject(); + expect(sayCallback.undocumented).toBeUndefined(); }); - describe('overloaded virtual symbols', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/virtual3.js'); - const constructors = docSet.getByLongname('module:connection'); - - it('should create multiple doclets for overloaded virtual symbols', () => { - expect(constructors).toBeArrayOfSize(2); - }); - - it('should use the correct signature for each virtual symbol', () => { - expect(constructors[0]).toBeObject(); - expect(constructors[0].params).toBeArray(); - expect(constructors[0].params[0].name).toBe('name'); - - expect(constructors[1]).toBeObject(); - expect(constructors[1].params).toBeUndefined(); - }); + it('should attach the comment to a documented symbol that follows a virtual symbol', () => { + expect(say).toBeObject(); + expect(say.undocumented).toBeUndefined(); }); + }); + + describe('overloaded virtual symbols', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/virtual3.js'); + const constructors = docSet.getByLongname('module:connection'); + + it('should create multiple doclets for overloaded virtual symbols', () => { + expect(constructors).toBeArrayOfSize(2); + }); + + it('should use the correct signature for each virtual symbol', () => { + expect(constructors[0]).toBeObject(); + expect(constructors[0].params).toBeArray(); + expect(constructors[0].params[0].name).toBe('name'); + + expect(constructors[1]).toBeObject(); + expect(constructors[1].params).toBeUndefined(); + }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/augment.js b/packages/jsdoc/test/specs/jsdoc/augment.js index 12e5727e..43510995 100644 --- a/packages/jsdoc/test/specs/jsdoc/augment.js +++ b/packages/jsdoc/test/specs/jsdoc/augment.js @@ -1,78 +1,78 @@ describe('jsdoc/augment', () => { - // TODO: more tests + // TODO: more tests - const augment = require('jsdoc/augment'); + const augment = require('jsdoc/augment'); - it('should exist', () => { - expect(augment).toBeObject(); + it('should exist', () => { + expect(augment).toBeObject(); + }); + + it('should have an "addImplemented" method', () => { + expect(augment.addImplemented).toBeFunction(); + }); + + it('should have an "addInherited" method', () => { + expect(augment.addInherited).toBeFunction(); + }); + + it('should have an "addMixedIn" method', () => { + expect(augment.addMixedIn).toBeFunction(); + }); + + it('should have an "augmentAll" method', () => { + expect(augment.augmentAll).toBeFunction(); + }); + + xdescribe('addImplemented', () => { + // TODO: add some basic tests (functionality is tested via @interface and @implements tags) + }); + + xdescribe('addInherited', () => { + // TODO: add some basic tests (functionality is tested via @augments tag) + }); + + xdescribe('addMixedIn', () => { + // TODO: add some basic tests (functionality is tested via documentation/mixes spec) + }); + + describe('augmentAll', () => { + it('should call all other methods that the module exports', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag2.js', null, null, false); + const methodNames = Object.keys(augment).filter((name) => name !== 'augmentAll'); + + methodNames.forEach((name) => { + spyOn(augment, name); + }); + + augment.augmentAll(docSet.doclets); + + methodNames.forEach((name) => { + expect(augment[name]).toHaveBeenCalled(); + }); }); - it('should have an "addImplemented" method', () => { - expect(augment.addImplemented).toBeFunction(); + it('should work when a class extends another class that implements an interface', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/augmentall.js', null, null, false); + let open; + + augment.augmentAll(docSet.doclets); + + open = docSet.getByLongname('EncryptedSocket#open').filter(({ ignore }) => !ignore); + + expect(open).toBeArrayOfSize(1); + expect(open[0].description).toBe('Open the connection.'); }); - it('should have an "addInherited" method', () => { - expect(augment.addInherited).toBeFunction(); - }); - - it('should have an "addMixedIn" method', () => { - expect(augment.addMixedIn).toBeFunction(); - }); - - it('should have an "augmentAll" method', () => { - expect(augment.augmentAll).toBeFunction(); - }); - - xdescribe('addImplemented', () => { - // TODO: add some basic tests (functionality is tested via @interface and @implements tags) - }); - - xdescribe('addInherited', () => { - // TODO: add some basic tests (functionality is tested via @augments tag) - }); - - xdescribe('addMixedIn', () => { - // TODO: add some basic tests (functionality is tested via documentation/mixes spec) - }); - - describe('augmentAll', () => { - it('should call all other methods that the module exports', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag2.js', null, null, false); - const methodNames = Object.keys(augment).filter(name => name !== 'augmentAll'); - - methodNames.forEach(name => { - spyOn(augment, name); - }); - - augment.augmentAll(docSet.doclets); - - methodNames.forEach(name => { - expect(augment[name]).toHaveBeenCalled(); - }); - }); - - it('should work when a class extends another class that implements an interface', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/augmentall.js', null, null, false); - let open; - - augment.augmentAll(docSet.doclets); - - open = docSet.getByLongname('EncryptedSocket#open').filter(({ignore}) => !ignore); - - expect(open).toBeArrayOfSize(1); - expect(open[0].description).toBe('Open the connection.'); - }); - - it('should work when a class implements an interface that extends another interface', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/augmentall2.js', null, null, false); - let open; - - augment.augmentAll(docSet.doclets); - - open = docSet.getByLongname('EncryptedSocket#open').filter(({ignore}) => !ignore); - - expect(open).toBeArrayOfSize(1); - expect(open[0].description).toBe('Open the connection.'); - }); + it('should work when a class implements an interface that extends another interface', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/augmentall2.js', null, null, false); + let open; + + augment.augmentAll(docSet.doclets); + + open = docSet.getByLongname('EncryptedSocket#open').filter(({ ignore }) => !ignore); + + expect(open).toBeArrayOfSize(1); + expect(open[0].description).toBe('Open the connection.'); }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/borrow.js b/packages/jsdoc/test/specs/jsdoc/borrow.js index a206cba6..521e9ad5 100644 --- a/packages/jsdoc/test/specs/jsdoc/borrow.js +++ b/packages/jsdoc/test/specs/jsdoc/borrow.js @@ -1,3 +1,3 @@ xdescribe('jsdoc/borrow', () => { - // TODO + // TODO }); diff --git a/packages/jsdoc/test/specs/jsdoc/doclet.js b/packages/jsdoc/test/specs/jsdoc/doclet.js index 75bcc727..0e573da1 100644 --- a/packages/jsdoc/test/specs/jsdoc/doclet.js +++ b/packages/jsdoc/test/specs/jsdoc/doclet.js @@ -1,304 +1,297 @@ describe('jsdoc/doclet', () => { - // TODO: more tests - const _ = require('lodash'); - const doclet = require('jsdoc/doclet'); - const Doclet = doclet.Doclet; - const { SCOPE } = require('@jsdoc/core').name; + // TODO: more tests + const _ = require('lodash'); + const doclet = require('jsdoc/doclet'); + const Doclet = doclet.Doclet; + const { SCOPE } = require('@jsdoc/core').name; - it('exists', () => { - expect(doclet).toBeObject(); + it('exists', () => { + expect(doclet).toBeObject(); + }); + + it('has a combine method', () => { + expect(doclet.combine).toBeFunction(); + }); + + it('has a Doclet class', () => { + expect(doclet.Doclet).toBeFunction(); + }); + + describe('Doclet', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/doclet.js'); + const testDoclet = docSet.getByLongname('test2')[0]; + + it('does not mangle Markdown in a description that uses leading asterisks', () => { + expect(testDoclet.description.includes('* List item 1')).toBeTrue(); + expect(testDoclet.description.includes('**Strong** is strong')).toBeTrue(); }); - it('has a combine method', () => { - expect(doclet.combine).toBeFunction(); + it('adds the AST node as a non-enumerable property', () => { + const descriptor = Object.getOwnPropertyDescriptor(testDoclet.meta.code, 'node'); + + expect(descriptor.enumerable).toBeFalse(); }); - it('has a Doclet class', () => { - expect(doclet.Doclet).toBeFunction(); + // TODO(hegemonic): more tests (namespaces, modules, etc.) + describe('name resolution', () => { + // TODO(hegemonic): Load fixtures instead of creating doclets manually + function makeDoclet(tagStrings) { + const comment = `/**\n${tagStrings.join('\n')}\n*/`; + + return new Doclet(comment, {}); + } + + describe('aliases', () => { + // TODO(hegemonic): This comment implies that we _don't_ need to set doclet.name... + // If `doclet.alias` is defined, `doclet.name` will be set to the same value by the + // time the test runs. Therefore, we set both `@alias` and `@name` in these tests. + it('can resolve aliases that identify instance members', () => { + const newDoclet = makeDoclet(['@alias Foo#bar', '@name Foo#bar']); + + expect(newDoclet.name).toBe('bar'); + expect(newDoclet.memberof).toBe('Foo'); + expect(newDoclet.scope).toBe('instance'); + expect(newDoclet.longname).toBe('Foo#bar'); + }); + + it('can resolve aliases that identify static members', () => { + const newDoclet = makeDoclet(['@alias Foo.bar', '@name Foo.bar']); + + expect(newDoclet.name).toBe('bar'); + expect(newDoclet.memberof).toBe('Foo'); + expect(newDoclet.scope).toBe('static'); + expect(newDoclet.longname).toBe('Foo.bar'); + }); + + it('works when the alias only specifies the short name', () => { + const newDoclet = makeDoclet(['@alias bar', '@name bar', '@memberof Foo', '@instance']); + + expect(newDoclet.name).toBe('bar'); + expect(newDoclet.memberof).toBe('Foo'); + expect(newDoclet.scope).toBe('instance'); + expect(newDoclet.longname).toBe('Foo#bar'); + }); + }); + + describe('events', () => { + const event = '@event'; + const memberOf = '@memberof MyClass'; + const eventName = '@name A'; + + // Test the basic @event that is not nested. + it('unnested @event gets resolved correctly', () => { + const newDoclet = makeDoclet([event, eventName]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBeUndefined(); + expect(newDoclet.longname).toBe('event:A'); + }); + + // test all permutations of @event @name [name] @memberof. + it('@event @name @memberof resolves correctly', () => { + const newDoclet = makeDoclet([event, eventName, memberOf]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + it('@event @memberof @name resolves correctly', () => { + const newDoclet = makeDoclet([event, memberOf, eventName]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + it('@name @event @memberof resolves correctly', () => { + const newDoclet = makeDoclet([eventName, event, memberOf]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + it('@name @memberof @event resolves correctly', () => { + const newDoclet = makeDoclet([eventName, memberOf, event]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + it('@memberof @event @name resolves correctly', () => { + const newDoclet = makeDoclet([memberOf, event, eventName]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + it('@memberof @name @event resolves correctly', () => { + const newDoclet = makeDoclet([memberOf, eventName, event]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + // test all permutations of @event [name] @memberof + it('@event [name] @memberof resolves correctly', () => { + const newDoclet = makeDoclet(['@event A', memberOf]); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + it('@memberof @event [name] resolves correctly', () => { + const newDoclet = makeDoclet([memberOf, '@event A']); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + // test full @event A.B + it('full @event definition works', () => { + const newDoclet = makeDoclet(['@event MyClass.A']); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + it('full @event definition with event: works', () => { + const newDoclet = makeDoclet(['@event MyClass.event:A']); + + expect(newDoclet.name).toBe('event:A'); + expect(newDoclet.memberof).toBe('MyClass'); + expect(newDoclet.longname).toBe('MyClass.event:A'); + }); + + // TODO(hegemonic): This only works if you resolve the names twice. As it happens, + // JSDoc does that, because it calls `Doclet#postProcess` twice, so this works in + // practice. But you shouldn't have to resolve the names twice... + xit('@event @name MyClass.EventName @memberof somethingelse works', () => { + const newDoclet = makeDoclet([event, '@name MyClass.A', '@memberof MyNamespace']); + + expect(newDoclet.name).toBe('A'); + expect(newDoclet.memberof).toBe('MyNamespace.MyClass'); + expect(newDoclet.longname).toBe('MyNamespace.MyClass.event:A'); + }); + }); + + describe('module members', () => { + // TODO(hegemonic): This only works if you resolve the names twice. As it happens, + // JSDoc does that, because it calls `Doclet#postProcess` twice, so this works in + // practice. But you shouldn't have to resolve the names twice... + xit('@name @function @memberof works', () => { + const newDoclet = makeDoclet([ + '@name Bar.prototype.baz', + '@function', + '@memberof module:foo', + '@param {string} qux', + ]); + + expect(newDoclet.name).toBe('baz'); + expect(newDoclet.memberof).toBe('module:foo.Bar'); + expect(newDoclet.longname).toBe('module:foo.Bar#baz'); + }); + }); + }); + }); + + describe('setScope', () => { + it('should accept the correct scope names', () => { + function setScope(scopeName) { + const newDoclet = new Doclet('/** Huzzah, a doclet! */'); + + newDoclet.setScope(scopeName); + } + + _.values(SCOPE.NAMES).forEach((scopeName) => { + expect(setScope.bind(null, scopeName)).not.toThrow(); + }); }); - describe('Doclet', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/doclet.js'); - const testDoclet = docSet.getByLongname('test2')[0]; + it('should throw an error for invalid scope names', () => { + function setScope() { + const newDoclet = new Doclet('/** Woe betide this doclet. */'); - it('does not mangle Markdown in a description that uses leading asterisks', () => { - expect(testDoclet.description.includes('* List item 1')).toBeTrue(); - expect(testDoclet.description.includes('**Strong** is strong')).toBeTrue(); - }); + newDoclet.setScope('fiddlesticks'); + } - it('adds the AST node as a non-enumerable property', () => { - const descriptor = Object.getOwnPropertyDescriptor(testDoclet.meta.code, 'node'); + expect(setScope).toThrow(); + }); + }); - expect(descriptor.enumerable).toBeFalse(); - }); + describe('combine', () => { + it('should override most properties of the secondary doclet', () => { + const primaryDoclet = new Doclet('/** New and improved!\n@version 2.0.0 */'); + const secondaryDoclet = new Doclet('/** Hello!\n@version 1.0.0 */'); + const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); - // TODO(hegemonic): more tests (namespaces, modules, etc.) - describe('name resolution', () => { - // TODO(hegemonic): Load fixtures instead of creating doclets manually - function makeDoclet(tagStrings) { - const comment = `/**\n${tagStrings.join('\n')}\n*/`; - - return new Doclet(comment, {}); - } - - describe('aliases', () => { - // TODO(hegemonic): This comment implies that we _don't_ need to set doclet.name... - // If `doclet.alias` is defined, `doclet.name` will be set to the same value by the - // time the test runs. Therefore, we set both `@alias` and `@name` in these tests. - it('can resolve aliases that identify instance members', () => { - const newDoclet = makeDoclet(['@alias Foo#bar', '@name Foo#bar']); - - expect(newDoclet.name).toBe('bar'); - expect(newDoclet.memberof).toBe('Foo'); - expect(newDoclet.scope).toBe('instance'); - expect(newDoclet.longname).toBe('Foo#bar'); - }); - - it('can resolve aliases that identify static members', () => { - const newDoclet = makeDoclet(['@alias Foo.bar', '@name Foo.bar']); - - expect(newDoclet.name).toBe('bar'); - expect(newDoclet.memberof).toBe('Foo'); - expect(newDoclet.scope).toBe('static'); - expect(newDoclet.longname).toBe('Foo.bar'); - }); - - it('works when the alias only specifies the short name', () => { - const newDoclet = makeDoclet([ - '@alias bar', - '@name bar', - '@memberof Foo', - '@instance' - ]); - - expect(newDoclet.name).toBe('bar'); - expect(newDoclet.memberof).toBe('Foo'); - expect(newDoclet.scope).toBe('instance'); - expect(newDoclet.longname).toBe('Foo#bar'); - }); - }); - - describe('events', () => { - const event = '@event'; - const memberOf = '@memberof MyClass'; - const eventName = '@name A'; - - // Test the basic @event that is not nested. - it('unnested @event gets resolved correctly', () => { - const newDoclet = makeDoclet([event, eventName]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBeUndefined(); - expect(newDoclet.longname).toBe('event:A'); - }); - - // test all permutations of @event @name [name] @memberof. - it('@event @name @memberof resolves correctly', () => { - const newDoclet = makeDoclet([event, eventName, memberOf]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - it('@event @memberof @name resolves correctly', () => { - const newDoclet = makeDoclet([event, memberOf, eventName]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - it('@name @event @memberof resolves correctly', () => { - const newDoclet = makeDoclet([eventName, event, memberOf]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - it('@name @memberof @event resolves correctly', () => { - const newDoclet = makeDoclet([eventName, memberOf, event]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - it('@memberof @event @name resolves correctly', () => { - const newDoclet = makeDoclet([memberOf, event, eventName]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - it('@memberof @name @event resolves correctly', () => { - const newDoclet = makeDoclet([memberOf, eventName, event]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - // test all permutations of @event [name] @memberof - it('@event [name] @memberof resolves correctly', () => { - const newDoclet = makeDoclet(['@event A', memberOf]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - it('@memberof @event [name] resolves correctly', () => { - const newDoclet = makeDoclet([memberOf, '@event A']); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - // test full @event A.B - it('full @event definition works', () => { - const newDoclet = makeDoclet(['@event MyClass.A']); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - it('full @event definition with event: works', () => { - const newDoclet = makeDoclet(['@event MyClass.event:A']); - - expect(newDoclet.name).toBe('event:A'); - expect(newDoclet.memberof).toBe('MyClass'); - expect(newDoclet.longname).toBe('MyClass.event:A'); - }); - - // TODO(hegemonic): This only works if you resolve the names twice. As it happens, - // JSDoc does that, because it calls `Doclet#postProcess` twice, so this works in - // practice. But you shouldn't have to resolve the names twice... - xit('@event @name MyClass.EventName @memberof somethingelse works', () => { - const newDoclet = makeDoclet([ - event, - '@name MyClass.A', - '@memberof MyNamespace' - ]); - - expect(newDoclet.name).toBe('A'); - expect(newDoclet.memberof).toBe('MyNamespace.MyClass'); - expect(newDoclet.longname).toBe('MyNamespace.MyClass.event:A'); - }); - }); - - describe('module members', () => { - // TODO(hegemonic): This only works if you resolve the names twice. As it happens, - // JSDoc does that, because it calls `Doclet#postProcess` twice, so this works in - // practice. But you shouldn't have to resolve the names twice... - xit('@name @function @memberof works', () => { - const newDoclet = makeDoclet([ - '@name Bar.prototype.baz', - '@function', - '@memberof module:foo', - '@param {string} qux' - ]); - - expect(newDoclet.name).toBe('baz'); - expect(newDoclet.memberof).toBe('module:foo.Bar'); - expect(newDoclet.longname).toBe('module:foo.Bar#baz'); - }); - }); - }); + Object.getOwnPropertyNames(newDoclet).forEach((property) => { + expect(newDoclet[property]).toEqual(primaryDoclet[property]); + }); }); - describe('setScope', () => { - it('should accept the correct scope names', () => { - function setScope(scopeName) { - const newDoclet = new Doclet('/** Huzzah, a doclet! */'); + it('should add properties that are missing from the secondary doclet', () => { + const primaryDoclet = new Doclet('/** Hello!\n@version 2.0.0 */'); + const secondaryDoclet = new Doclet('/** Hello! */'); + const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); - newDoclet.setScope(scopeName); - } - - _.values(SCOPE.NAMES).forEach(scopeName => { - expect(setScope.bind(null, scopeName)).not.toThrow(); - }); - }); - - it('should throw an error for invalid scope names', () => { - function setScope() { - const newDoclet = new Doclet('/** Woe betide this doclet. */'); - - newDoclet.setScope('fiddlesticks'); - } - - expect(setScope).toThrow(); - }); + expect(newDoclet.version).toBe('2.0.0'); }); - describe('combine', () => { - it('should override most properties of the secondary doclet', () => { - const primaryDoclet = new Doclet('/** New and improved!\n@version 2.0.0 */'); - const secondaryDoclet = new Doclet('/** Hello!\n@version 1.0.0 */'); - const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); + describe('params and properties', () => { + const properties = ['params', 'properties']; - Object.getOwnPropertyNames(newDoclet).forEach(property => { - expect(newDoclet[property]).toEqual(primaryDoclet[property]); - }); - }); + it( + "should use the secondary doclet's params and properties if the primary doclet " + + 'had none', + () => { + const primaryDoclet = new Doclet('/** Hello! */'); + const secondaryComment = [ + '/**', + ' * @param {string} foo - The foo.', + ' * @property {number} bar - The bar.', + ' */', + ].join('\n'); + const secondaryDoclet = new Doclet(secondaryComment); + const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); - it('should add properties that are missing from the secondary doclet', () => { - const primaryDoclet = new Doclet('/** Hello!\n@version 2.0.0 */'); - const secondaryDoclet = new Doclet('/** Hello! */'); - const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); + properties.forEach((property) => { + expect(newDoclet[property]).toEqual(secondaryDoclet[property]); + }); + } + ); - expect(newDoclet.version).toBe('2.0.0'); - }); + it( + "should use the primary doclet's params and properties if the primary doclet has " + 'some', + () => { + const primaryComment = [ + '/**', + ' * @param {number} baz - The baz.', + ' * @property {string} qux - The qux.', + ' */', + ].join('\n'); + const primaryDoclet = new Doclet(primaryComment); + const secondaryComment = [ + '/**', + ' * @param {string} foo - The foo.', + ' * @property {number} bar - The bar.', + ' */', + ].join('\n'); + const secondaryDoclet = new Doclet(secondaryComment); + const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); - describe('params and properties', () => { - const properties = [ - 'params', - 'properties' - ]; - - it('should use the secondary doclet\'s params and properties if the primary doclet ' + - 'had none', () => { - const primaryDoclet = new Doclet('/** Hello! */'); - const secondaryComment = [ - '/**', - ' * @param {string} foo - The foo.', - ' * @property {number} bar - The bar.', - ' */' - ].join('\n'); - const secondaryDoclet = new Doclet(secondaryComment); - const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); - - properties.forEach(property => { - expect(newDoclet[property]).toEqual(secondaryDoclet[property]); - }); - }); - - it('should use the primary doclet\'s params and properties if the primary doclet has ' + - 'some', () => { - const primaryComment = [ - '/**', - ' * @param {number} baz - The baz.', - ' * @property {string} qux - The qux.', - ' */' - ].join('\n'); - const primaryDoclet = new Doclet(primaryComment); - const secondaryComment = [ - '/**', - ' * @param {string} foo - The foo.', - ' * @property {number} bar - The bar.', - ' */' - ].join('\n'); - const secondaryDoclet = new Doclet(secondaryComment); - const newDoclet = doclet.combine(primaryDoclet, secondaryDoclet); - - properties.forEach(property => { - expect(newDoclet[property]).toEqual(primaryDoclet[property]); - }); - }); - }); + properties.forEach((property) => { + expect(newDoclet[property]).toEqual(primaryDoclet[property]); + }); + } + ); }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/package.js b/packages/jsdoc/test/specs/jsdoc/package.js index 7c9f7b8e..19e019c3 100644 --- a/packages/jsdoc/test/specs/jsdoc/package.js +++ b/packages/jsdoc/test/specs/jsdoc/package.js @@ -1,264 +1,270 @@ const hasOwnProp = Object.prototype.hasOwnProperty; describe('jsdoc/package', () => { - let emptyPackage; - const jsdocPackage = require('jsdoc/package'); - const Package = jsdocPackage.Package; + let emptyPackage; + const jsdocPackage = require('jsdoc/package'); + const Package = jsdocPackage.Package; - function checkPackageProperty(name, value) { - let myPackage; - const obj = {}; + function checkPackageProperty(name, value) { + let myPackage; + const obj = {}; - obj[name] = value; - myPackage = new Package( JSON.stringify(obj) ); - // add the package object to the cached parse results, so we can validate it against the - // doclet schema - jsdoc.addParseResults(`package-property-${name}.js`, [myPackage]); + obj[name] = value; + myPackage = new Package(JSON.stringify(obj)); + // add the package object to the cached parse results, so we can validate it against the + // doclet schema + jsdoc.addParseResults(`package-property-${name}.js`, [myPackage]); - expect(myPackage[name]).toEqual(value); - } + expect(myPackage[name]).toEqual(value); + } - it('should exist', () => { - expect(jsdocPackage).toBeObject(); + it('should exist', () => { + expect(jsdocPackage).toBeObject(); + }); + + it('should export a "Package" constructor', () => { + expect(Package).toBeFunction(); + }); + + describe('Package', () => { + beforeEach(() => { + emptyPackage = new Package(); }); - it('should export a "Package" constructor', () => { - expect(Package).toBeFunction(); + it('should accept a JSON-format string', () => { + function newPackage() { + return new Package('{"foo": "bar"}'); + } + + expect(newPackage).not.toThrow(); }); - describe('Package', () => { - beforeEach(() => { - emptyPackage = new Package(); - }); + it('should accept a JSON-format string with a leading BOM', () => { + function newPackage() { + return new Package('\uFEFF{}'); + } - it('should accept a JSON-format string', () => { - function newPackage() { - return new Package('{"foo": "bar"}'); - } - - expect(newPackage).not.toThrow(); - }); - - it('should accept a JSON-format string with a leading BOM', () => { - function newPackage() { - return new Package('\uFEFF{}'); - } - - expect(newPackage).not.toThrow(); - }); - - it('should work when called with no arguments', () => { - function newPackage() { - return new Package(); - } - - expect(newPackage).not.toThrow(); - }); - - it('should log an error when called with bad input', () => { - function newPackage() { - return new Package('abcdefg'); - } - - expect(newPackage).not.toThrow(); - expect(jsdoc.didLog(newPackage, 'error')).toBeTrue(); - }); - - describe('author', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'author') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('author', { - name: 'Jane Smith', - email: 'jsmith@example.com' - }); - }); - }); - - describe('bugs', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'bugs') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('bugs', { url: 'http://example.com/bugs' }); - }); - }); - - describe('contributors', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'contributors') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('contributors', [{ - name: 'Jane Smith', - email: 'jsmith@example.com' - }]); - }); - }); - - describe('dependencies', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'dependencies') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('dependencies', { bar: '~1.1.0' }); - }); - }); - - describe('description', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'description') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('description', 'My package.'); - }); - }); - - describe('devDependencies', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'devDependencies') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('devDependencies', { baz: '~3.4.5' }); - }); - }); - - describe('engines', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'engines') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('engines', { node: '>=0.10.3' }); - }); - }); - - describe('files', () => { - it('should contain an empty array by default', () => { - expect(emptyPackage.files).toBeEmptyArray(); - }); - - it('should ignore the value from the package file', () => { - const myPackage = new Package('{"files": ["foo", "bar"]}'); - - expect(myPackage.files).toBeEmptyArray(); - }); - }); - - describe('homepage', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'homepage') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('homepage', 'http://example.com/'); - }); - }); - - describe('keywords', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'keywords') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('keywords', ['foo', 'bar']); - }); - }); - - describe('licenses', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'licenses') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('licenses', [{ - type: 'My Open-Source License', - url: 'http://example.com/oss' - }]); - }); - - it('should contain the value of "license" from the package file', () => { - const myPackage = new Package('{"license": "My-OSS-License"}'); - - expect(myPackage.license).toBeUndefined(); - expect(myPackage.licenses).toBeArrayOfSize(1); - expect(myPackage.licenses[0].type).toBe('My-OSS-License'); - }); - - it('should combine the "license" and "licenses" properties', () => { - const packageInfo = { - license: 'My-OSS-License', - licenses: [{ - type: 'My Open-Source License', - url: 'http://example.com/oss' - }] - }; - const myPackage = new Package( JSON.stringify(packageInfo) ); - - expect(myPackage.licenses).toBeArrayOfSize(2); - }); - }); - - describe('longname', () => { - it('should default to "package:undefined"', () => { - expect(emptyPackage.longname).toBe('package:undefined'); - }); - - it('should reflect the value of the "name" property', () => { - const myPackage = new Package('{"name": "foo"}'); - - expect(myPackage.longname).toBe('package:foo'); - }); - }); - - describe('main', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'main') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('main', 'foo'); - }); - }); - - describe('name', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'name') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('name', 'foo'); - }); - }); - - describe('repository', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'repository') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('repository', { - type: 'git', - url: 'git@example.org:foo/bar/baz.git' - }); - }); - }); - - describe('version', () => { - it('should not exist by default', () => { - expect( hasOwnProp.call(emptyPackage, 'version') ).toBeFalse(); - }); - - it('should contain the value from the package file', () => { - checkPackageProperty('version', '0.1.2'); - }); - }); + expect(newPackage).not.toThrow(); }); + + it('should work when called with no arguments', () => { + function newPackage() { + return new Package(); + } + + expect(newPackage).not.toThrow(); + }); + + it('should log an error when called with bad input', () => { + function newPackage() { + return new Package('abcdefg'); + } + + expect(newPackage).not.toThrow(); + expect(jsdoc.didLog(newPackage, 'error')).toBeTrue(); + }); + + describe('author', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'author')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('author', { + name: 'Jane Smith', + email: 'jsmith@example.com', + }); + }); + }); + + describe('bugs', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'bugs')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('bugs', { url: 'http://example.com/bugs' }); + }); + }); + + describe('contributors', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'contributors')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('contributors', [ + { + name: 'Jane Smith', + email: 'jsmith@example.com', + }, + ]); + }); + }); + + describe('dependencies', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'dependencies')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('dependencies', { bar: '~1.1.0' }); + }); + }); + + describe('description', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'description')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('description', 'My package.'); + }); + }); + + describe('devDependencies', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'devDependencies')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('devDependencies', { baz: '~3.4.5' }); + }); + }); + + describe('engines', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'engines')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('engines', { node: '>=0.10.3' }); + }); + }); + + describe('files', () => { + it('should contain an empty array by default', () => { + expect(emptyPackage.files).toBeEmptyArray(); + }); + + it('should ignore the value from the package file', () => { + const myPackage = new Package('{"files": ["foo", "bar"]}'); + + expect(myPackage.files).toBeEmptyArray(); + }); + }); + + describe('homepage', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'homepage')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('homepage', 'http://example.com/'); + }); + }); + + describe('keywords', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'keywords')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('keywords', ['foo', 'bar']); + }); + }); + + describe('licenses', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'licenses')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('licenses', [ + { + type: 'My Open-Source License', + url: 'http://example.com/oss', + }, + ]); + }); + + it('should contain the value of "license" from the package file', () => { + const myPackage = new Package('{"license": "My-OSS-License"}'); + + expect(myPackage.license).toBeUndefined(); + expect(myPackage.licenses).toBeArrayOfSize(1); + expect(myPackage.licenses[0].type).toBe('My-OSS-License'); + }); + + it('should combine the "license" and "licenses" properties', () => { + const packageInfo = { + license: 'My-OSS-License', + licenses: [ + { + type: 'My Open-Source License', + url: 'http://example.com/oss', + }, + ], + }; + const myPackage = new Package(JSON.stringify(packageInfo)); + + expect(myPackage.licenses).toBeArrayOfSize(2); + }); + }); + + describe('longname', () => { + it('should default to "package:undefined"', () => { + expect(emptyPackage.longname).toBe('package:undefined'); + }); + + it('should reflect the value of the "name" property', () => { + const myPackage = new Package('{"name": "foo"}'); + + expect(myPackage.longname).toBe('package:foo'); + }); + }); + + describe('main', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'main')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('main', 'foo'); + }); + }); + + describe('name', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'name')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('name', 'foo'); + }); + }); + + describe('repository', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'repository')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('repository', { + type: 'git', + url: 'git@example.org:foo/bar/baz.git', + }); + }); + }); + + describe('version', () => { + it('should not exist by default', () => { + expect(hasOwnProp.call(emptyPackage, 'version')).toBeFalse(); + }); + + it('should contain the value from the package file', () => { + checkPackageProperty('version', '0.1.2'); + }); + }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/plugins.js b/packages/jsdoc/test/specs/jsdoc/plugins.js index 4df906fb..89b711a0 100644 --- a/packages/jsdoc/test/specs/jsdoc/plugins.js +++ b/packages/jsdoc/test/specs/jsdoc/plugins.js @@ -1,15 +1,15 @@ describe('jsdoc/plugins', () => { - const plugins = require('jsdoc/plugins'); + const plugins = require('jsdoc/plugins'); - it('should exist', () => { - expect(plugins).toBeObject(); - }); + it('should exist', () => { + expect(plugins).toBeObject(); + }); - it('should export an "installPlugins" function', () => { - expect(plugins.installPlugins).toBeFunction(); - }); + it('should export an "installPlugins" function', () => { + expect(plugins.installPlugins).toBeFunction(); + }); - xdescribe('installPlugins', () => { - // TODO - }); + xdescribe('installPlugins', () => { + // TODO + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/schema.js b/packages/jsdoc/test/specs/jsdoc/schema.js index 52f01f9c..112b1647 100644 --- a/packages/jsdoc/test/specs/jsdoc/schema.js +++ b/packages/jsdoc/test/specs/jsdoc/schema.js @@ -1,79 +1,78 @@ describe('jsdoc/schema', () => { - const schema = require('jsdoc/schema'); + const schema = require('jsdoc/schema'); - it('should exist', () => { - expect(schema).toBeObject(); + it('should exist', () => { + expect(schema).toBeObject(); + }); + + it('should export a "BUGS_SCHEMA" object', () => { + expect(schema.BUGS_SCHEMA).toBeObject(); + }); + + it('should export a "CONTACT_INFO_SCHEMA" object', () => { + expect(schema.CONTACT_INFO_SCHEMA).toBeObject(); + }); + + it('should export a "DOCLET_SCHEMA" object', () => { + expect(schema.DOCLET_SCHEMA).toBeObject(); + }); + + it('should export a "DOCLETS_SCHEMA" object', () => { + expect(schema.DOCLETS_SCHEMA).toBeObject(); + }); + + it('should export an "ENUM_PROPERTY_SCHEMA" object', () => { + expect(schema.ENUM_PROPERTY_SCHEMA).toBeObject(); + }); + + it('should export a "META_SCHEMA" object', () => { + expect(schema.META_SCHEMA).toBeObject(); + }); + + it('should export a "PACKAGE_SCHEMA" object', () => { + expect(schema.PACKAGE_SCHEMA).toBeObject(); + }); + + it('should export a "PARAM_SCHEMA" object', () => { + expect(schema.PARAM_SCHEMA).toBeObject(); + }); + + it('should export a "TYPE_PROPERTY_SCHEMA" object', () => { + expect(schema.TYPE_PROPERTY_SCHEMA).toBeObject(); + }); + + describe('validation', () => { + const Ajv = require('ajv'); + + const ajv = new Ajv({ + allErrors: true, + ownProperties: true, + }); + const validate = ajv.compile(schema.DOCLETS_SCHEMA); + + it('should find validation errors in bogus input', () => { + const doclets = [ + { + foo: 'bar', + }, + ]; + const isValid = validate(doclets); + + expect(isValid).toBeFalse(); }); - it('should export a "BUGS_SCHEMA" object', () => { - expect(schema.BUGS_SCHEMA).toBeObject(); - }); - - it('should export a "CONTACT_INFO_SCHEMA" object', () => { - expect(schema.CONTACT_INFO_SCHEMA).toBeObject(); - }); - - it('should export a "DOCLET_SCHEMA" object', () => { - expect(schema.DOCLET_SCHEMA).toBeObject(); - }); - - it('should export a "DOCLETS_SCHEMA" object', () => { - expect(schema.DOCLETS_SCHEMA).toBeObject(); - }); - - it('should export an "ENUM_PROPERTY_SCHEMA" object', () => { - expect(schema.ENUM_PROPERTY_SCHEMA).toBeObject(); - }); - - it('should export a "META_SCHEMA" object', () => { - expect(schema.META_SCHEMA).toBeObject(); - }); - - it('should export a "PACKAGE_SCHEMA" object', () => { - expect(schema.PACKAGE_SCHEMA).toBeObject(); - }); - - it('should export a "PARAM_SCHEMA" object', () => { - expect(schema.PARAM_SCHEMA).toBeObject(); - }); - - it('should export a "TYPE_PROPERTY_SCHEMA" object', () => { - expect(schema.TYPE_PROPERTY_SCHEMA).toBeObject(); - }); - - describe('validation', () => { - const Ajv = require('ajv'); - - const ajv = new Ajv({ - allErrors: true, - ownProperties: true - }); - const validate = ajv.compile(schema.DOCLETS_SCHEMA); - - it('should find validation errors in bogus input', () => { - const doclets = [ - { - foo: 'bar' - } - ]; - const isValid = validate(doclets); - - expect(isValid).toBeFalse(); - }); - - it('should not find any validation errors in the JSDoc parse results', () => { - jsdoc.getParseResults().forEach(doclets => { - const isValid = validate(doclets.doclets); - - // hack to get the filename/errors in the test results - if (!isValid) { - expect(doclets.filename).toBe(''); - expect(validate.errors).toBeEmptyArray(); - } - else { - expect(validate.errors).toBeNull(); - } - }); - }); + it('should not find any validation errors in the JSDoc parse results', () => { + jsdoc.getParseResults().forEach((doclets) => { + const isValid = validate(doclets.doclets); + + // hack to get the filename/errors in the test results + if (!isValid) { + expect(doclets.filename).toBe(''); + expect(validate.errors).toBeEmptyArray(); + } else { + expect(validate.errors).toBeNull(); + } + }); }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/src/filter.js b/packages/jsdoc/test/specs/jsdoc/src/filter.js index f30e1be3..9568d6b3 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/filter.js +++ b/packages/jsdoc/test/specs/jsdoc/src/filter.js @@ -1,163 +1,157 @@ describe('jsdoc/src/filter', () => { - const filter = require('jsdoc/src/filter'); - const path = require('path'); + const filter = require('jsdoc/src/filter'); + const path = require('path'); - it('should exist', () => { - expect(filter).toBeObject(); + it('should exist', () => { + expect(filter).toBeObject(); + }); + + it('should export a "Filter" class', () => { + expect(filter.Filter).toBeFunction(); + }); + + describe('Filter', () => { + let myFilter; + + const defaultIncludePattern = /.+\.js(doc)?$/; + const defaultExcludePattern = /(^|\/|\\)_/; + + beforeEach(() => { + myFilter = new filter.Filter({}); }); - it('should export a "Filter" class', () => { - expect(filter.Filter).toBeFunction(); + it('should have an "exclude" property', () => { + expect(myFilter.exclude).toBeDefined(); }); - describe('Filter', () => { - let myFilter; - - const defaultIncludePattern = /.+\.js(doc)?$/; - const defaultExcludePattern = /(^|\/|\\)_/; - - beforeEach(() => { - myFilter = new filter.Filter({}); - }); - - it('should have an "exclude" property', () => { - expect(myFilter.exclude).toBeDefined(); - }); - - it('should have an "excludePattern" property', () => { - expect(myFilter.excludePattern).toBeDefined(); - }); - - it('should have an "includePattern" property', () => { - expect(myFilter.includePattern).toBeDefined(); - }); - - it('should have an "isIncluded" method', () => { - expect(myFilter.isIncluded).toBeFunction(); - }); - - describe('exclude', () => { - it('should default to null', () => { - expect(myFilter.exclude).toBeNull(); - }); - - it('should be null if the value passed to the constructor was not an array', - () => { - myFilter = new filter.Filter({ - exclude: 'foo' - }); - - expect(myFilter.exclude).toBeNull(); - }); - - it('should resolve paths relative to the user\'s working directory', () => { - const filename = 'bar.js'; - - myFilter = new filter.Filter({ - exclude: [filename] - }); - - expect(myFilter.exclude).toEqual([path.resolve(process.cwd(), filename)]); - }); - }); - - function testRegExpProperty(name) { - it('should default to null', () => { - expect(myFilter[name]).toBeNull(); - }); - - it('should contain the regexp passed to the constructor', () => { - const regExp = /^foo$/; - const options = {}; - - options[name] = regExp; - myFilter = new filter.Filter(options); - - expect(myFilter[name]).toBe(regExp); - }); - - it('should contain a regexp if a string was passed to the constructor', () => { - const regExpString = '^foo$'; - const options = {}; - - options[name] = regExpString; - myFilter = new filter.Filter(options); - - expect(myFilter[name]).toBeRegExp(); - expect(myFilter[name].source).toBe(regExpString); - }); - } - - describe( 'excludePattern', testRegExpProperty.bind(jasmine, 'excludePattern') ); - - describe( 'includePattern', testRegExpProperty.bind(jasmine, 'includePattern') ); - - describe('isIncluded', () => { - it('should return the correct source files', () => { - let files = [ - 'yes.js', - '/yes.jsdoc', - '/_nope.js', - '.ignore', - path.normalize(`${process.cwd()}/scratch/conf.js`) - ]; - - myFilter = new filter.Filter({ - includePattern: defaultIncludePattern, - excludePattern: defaultExcludePattern, - exclude: ['.ignore', 'scratch/conf.js'] - }); - - files = files.filter($ => myFilter.isIncluded($)); - - expect(files).toBeArrayOfSize(2); - expect( files.includes('yes.js') ).toBeTrue(); - expect( files.includes('/yes.jsdoc') ).toBeTrue(); - }); - - it('should be able to exclude specific subdirectories', () => { - let files = [ - 'yes.js', - 'topsecret/nope.js', - 'module/yes.js', - 'module/topsecret/nope.js' - ]; - - myFilter = new filter.Filter({ - includePattern: defaultIncludePattern, - excludePattern: defaultExcludePattern, - exclude: ['topsecret', 'module/topsecret'] - }); - - files = files.filter($ => myFilter.isIncluded($)); - - expect(files).toBeArrayOfSize(2); - expect( files.includes('yes.js') ).toBeTrue(); - expect( files.includes('module/yes.js') ).toBeTrue(); - }); - - it('should be able to exclude descendants of excluded subdirectories', () => { - let files = [ - 'yes.js', - 'topsecret/nested/nope.js', - 'module/yes.js', - 'module/topsecret/nested/nope.js' - ]; - - myFilter = new filter.Filter({ - includePattern: defaultIncludePattern, - excludePattern: defaultExcludePattern, - exclude: ['topsecret', 'module/topsecret'] - }); - - files = files.filter($ => myFilter.isIncluded($)); - - expect(files).toBeArrayOfSize(2); - expect( files.includes('yes.js') ).toBeTrue(); - expect( files.includes('module/yes.js') ).toBeTrue(); - expect( files.includes('topsecret/nested/nope.js') ).toBeFalse(); - expect( files.includes('module/topsecret/nested/nope.js') ).toBeFalse(); - }); - }); + it('should have an "excludePattern" property', () => { + expect(myFilter.excludePattern).toBeDefined(); }); + + it('should have an "includePattern" property', () => { + expect(myFilter.includePattern).toBeDefined(); + }); + + it('should have an "isIncluded" method', () => { + expect(myFilter.isIncluded).toBeFunction(); + }); + + describe('exclude', () => { + it('should default to null', () => { + expect(myFilter.exclude).toBeNull(); + }); + + it('should be null if the value passed to the constructor was not an array', () => { + myFilter = new filter.Filter({ + exclude: 'foo', + }); + + expect(myFilter.exclude).toBeNull(); + }); + + it("should resolve paths relative to the user's working directory", () => { + const filename = 'bar.js'; + + myFilter = new filter.Filter({ + exclude: [filename], + }); + + expect(myFilter.exclude).toEqual([path.resolve(process.cwd(), filename)]); + }); + }); + + function testRegExpProperty(name) { + it('should default to null', () => { + expect(myFilter[name]).toBeNull(); + }); + + it('should contain the regexp passed to the constructor', () => { + const regExp = /^foo$/; + const options = {}; + + options[name] = regExp; + myFilter = new filter.Filter(options); + + expect(myFilter[name]).toBe(regExp); + }); + + it('should contain a regexp if a string was passed to the constructor', () => { + const regExpString = '^foo$'; + const options = {}; + + options[name] = regExpString; + myFilter = new filter.Filter(options); + + expect(myFilter[name]).toBeRegExp(); + expect(myFilter[name].source).toBe(regExpString); + }); + } + + describe('excludePattern', testRegExpProperty.bind(jasmine, 'excludePattern')); + + describe('includePattern', testRegExpProperty.bind(jasmine, 'includePattern')); + + describe('isIncluded', () => { + it('should return the correct source files', () => { + let files = [ + 'yes.js', + '/yes.jsdoc', + '/_nope.js', + '.ignore', + path.normalize(`${process.cwd()}/scratch/conf.js`), + ]; + + myFilter = new filter.Filter({ + includePattern: defaultIncludePattern, + excludePattern: defaultExcludePattern, + exclude: ['.ignore', 'scratch/conf.js'], + }); + + files = files.filter(($) => myFilter.isIncluded($)); + + expect(files).toBeArrayOfSize(2); + expect(files.includes('yes.js')).toBeTrue(); + expect(files.includes('/yes.jsdoc')).toBeTrue(); + }); + + it('should be able to exclude specific subdirectories', () => { + let files = ['yes.js', 'topsecret/nope.js', 'module/yes.js', 'module/topsecret/nope.js']; + + myFilter = new filter.Filter({ + includePattern: defaultIncludePattern, + excludePattern: defaultExcludePattern, + exclude: ['topsecret', 'module/topsecret'], + }); + + files = files.filter(($) => myFilter.isIncluded($)); + + expect(files).toBeArrayOfSize(2); + expect(files.includes('yes.js')).toBeTrue(); + expect(files.includes('module/yes.js')).toBeTrue(); + }); + + it('should be able to exclude descendants of excluded subdirectories', () => { + let files = [ + 'yes.js', + 'topsecret/nested/nope.js', + 'module/yes.js', + 'module/topsecret/nested/nope.js', + ]; + + myFilter = new filter.Filter({ + includePattern: defaultIncludePattern, + excludePattern: defaultExcludePattern, + exclude: ['topsecret', 'module/topsecret'], + }); + + files = files.filter(($) => myFilter.isIncluded($)); + + expect(files).toBeArrayOfSize(2); + expect(files.includes('yes.js')).toBeTrue(); + expect(files.includes('module/yes.js')).toBeTrue(); + expect(files.includes('topsecret/nested/nope.js')).toBeFalse(); + expect(files.includes('module/topsecret/nested/nope.js')).toBeFalse(); + }); + }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/src/handlers.js b/packages/jsdoc/test/specs/jsdoc/src/handlers.js index 2f70d43f..0e0bd9dd 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/handlers.js +++ b/packages/jsdoc/test/specs/jsdoc/src/handlers.js @@ -1,54 +1,54 @@ describe('jsdoc/src/handlers', () => { - const handlers = require('jsdoc/src/handlers'); + const handlers = require('jsdoc/src/handlers'); - const testParser = jsdoc.createParser(); + const testParser = jsdoc.createParser(); - handlers.attachTo(testParser); + handlers.attachTo(testParser); - it('should exist', () => { - expect(handlers).toBeObject(); + it('should exist', () => { + expect(handlers).toBeObject(); + }); + + it('should export an "attachTo" function', () => { + expect(handlers.attachTo).toBeFunction(); + }); + + describe('attachTo', () => { + it('should attach a "jsdocCommentFound" handler to the parser', () => { + const callbacks = testParser.listeners('jsdocCommentFound'); + + expect(callbacks).toBeArrayOfSize(1); + expect(callbacks[0]).toBeFunction(); }); - it('should export an "attachTo" function', () => { - expect(handlers.attachTo).toBeFunction(); + it('should attach a "symbolFound" handler to the parser', () => { + const callbacks = testParser.listeners('symbolFound'); + + expect(callbacks).toBeArrayOfSize(1); + expect(callbacks[0]).toBeFunction(); }); - describe('attachTo', () => { - it('should attach a "jsdocCommentFound" handler to the parser', () => { - const callbacks = testParser.listeners('jsdocCommentFound'); + it('should attach a "fileComplete" handler to the parser', () => { + const callbacks = testParser.listeners('fileComplete'); - expect(callbacks).toBeArrayOfSize(1); - expect(callbacks[0]).toBeFunction(); - }); - - it('should attach a "symbolFound" handler to the parser', () => { - const callbacks = testParser.listeners('symbolFound'); - - expect(callbacks).toBeArrayOfSize(1); - expect(callbacks[0]).toBeFunction(); - }); - - it('should attach a "fileComplete" handler to the parser', () => { - const callbacks = testParser.listeners('fileComplete'); - - expect(callbacks).toBeArrayOfSize(1); - expect(callbacks[0]).toBeFunction(); - }); + expect(callbacks).toBeArrayOfSize(1); + expect(callbacks[0]).toBeFunction(); }); + }); - describe('jsdocCommentFound handler', () => { - /* eslint-disable no-script-url */ - const sourceCode = 'javascript:/** @name bar */'; - /* eslint-enable no-script-url */ - const result = testParser.parse(sourceCode); + describe('jsdocCommentFound handler', () => { + /* eslint-disable no-script-url */ + const sourceCode = 'javascript:/** @name bar */'; + /* eslint-enable no-script-url */ + const result = testParser.parse(sourceCode); - it('should create a doclet for comments with "@name" tags', () => { - expect(result).toBeArrayOfSize(1); - expect(result[0].name).toBe('bar'); - }); + it('should create a doclet for comments with "@name" tags', () => { + expect(result).toBeArrayOfSize(1); + expect(result[0].name).toBe('bar'); }); + }); - xdescribe('symbolFound handler', () => { - // TODO - }); + xdescribe('symbolFound handler', () => { + // TODO + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/src/parser.js b/packages/jsdoc/test/specs/jsdoc/src/parser.js index bc6850ba..2c0f3baa 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/parser.js +++ b/packages/jsdoc/test/specs/jsdoc/src/parser.js @@ -1,408 +1,412 @@ /* eslint-disable no-script-url */ describe('jsdoc/src/parser', () => { - const _ = require('lodash'); - const { attachTo } = require('jsdoc/src/handlers'); - const fs = require('fs'); - const jsdocParser = require('jsdoc/src/parser'); - const path = require('path'); + const _ = require('lodash'); + const { attachTo } = require('jsdoc/src/handlers'); + const fs = require('fs'); + const jsdocParser = require('jsdoc/src/parser'); + const path = require('path'); - const dirname = path.resolve(path.join(__dirname, '..', '..', '..', '..')); + const dirname = path.resolve(path.join(__dirname, '..', '..', '..', '..')); - it('should exist', () => { - expect(jsdocParser).toBeObject(); + it('should exist', () => { + expect(jsdocParser).toBeObject(); + }); + + it('should export a "createParser" method', () => { + expect(jsdocParser.createParser).toBeFunction(); + }); + + it('should export a "Parser" constructor', () => { + expect(jsdocParser.Parser).toBeFunction(); + }); + + describe('createParser', () => { + it('should return a Parser when called without arguments', () => { + expect(jsdocParser.createParser()).toBeObject(); }); - it('should export a "createParser" method', () => { - expect(jsdocParser.createParser).toBeFunction(); + it('should create a jsdoc/src/parser.Parser instance with the argument "js"', () => { + const parser = jsdocParser.createParser('js'); + + expect(parser instanceof jsdocParser.Parser).toBeTrue(); }); - it('should export a "Parser" constructor', () => { - expect(jsdocParser.Parser).toBeFunction(); + it('should log a fatal error on bad input', () => { + function createParser() { + jsdocParser.createParser('not-a-real-parser-ever'); + } + + expect(jsdoc.didLog(createParser, 'fatal')).toBeTrue(); + }); + }); + + describe('Parser', () => { + let parser; + + function newParser() { + parser = new jsdocParser.Parser(); + } + + newParser(); + + it('should have a "visitor" property', () => { + expect(parser.visitor).toBeObject(); }); - describe('createParser', () => { - it('should return a Parser when called without arguments', () => { - expect(jsdocParser.createParser()).toBeObject(); - }); - - it('should create a jsdoc/src/parser.Parser instance with the argument "js"', () => { - const parser = jsdocParser.createParser('js'); - - expect(parser instanceof jsdocParser.Parser).toBeTrue(); - }); - - it('should log a fatal error on bad input', () => { - function createParser() { - jsdocParser.createParser('not-a-real-parser-ever'); - } - - expect(jsdoc.didLog(createParser, 'fatal')).toBeTrue(); - }); + it('should have a "walker" property', () => { + expect(parser.walker).toBeObject(); }); - describe('Parser', () => { - let parser; + it('should have a "parse" method', () => { + expect(parser.parse).toBeFunction(); + }); - function newParser() { - parser = new jsdocParser.Parser(); + it('should have a "results" method', () => { + expect(parser.results).toBeFunction(); + }); + + it('should have an "addAstNodeVisitor" method', () => { + expect(parser.addAstNodeVisitor).toBeFunction(); + }); + + it('should have a "getAstNodeVisitors" method', () => { + expect(parser.getAstNodeVisitors).toBeFunction(); + }); + + describe('visitor', () => { + it('should contain an appropriate visitor by default', () => { + const { Visitor } = require('jsdoc/src/visitor'); + + expect(parser.visitor instanceof Visitor).toBeTrue(); + }); + }); + + describe('walker', () => { + it('should contain an appropriate walker by default', () => { + const { Walker } = require('jsdoc/src/walker'); + + expect(parser.walker instanceof Walker).toBeTrue(); + }); + }); + + describe('parse', () => { + beforeEach(newParser); + + it('should fire "parseBegin" events before it parses any files', () => { + const spy = jasmine.createSpy(); + const sourceFiles = ['javascript:/** @name foo */']; + + parser.on('parseBegin', spy).parse(sourceFiles); + expect(spy).toHaveBeenCalled(); + expect(spy.calls.mostRecent().args[0].sourcefiles).toBe(sourceFiles); + }); + + it("should allow 'parseBegin' handlers to modify the list of source files", () => { + const sourceCode = 'javascript:/** @name foo */'; + const newFiles = ['[[replaced]]']; + let evt; + + function handler(e) { + e.sourcefiles = newFiles; + evt = e; } - newParser(); + parser.on('parseBegin', handler).parse(sourceCode); + expect(evt.sourcefiles).toBe(newFiles); + }); - it('should have a "visitor" property', () => { - expect(parser.visitor).toBeObject(); + it('should fire "jsdocCommentFound" events when a source file contains JSDoc comments', () => { + const spy = jasmine.createSpy(); + const sourceCode = ['javascript:/** @name bar */']; + + parser.on('jsdocCommentFound', spy).parse(sourceCode); + + expect(spy).toHaveBeenCalled(); + expect(spy.calls.mostRecent().args[0].comment).toBe('/** @name bar */'); + }); + + it('should fire "symbolFound" events when a source file contains named symbols', () => { + const spy = jasmine.createSpy(); + const sourceCode = 'javascript:var foo = 1'; + + parser.on('symbolFound', spy).parse(sourceCode); + + expect(spy).toHaveBeenCalled(); + }); + + it('should fire "newDoclet" events after creating a new doclet', () => { + const spy = jasmine.createSpy(); + const sourceCode = 'javascript:var foo = 1'; + + parser.on('symbolFound', spy).parse(sourceCode); + + expect(spy).toHaveBeenCalled(); + }); + + it('should allow "newDoclet" handlers to modify doclets', () => { + let results; + const sourceCode = 'javascript:/** @class */function Foo() {}'; + + function handler(e) { + e.doclet = _.cloneDeep(e.doclet); + e.doclet.foo = 'bar'; + } + + attachTo(parser); + parser.on('newDoclet', handler).parse(sourceCode); + results = parser.results(); + + expect(results[0].foo).toBe('bar'); + }); + + it('should call AST node visitors', () => { + const { Syntax } = require('@jsdoc/parse'); + + let args; + const sourceCode = ['javascript:/** foo */var foo;']; + const visitor = { + visitNode(node, e) { + if (e && e.code && !args) { + args = Array.prototype.slice.call(arguments); + } + }, + }; + + attachTo(parser); + parser.addAstNodeVisitor(visitor); + parser.parse(sourceCode); + + expect(args).toBeArrayOfSize(4); + + // args[0]: AST node + expect(args[0].type).toBe(Syntax.VariableDeclarator); + + // args[1]: JSDoc event + expect(args[1]).toBeObject(); + expect(args[1].code).toBeObject(); + expect(args[1].code.name).toBe('foo'); + + // args[2]: parser + expect(args[2]).toBeObject(); + expect(args[2] instanceof jsdocParser.Parser).toBeTrue(); + + // args[3]: current source name + expect(String(args[3])).toBe('[[string0]]'); + }); + + it('should reflect changes made by AST node visitors', () => { + let doclet; + const sourceCode = ['javascript:/** foo */var foo;']; + const visitor = { + visitNode(node, e) { + if (e && e.code && e.code.name === 'foo') { + e.code.name = 'bar'; + } + }, + }; + + attachTo(parser); + parser.addAstNodeVisitor(visitor); + parser.parse(sourceCode); + + doclet = parser.results()[0]; + + expect(doclet).toBeObject(); + expect(doclet.name).toBe('bar'); + }); + + it('should fire "parseComplete" events after it finishes parsing files', () => { + let eventObject; + const spy = jasmine.createSpy(); + const sourceCode = ['javascript:/** @class */function Foo() {}']; + + attachTo(parser); + parser.on('parseComplete', spy).parse(sourceCode); + + expect(spy).toHaveBeenCalled(); + + eventObject = spy.calls.mostRecent().args[0]; + + expect(eventObject).toBeDefined(); + expect(eventObject.sourcefiles).toEqual(['[[string0]]']); + + expect(eventObject.doclets).toBeArrayOfSize(1); + expect(eventObject.doclets[0].kind).toBe('class'); + expect(eventObject.doclets[0].longname).toBe('Foo'); + }); + + it('should fire a "processingComplete" event when fireProcessingComplete is called', () => { + const spy = jasmine.createSpy(); + const doclets = ['a', 'b']; + let mostRecentArg0; + + parser.on('processingComplete', spy).fireProcessingComplete(doclets); + + expect(spy).toHaveBeenCalled(); + + mostRecentArg0 = spy.calls.mostRecent().args[0]; + expect(mostRecentArg0).toBeObject(); + expect(mostRecentArg0.doclets).toBe(doclets); + }); + + it('should not throw errors when parsing files with ES6 syntax', () => { + function parse() { + const parserSrc = `javascript:${fs.readFileSync( + path.join(dirname, 'test/fixtures/es6.js'), + 'utf8' + )}`; + + parser.parse(parserSrc); + } + + expect(parse).not.toThrow(); + }); + + it('should be able to parse its own source file', () => { + const parserSrc = `javascript:${fs.readFileSync( + path.join(dirname, 'lib/jsdoc/src/parser.js'), + 'utf8' + )}`; + + function parse() { + parser.parse(parserSrc); + } + + expect(parse).not.toThrow(); + }); + + it('should comment out a POSIX hashbang at the start of the file', () => { + const parserSrc = 'javascript:#!/usr/bin/env node\n/** class */function Foo() {}'; + + function parse() { + parser.parse(parserSrc); + } + + expect(parse).not.toThrow(); + }); + }); + + describe('results', () => { + beforeEach(newParser); + + it('returns an empty array before files are parsed', () => { + const results = parser.results(); + + expect(results).toBeEmptyArray(); + }); + + it('returns an array of doclets after files are parsed', () => { + const source = 'javascript:var foo;'; + let results; + + attachTo(parser); + + parser.parse(source); + results = parser.results(); + + expect(results).toBeArrayOfSize(1); + expect(results[0]).toBeObject(); + expect(results[0].name).toBe('foo'); + }); + + it('should reflect comment changes made by "jsdocCommentFound" handlers', () => { + // we test both POSIX and Windows line endings + const source = + 'javascript:/**\n * replaceme\r\n * @module foo\n */\n\n' + + '/**\n * replaceme\n */\nvar bar;'; + + parser.on('jsdocCommentFound', (e) => { + e.comment = e.comment.replace('replaceme', 'REPLACED!'); }); + attachTo(parser); - it('should have a "walker" property', () => { - expect(parser.walker).toBeObject(); + parser.parse(source); + parser.results().forEach(({ comment }) => { + expect(comment).not.toMatch('replaceme'); + expect(comment).toMatch('REPLACED!'); }); - - it('should have a "parse" method', () => { - expect(parser.parse).toBeFunction(); - }); - - it('should have a "results" method', () => { - expect(parser.results).toBeFunction(); - }); - - it('should have an "addAstNodeVisitor" method', () => { - expect(parser.addAstNodeVisitor).toBeFunction(); - }); - - it('should have a "getAstNodeVisitors" method', () => { - expect(parser.getAstNodeVisitors).toBeFunction(); - }); - - describe('visitor', () => { - it('should contain an appropriate visitor by default', () => { - const { Visitor } = require('jsdoc/src/visitor'); - - expect(parser.visitor instanceof Visitor).toBeTrue(); - }); - }); - - describe('walker', () => { - it('should contain an appropriate walker by default', () => { - const { Walker } = require('jsdoc/src/walker'); - - expect(parser.walker instanceof Walker).toBeTrue(); - }); - }); - - describe('parse', () => { - beforeEach(newParser); - - it('should fire "parseBegin" events before it parses any files', () => { - const spy = jasmine.createSpy(); - const sourceFiles = ['javascript:/** @name foo */']; - - parser.on('parseBegin', spy).parse(sourceFiles); - expect(spy).toHaveBeenCalled(); - expect(spy.calls.mostRecent().args[0].sourcefiles).toBe(sourceFiles); - }); - - it("should allow 'parseBegin' handlers to modify the list of source files", () => { - const sourceCode = 'javascript:/** @name foo */'; - const newFiles = ['[[replaced]]']; - let evt; - - function handler(e) { - e.sourcefiles = newFiles; - evt = e; - } - - parser.on('parseBegin', handler).parse(sourceCode); - expect(evt.sourcefiles).toBe(newFiles); - }); - - it('should fire "jsdocCommentFound" events when a source file contains JSDoc comments', () => { - const spy = jasmine.createSpy(); - const sourceCode = ['javascript:/** @name bar */']; - - parser.on('jsdocCommentFound', spy).parse(sourceCode); - - expect(spy).toHaveBeenCalled(); - expect(spy.calls.mostRecent().args[0].comment).toBe('/** @name bar */'); - }); - - it('should fire "symbolFound" events when a source file contains named symbols', () => { - const spy = jasmine.createSpy(); - const sourceCode = 'javascript:var foo = 1'; - - parser.on('symbolFound', spy).parse(sourceCode); - - expect(spy).toHaveBeenCalled(); - }); - - it('should fire "newDoclet" events after creating a new doclet', () => { - const spy = jasmine.createSpy(); - const sourceCode = 'javascript:var foo = 1'; - - parser.on('symbolFound', spy).parse(sourceCode); - - expect(spy).toHaveBeenCalled(); - }); - - it('should allow "newDoclet" handlers to modify doclets', () => { - let results; - const sourceCode = 'javascript:/** @class */function Foo() {}'; - - function handler(e) { - e.doclet = _.cloneDeep(e.doclet); - e.doclet.foo = 'bar'; - } - - attachTo(parser); - parser.on('newDoclet', handler).parse(sourceCode); - results = parser.results(); - - expect(results[0].foo).toBe('bar'); - }); - - it('should call AST node visitors', () => { - const { Syntax } = require('@jsdoc/parse'); - - let args; - const sourceCode = ['javascript:/** foo */var foo;']; - const visitor = { - visitNode(node, e) { - if (e && e.code && !args) { - args = Array.prototype.slice.call(arguments); - } - } - }; - - attachTo(parser); - parser.addAstNodeVisitor(visitor); - parser.parse(sourceCode); - - expect(args).toBeArrayOfSize(4); - - // args[0]: AST node - expect(args[0].type).toBe(Syntax.VariableDeclarator); - - // args[1]: JSDoc event - expect(args[1]).toBeObject(); - expect(args[1].code).toBeObject(); - expect(args[1].code.name).toBe('foo'); - - // args[2]: parser - expect(args[2]).toBeObject(); - expect(args[2] instanceof jsdocParser.Parser).toBeTrue(); - - // args[3]: current source name - expect( String(args[3]) ).toBe('[[string0]]'); - }); - - it('should reflect changes made by AST node visitors', () => { - let doclet; - const sourceCode = ['javascript:/** foo */var foo;']; - const visitor = { - visitNode(node, e) { - if (e && e.code && e.code.name === 'foo') { - e.code.name = 'bar'; - } - } - }; - - attachTo(parser); - parser.addAstNodeVisitor(visitor); - parser.parse(sourceCode); - - doclet = parser.results()[0]; - - expect(doclet).toBeObject(); - expect(doclet.name).toBe('bar'); - }); - - it('should fire "parseComplete" events after it finishes parsing files', () => { - let eventObject; - const spy = jasmine.createSpy(); - const sourceCode = ['javascript:/** @class */function Foo() {}']; - - attachTo(parser); - parser.on('parseComplete', spy).parse(sourceCode); - - expect(spy).toHaveBeenCalled(); - - eventObject = spy.calls.mostRecent().args[0]; - - expect(eventObject).toBeDefined(); - expect(eventObject.sourcefiles).toEqual(['[[string0]]']); - - expect(eventObject.doclets).toBeArrayOfSize(1); - expect(eventObject.doclets[0].kind).toBe('class'); - expect(eventObject.doclets[0].longname).toBe('Foo'); - }); - - it('should fire a "processingComplete" event when fireProcessingComplete is called', () => { - const spy = jasmine.createSpy(); - const doclets = ['a', 'b']; - let mostRecentArg0; - - parser.on('processingComplete', spy).fireProcessingComplete(doclets); - - expect(spy).toHaveBeenCalled(); - - mostRecentArg0 = spy.calls.mostRecent().args[0]; - expect(mostRecentArg0).toBeObject(); - expect(mostRecentArg0.doclets).toBe(doclets); - }); - - it('should not throw errors when parsing files with ES6 syntax', () => { - function parse() { - const parserSrc = `javascript:${fs.readFileSync( - path.join(dirname, 'test/fixtures/es6.js'), 'utf8')}`; - - parser.parse(parserSrc); - } - - expect(parse).not.toThrow(); - }); - - it('should be able to parse its own source file', () => { - const parserSrc = `javascript:${fs.readFileSync(path.join(dirname, - 'lib/jsdoc/src/parser.js'), 'utf8')}`; - - function parse() { - parser.parse(parserSrc); - } - - expect(parse).not.toThrow(); - }); - - it('should comment out a POSIX hashbang at the start of the file', () => { - const parserSrc = 'javascript:#!/usr/bin/env node\n/** class */function Foo() {}'; - - function parse() { - parser.parse(parserSrc); - } - - expect(parse).not.toThrow(); - }); - }); - - describe('results', () => { - beforeEach(newParser); - - it('returns an empty array before files are parsed', () => { - const results = parser.results(); - - expect(results).toBeEmptyArray(); - }); - - it('returns an array of doclets after files are parsed', () => { - const source = 'javascript:var foo;'; - let results; - - attachTo(parser); - - parser.parse(source); - results = parser.results(); - - expect(results).toBeArrayOfSize(1); - expect(results[0]).toBeObject(); - expect(results[0].name).toBe('foo'); - }); - - it('should reflect comment changes made by "jsdocCommentFound" handlers', () => { - // we test both POSIX and Windows line endings - const source = 'javascript:/**\n * replaceme\r\n * @module foo\n */\n\n' + - '/**\n * replaceme\n */\nvar bar;'; - - parser.on('jsdocCommentFound', e => { - e.comment = e.comment.replace('replaceme', 'REPLACED!'); - }); - attachTo(parser); - - parser.parse(source); - parser.results().forEach(({comment}) => { - expect(comment).not.toMatch('replaceme'); - expect(comment).toMatch('REPLACED!'); - }); - }); - - // TODO: this test appears to be doing nothing... - xdescribe('event order', () => { - const events = { - all: [], - jsdocCommentFound: [], - symbolFound: [] - }; - const source = fs.readFileSync(path.join(dirname, - 'test/fixtures/eventorder.js'), 'utf8'); - - /* + }); + + // TODO: this test appears to be doing nothing... + xdescribe('event order', () => { + const events = { + all: [], + jsdocCommentFound: [], + symbolFound: [], + }; + const source = fs.readFileSync(path.join(dirname, 'test/fixtures/eventorder.js'), 'utf8'); + + /* function pushEvent(e) { events.all.push(e); events[e.event].push(e); } */ - function sourceOrderSort(atom1, atom2) { - if (atom1.range[1] < atom2.range[0]) { - return -1; - } - else if (atom1.range[0] < atom2.range[0] && atom1.range[1] === atom2.range[1]) { - return 1; - } - else { - return 0; - } - } + function sourceOrderSort(atom1, atom2) { + if (atom1.range[1] < atom2.range[0]) { + return -1; + } else if (atom1.range[0] < atom2.range[0] && atom1.range[1] === atom2.range[1]) { + return 1; + } else { + return 0; + } + } - it('should fire interleaved jsdocCommentFound and symbolFound events, ' + - 'in source order', () => { - attachTo(parser); - parser.parse(source); - events.all.slice(0).sort(sourceOrderSort).forEach((e, i) => { - expect(e).toBe(events.all[i]); - }); - }); - }); - }); - - describe('addAstNodeVisitor', () => { - /* eslint-disable no-empty-function */ - function visitorA() {} - function visitorB() {} - /* eslint-enable no-empty-function */ - - let visitors; - - beforeEach(newParser); - - it('should work with a single node visitor', () => { - parser.addAstNodeVisitor(visitorA); - - visitors = parser.getAstNodeVisitors(); - - expect(visitors).toEqual([visitorA]); - }); - - it('should work with multiple node visitors', () => { - parser.addAstNodeVisitor(visitorA); - parser.addAstNodeVisitor(visitorB); - - visitors = parser.getAstNodeVisitors(); - - expect(visitors).toEqual([ - visitorA, - visitorB - ]); - }); - }); - - describe('getAstNodeVisitors', () => { - beforeEach(newParser); - - it('should return an empty array by default', () => { - const visitors = parser.getAstNodeVisitors(); - - expect(visitors).toBeEmptyArray(); - }); - - // other functionality is covered by the addNodeVisitors tests - }); + it( + 'should fire interleaved jsdocCommentFound and symbolFound events, ' + 'in source order', + () => { + attachTo(parser); + parser.parse(source); + events.all + .slice(0) + .sort(sourceOrderSort) + .forEach((e, i) => { + expect(e).toBe(events.all[i]); + }); + } + ); + }); }); + + describe('addAstNodeVisitor', () => { + /* eslint-disable no-empty-function */ + function visitorA() {} + function visitorB() {} + /* eslint-enable no-empty-function */ + + let visitors; + + beforeEach(newParser); + + it('should work with a single node visitor', () => { + parser.addAstNodeVisitor(visitorA); + + visitors = parser.getAstNodeVisitors(); + + expect(visitors).toEqual([visitorA]); + }); + + it('should work with multiple node visitors', () => { + parser.addAstNodeVisitor(visitorA); + parser.addAstNodeVisitor(visitorB); + + visitors = parser.getAstNodeVisitors(); + + expect(visitors).toEqual([visitorA, visitorB]); + }); + }); + + describe('getAstNodeVisitors', () => { + beforeEach(newParser); + + it('should return an empty array by default', () => { + const visitors = parser.getAstNodeVisitors(); + + expect(visitors).toBeEmptyArray(); + }); + + // other functionality is covered by the addNodeVisitors tests + }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/src/scanner.js b/packages/jsdoc/test/specs/jsdoc/src/scanner.js index ef77d2b6..8ee0d657 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/scanner.js +++ b/packages/jsdoc/test/specs/jsdoc/src/scanner.js @@ -1,51 +1,50 @@ describe('jsdoc/src/scanner', () => { - const path = require('path'); - const scanner = require('jsdoc/src/scanner'); + const path = require('path'); + const scanner = require('jsdoc/src/scanner'); - const filter = new (require('jsdoc/src/filter').Filter)({ - includePattern: /.+\.js(doc)?$/, - excludePattern: /(^|\/|\\)_/ - }); - const sourcePath = path.normalize(`${__dirname}/../../../fixtures/src`); + const filter = new (require('jsdoc/src/filter').Filter)({ + includePattern: /.+\.js(doc)?$/, + excludePattern: /(^|\/|\\)_/, + }); + const sourcePath = path.normalize(`${__dirname}/../../../fixtures/src`); - it('should exist', () => { - expect(scanner).toBeObject(); + it('should exist', () => { + expect(scanner).toBeObject(); + }); + + it('should export a "Scanner" class', () => { + expect(scanner.Scanner).toBeFunction(); + }); + + describe('Scanner', () => { + it('should inherit from EventEmitter', () => { + const { EventEmitter } = require('events'); + const testScanner = new scanner.Scanner(); + + expect(testScanner instanceof EventEmitter).toBeTrue(); }); - it('should export a "Scanner" class', () => { - expect(scanner.Scanner).toBeFunction(); + it('should have a "scan" method', () => { + const testScanner = new scanner.Scanner(); + + expect(testScanner.scan).toBeFunction(); }); - describe('Scanner', () => { - it('should inherit from EventEmitter', () => { - const { EventEmitter } = require('events'); - const testScanner = new scanner.Scanner(); + describe('scan', () => { + it('should return the correct source files', () => { + const testScanner = new scanner.Scanner(); + const parentPath = path.normalize(`${__dirname}/../../../..`); + let sourceFiles = testScanner.scan([sourcePath], 3, filter); - expect(testScanner instanceof EventEmitter).toBeTrue(); - }); + sourceFiles = sourceFiles.map(($) => path.relative(parentPath, $)); - it('should have a "scan" method', () => { - const testScanner = new scanner.Scanner(); - - expect(testScanner.scan).toBeFunction(); - }); - - describe('scan', () => { - it('should return the correct source files', () => { - const testScanner = new scanner.Scanner(); - const parentPath = path.normalize(`${__dirname}/../../../..`); - let sourceFiles = testScanner.scan([sourcePath], 3, filter); - - sourceFiles = sourceFiles.map($ => path.relative(parentPath, $)); - - expect(sourceFiles).toBeArrayOfSize(3); - expect( sourceFiles.includes(path.join('test', 'fixtures', 'src', 'one.js')) ) - .toBeTrue(); - expect( sourceFiles.includes(path.join('test', 'fixtures', 'src', 'two.js')) ) - .toBeTrue(); - expect( sourceFiles.includes(path.join('test', 'fixtures', 'src', 'dir1', 'three.js')) ) - .toBeTrue(); - }); - }); + expect(sourceFiles).toBeArrayOfSize(3); + expect(sourceFiles.includes(path.join('test', 'fixtures', 'src', 'one.js'))).toBeTrue(); + expect(sourceFiles.includes(path.join('test', 'fixtures', 'src', 'two.js'))).toBeTrue(); + expect( + sourceFiles.includes(path.join('test', 'fixtures', 'src', 'dir1', 'three.js')) + ).toBeTrue(); + }); }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/src/visitor.js b/packages/jsdoc/test/specs/jsdoc/src/visitor.js index 0e672a01..87f19ed1 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/visitor.js +++ b/packages/jsdoc/test/specs/jsdoc/src/visitor.js @@ -1,216 +1,216 @@ describe('jsdoc/src/visitor', () => { + // TODO: more tests + + const { Parser } = require('jsdoc/src/parser'); + const { Visitor } = require('jsdoc/src/visitor'); + const parser = new Parser(); + const visitor = new Visitor(); + + describe('visitNodeComments', () => { // TODO: more tests - const { Parser } = require('jsdoc/src/parser'); - const { Visitor } = require('jsdoc/src/visitor'); - const parser = new Parser(); - const visitor = new Visitor(); + let events = []; - describe('visitNodeComments', () => { - // TODO: more tests + function listener(event) { + events.push(event); + } - let events = []; - - function listener(event) { - events.push(event); - } - - beforeEach(() => { - parser.addListener('jsdocCommentFound', listener); - }); - - afterEach(() => { - parser.removeListener('jsdocCommentFound', listener); - events = []; - }); - - it('should ignore line comments', () => { - const node = { - leadingComments: [ - { - type: 'CommentLine', - value: ' line comment', - loc: { - start: { - line: 0, - column: 0 - } - } - } - ] - }; - - visitor.visitNodeComments(node, parser, 'fake'); - - expect(events).toBeEmptyArray(); - }); - - it('should ignore normal, non-JSDoc block comments', () => { - const node = { - leadingComments: [ - { - type: 'CommentBlock', - value: ' block comment ', - loc: { - start: { - line: 0, - column: 0 - } - } - } - ] - }; - - visitor.visitNodeComments(node, parser, 'fake'); - - expect(events).toBeEmptyArray(); - }); - - it('should ignore comments that begin with three or more asterisks', () => { - const node = { - leadingComments: [ - { - type: 'CommentBlock', - value: '** block comment ', - loc: { - start: { - line: 0, - column: 0 - } - } - } - ] - }; - - visitor.visitNodeComments(node, parser, 'fake'); - - expect(events).toBeEmptyArray(); - }); - - it('should ignore empty block comments', () => { - const node = { - leadingComments: [ - { - type: 'CommentBlock', - value: '', - loc: { - start: { - line: 0, - column: 0 - } - } - } - ] - }; - - visitor.visitNodeComments(node, parser, 'fake'); - - expect(events).toBeEmptyArray(); - }); - - it('should fire an event for JSDoc comments', () => { - const node = { - leadingComments: [ - { - type: 'CommentBlock', - value: '* block comment ', - loc: { - start: { - line: 0, - column: 0 - } - } - } - ] - }; - - visitor.visitNodeComments(node, parser, 'fake'); - - expect(events).toBeArrayOfSize(1); - expect(events[0].comment).toBe('/** block comment */'); - }); + beforeEach(() => { + parser.addListener('jsdocCommentFound', listener); }); - // TODO: these tests aren't working; the code for visitor.visitNode() stops running in the - // middle of the SymbolFound constructor. maybe an async issue? - xdescribe('visitNode', () => { - // TODO: more tests - - let events = []; - - function listener(event) { - events.push(event); - } - - beforeEach(() => { - parser.addListener('symbolFound', listener); - }); - - afterEach(() => { - parser.removeListener('symbolFound', listener); - events = []; - }); - - it('should ignore non-JSDoc leading comments', () => { - const node = { - type: 'Property', - key: { - type: 'Identifier', - name: 'foo' - }, - value: { - type: 'Literal', - value: true - }, - kind: 'init', - leadingComments: [ - { - type: 'CommentBlock', - value: ' block comment ', - loc: { - start: { - line: 0, - column: 0 - } - } - } - ] - }; - - visitor.visitNode(node, parser, 'fake'); - - expect(events[0].comment).toBe(''); - }); - - it('should include JSDoc leading comments', () => { - const node = { - type: 'Property', - key: { - type: 'Identifier', - name: 'foo' - }, - value: { - type: 'Literal', - value: true - }, - kind: 'init', - leadingComments: [ - { - type: 'CommentBlock', - value: '* block comment ', - loc: { - start: { - line: 0, - column: 0 - } - } - } - ] - }; - - visitor.visitNode(node, parser, 'fake'); - - expect(events[0].comment).toBe('/** block comment */'); - }); + afterEach(() => { + parser.removeListener('jsdocCommentFound', listener); + events = []; }); + + it('should ignore line comments', () => { + const node = { + leadingComments: [ + { + type: 'CommentLine', + value: ' line comment', + loc: { + start: { + line: 0, + column: 0, + }, + }, + }, + ], + }; + + visitor.visitNodeComments(node, parser, 'fake'); + + expect(events).toBeEmptyArray(); + }); + + it('should ignore normal, non-JSDoc block comments', () => { + const node = { + leadingComments: [ + { + type: 'CommentBlock', + value: ' block comment ', + loc: { + start: { + line: 0, + column: 0, + }, + }, + }, + ], + }; + + visitor.visitNodeComments(node, parser, 'fake'); + + expect(events).toBeEmptyArray(); + }); + + it('should ignore comments that begin with three or more asterisks', () => { + const node = { + leadingComments: [ + { + type: 'CommentBlock', + value: '** block comment ', + loc: { + start: { + line: 0, + column: 0, + }, + }, + }, + ], + }; + + visitor.visitNodeComments(node, parser, 'fake'); + + expect(events).toBeEmptyArray(); + }); + + it('should ignore empty block comments', () => { + const node = { + leadingComments: [ + { + type: 'CommentBlock', + value: '', + loc: { + start: { + line: 0, + column: 0, + }, + }, + }, + ], + }; + + visitor.visitNodeComments(node, parser, 'fake'); + + expect(events).toBeEmptyArray(); + }); + + it('should fire an event for JSDoc comments', () => { + const node = { + leadingComments: [ + { + type: 'CommentBlock', + value: '* block comment ', + loc: { + start: { + line: 0, + column: 0, + }, + }, + }, + ], + }; + + visitor.visitNodeComments(node, parser, 'fake'); + + expect(events).toBeArrayOfSize(1); + expect(events[0].comment).toBe('/** block comment */'); + }); + }); + + // TODO: these tests aren't working; the code for visitor.visitNode() stops running in the + // middle of the SymbolFound constructor. maybe an async issue? + xdescribe('visitNode', () => { + // TODO: more tests + + let events = []; + + function listener(event) { + events.push(event); + } + + beforeEach(() => { + parser.addListener('symbolFound', listener); + }); + + afterEach(() => { + parser.removeListener('symbolFound', listener); + events = []; + }); + + it('should ignore non-JSDoc leading comments', () => { + const node = { + type: 'Property', + key: { + type: 'Identifier', + name: 'foo', + }, + value: { + type: 'Literal', + value: true, + }, + kind: 'init', + leadingComments: [ + { + type: 'CommentBlock', + value: ' block comment ', + loc: { + start: { + line: 0, + column: 0, + }, + }, + }, + ], + }; + + visitor.visitNode(node, parser, 'fake'); + + expect(events[0].comment).toBe(''); + }); + + it('should include JSDoc leading comments', () => { + const node = { + type: 'Property', + key: { + type: 'Identifier', + name: 'foo', + }, + value: { + type: 'Literal', + value: true, + }, + kind: 'init', + leadingComments: [ + { + type: 'CommentBlock', + value: '* block comment ', + loc: { + start: { + line: 0, + column: 0, + }, + }, + }, + ], + }; + + visitor.visitNode(node, parser, 'fake'); + + expect(events[0].comment).toBe('/** block comment */'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/src/walker.js b/packages/jsdoc/test/specs/jsdoc/src/walker.js index c7406d0b..177d84ed 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/walker.js +++ b/packages/jsdoc/test/specs/jsdoc/src/walker.js @@ -1,31 +1,31 @@ describe('jsdoc/src/walker', () => { - const walker = require('jsdoc/src/walker'); + const walker = require('jsdoc/src/walker'); - it('should exist', () => { - expect(walker).toBeObject(); + it('should exist', () => { + expect(walker).toBeObject(); + }); + + it('should export a "walkers" object', () => { + expect(walker.walkers).toBeObject(); + }); + + it('should export a "Walker" class', () => { + expect(walker.Walker).toBeFunction(); + }); + + describe('walkers', () => { + const { Syntax } = require('@jsdoc/parse'); + + // TODO: tests for default functions + + it('should contain a function for each known node type', () => { + Object.keys(Syntax).forEach((nodeType) => { + expect(walker.walkers[nodeType]).toBeFunction(); + }); }); + }); - it('should export a "walkers" object', () => { - expect(walker.walkers).toBeObject(); - }); - - it('should export a "Walker" class', () => { - expect(walker.Walker).toBeFunction(); - }); - - describe('walkers', () => { - const { Syntax } = require('@jsdoc/parse'); - - // TODO: tests for default functions - - it('should contain a function for each known node type', () => { - Object.keys(Syntax).forEach(nodeType => { - expect(walker.walkers[nodeType]).toBeFunction(); - }); - }); - }); - - xdescribe('Walker', () => { - // TODO - }); + xdescribe('Walker', () => { + // TODO + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/tag.js b/packages/jsdoc/test/specs/jsdoc/tag.js index 8910e86f..beee2dd0 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag.js +++ b/packages/jsdoc/test/specs/jsdoc/tag.js @@ -1,225 +1,226 @@ const hasOwnProp = Object.prototype.hasOwnProperty; describe('jsdoc/tag', () => { - const env = require('jsdoc/env'); - const jsdocDictionary = require('jsdoc/tag/dictionary'); - const jsdocTag = require('jsdoc/tag'); - const parseType = require('@jsdoc/tag').type.parse; + const env = require('jsdoc/env'); + const jsdocDictionary = require('jsdoc/tag/dictionary'); + const jsdocTag = require('jsdoc/tag'); + const parseType = require('@jsdoc/tag').type.parse; - it('should exist', () => { - expect(jsdocTag).toBeObject(); + it('should exist', () => { + expect(jsdocTag).toBeObject(); + }); + + it('should export a Tag function', () => { + expect(jsdocTag.Tag).toBeFunction(); + }); + + describe('Tag', () => { + const meta = { + lineno: 1, + filename: 'asdf.js', + }; + const desc = 'lalblakd lkjasdlib\n lija'; + const text = `{!number} [foo=1] - ${desc}`; + const exampleRaw = [ + 'Asdf\n', + ' myFunction(1, 2); // returns 3\n', + ' myFunction(3, 4); // returns 7\n', + ]; + const textExample = exampleRaw.join(''); + const exampleIndentedRaw = [ + ' var firstLine;\n', + ' function secondLine() {\n', + ' // comment\n', + ' }\n', + ]; + const textExampleIndented = exampleIndentedRaw.join(''); + + let tagArg; + let tagExample; + let tagExampleIndented; + let tagParam; + let tagParamWithType; + let tagType; + + // allow each test to recreate the tags (for example, after enabling debug mode) + function createTags() { + // synonym for @param; space in the title + tagArg = new jsdocTag.Tag('arg ', text, meta); + // @param with no type, but with optional and defaultvalue + tagParam = new jsdocTag.Tag('param', '[foo=1]', meta); + // @param with type and no type modifiers (such as optional) + tagParamWithType = new jsdocTag.Tag('param', '{string} foo', meta); + // @example that does not need indentation to be removed + tagExample = new jsdocTag.Tag('example', textExample, meta); + // @example that needs indentation to be removed + tagExampleIndented = new jsdocTag.Tag('example', textExampleIndented, meta); + // for testing that onTagText is run when necessary + tagType = new jsdocTag.Tag('type', 'MyType ', meta); + } + + beforeEach(() => { + createTags(); }); - it('should export a Tag function', () => { - expect(jsdocTag.Tag).toBeFunction(); + it("should have a 'originalTitle' property, a string", () => { + expect(tagArg.originalTitle).toBeString(); }); - describe('Tag', () => { - const meta = { - lineno: 1, - filename: 'asdf.js' - }; - const desc = 'lalblakd lkjasdlib\n lija'; - const text = `{!number} [foo=1] - ${desc}`; - const exampleRaw = [ - 'Asdf\n', - ' myFunction(1, 2); // returns 3\n', - ' myFunction(3, 4); // returns 7\n' - ]; - const textExample = exampleRaw.join(''); - const exampleIndentedRaw = [ - ' var firstLine;\n', - ' function secondLine() {\n', - ' // comment\n', - ' }\n' - ]; - const textExampleIndented = exampleIndentedRaw.join(''); + it("'originalTitle' property should be the initial tag title, trimmed of whitespace", () => { + expect(tagArg.originalTitle).toBe('arg'); + expect(tagExample.originalTitle).toBe('example'); + }); - let tagArg; - let tagExample; - let tagExampleIndented; - let tagParam; - let tagParamWithType; - let tagType; + it("should have a 'title' property, a string", () => { + expect(tagArg.title).toBeString(); + }); - // allow each test to recreate the tags (for example, after enabling debug mode) - function createTags() { - // synonym for @param; space in the title - tagArg = new jsdocTag.Tag('arg ', text, meta); - // @param with no type, but with optional and defaultvalue - tagParam = new jsdocTag.Tag('param', '[foo=1]', meta); - // @param with type and no type modifiers (such as optional) - tagParamWithType = new jsdocTag.Tag('param', '{string} foo', meta); - // @example that does not need indentation to be removed - tagExample = new jsdocTag.Tag('example', textExample, meta); - // @example that needs indentation to be removed - tagExampleIndented = new jsdocTag.Tag('example', textExampleIndented, meta); - // for testing that onTagText is run when necessary - tagType = new jsdocTag.Tag('type', 'MyType ', meta); + it("'title' property should be the normalized tag title", () => { + expect(tagArg.title).toBe(jsdocDictionary.normalize(tagArg.originalTitle)); + expect(tagExample.title).toBe(jsdocDictionary.normalize(tagExample.originalTitle)); + }); + + it("should have a 'text' property, a string", () => { + expect(tagArg.text).toBeString(); + }); + + it("should have a 'value' property", () => { + expect(tagArg.value).toBeDefined(); + expect(tagExample.value).toBeDefined(); + expect(tagType.value).toBeDefined(); + }); + + describe("'text' property", () => { + it("'text' property should be the trimmed tag text, with all leading and trailing space removed unless tagDef.keepsWhitespace", () => { + // @example has keepsWhitespace and removesIndent, @param doesn't + expect(tagArg.text).toBe(text.replace(/^\s+|\n$/g, '')); + expect(tagExample.text).toBe(textExample.replace(/\n$/, '')); + expect(tagExampleIndented.text).toBe( + textExampleIndented.replace(/^ {5}/gm, '').replace(/\n$/, '') + ); + }); + + it("'text' property should have onTagText run on it if it has it.", () => { + const def = jsdocDictionary.lookUp('type'); + + expect(def.onTagText).toBeFunction(); + + // @type adds {} around the type if necessary. + expect(tagType.text).toBe(def.onTagText('MyType')); + }); + + it('should be enclosed in quotes, with no whitespace trimming, if it is a symbol name with leading or trailing whitespace', () => { + let wsBoth; + let wsLeading; + let wsOnly; + let wsTrailing; + + function newTags() { + wsOnly = new jsdocTag.Tag('name', ' ', { code: { name: ' ' } }); + wsLeading = new jsdocTag.Tag('name', ' foo', { code: { name: ' foo' } }); + wsTrailing = new jsdocTag.Tag('name', 'foo ', { code: { name: 'foo ' } }); + wsBoth = new jsdocTag.Tag('name', ' foo ', { code: { name: ' foo ' } }); } - beforeEach(() => { - createTags(); - }); - - it("should have a 'originalTitle' property, a string", () => { - expect(tagArg.originalTitle).toBeString(); - }); - - it("'originalTitle' property should be the initial tag title, trimmed of whitespace", () => { - expect(tagArg.originalTitle).toBe('arg'); - expect(tagExample.originalTitle).toBe('example'); - }); - - it("should have a 'title' property, a string", () => { - expect(tagArg.title).toBeString(); - }); - - it("'title' property should be the normalized tag title", () => { - expect(tagArg.title).toBe(jsdocDictionary.normalize(tagArg.originalTitle)); - expect(tagExample.title).toBe(jsdocDictionary.normalize(tagExample.originalTitle)); - }); - - it("should have a 'text' property, a string", () => { - expect(tagArg.text).toBeString(); - }); - - it("should have a 'value' property", () => { - expect(tagArg.value).toBeDefined(); - expect(tagExample.value).toBeDefined(); - expect(tagType.value).toBeDefined(); - }); - - describe("'text' property", () => { - it("'text' property should be the trimmed tag text, with all leading and trailing space removed unless tagDef.keepsWhitespace", () => { - // @example has keepsWhitespace and removesIndent, @param doesn't - expect(tagArg.text).toBe( text.replace(/^\s+|\n$/g, '') ); - expect(tagExample.text).toBe( textExample.replace(/\n$/, '') ); - expect(tagExampleIndented.text).toBe( textExampleIndented.replace(/^ {5}/gm, '') - .replace(/\n$/, '') ); - }); - - it("'text' property should have onTagText run on it if it has it.", () => { - const def = jsdocDictionary.lookUp('type'); - - expect(def.onTagText).toBeFunction(); - - // @type adds {} around the type if necessary. - expect(tagType.text).toBe(def.onTagText('MyType')); - }); - - it('should be enclosed in quotes, with no whitespace trimming, if it is a symbol name with leading or trailing whitespace', () => { - let wsBoth; - let wsLeading; - let wsOnly; - let wsTrailing; - - function newTags() { - wsOnly = new jsdocTag.Tag('name', ' ', { code: { name: ' ' } }); - wsLeading = new jsdocTag.Tag('name', ' foo', { code: { name: ' foo' } }); - wsTrailing = new jsdocTag.Tag('name', 'foo ', { code: { name: 'foo ' } }); - wsBoth = new jsdocTag.Tag('name', ' foo ', { code: { name: ' foo ' } }); - } - - expect(jsdoc.didLog(newTags, 'error')).toBeFalse(); - expect(wsOnly.text).toBe('" "'); - expect(wsLeading.text).toBe('" foo"'); - expect(wsTrailing.text).toBe('"foo "'); - expect(wsBoth.text).toBe('" foo "'); - }); - }); - - describe("'value' property", () => { - const debug = Boolean(env.opts.debug); - - afterEach(() => { - env.opts.debug = debug; - }); - - it("'value' property should equal tag text if tagDef.canHaveType and canHaveName are both false", () => { - // @example can't have type or name - expect(typeof tagExample.value).toBe('string'); - expect(tagExample.value).toBe(tagExample.text); - }); - - it("'value' property should be an object if tagDef can have type or name", () => { - expect(typeof tagType.value).toBe('object'); - expect(typeof tagArg.value).toBe('object'); - }); - - function verifyTagType(tag) { - let def; - let descriptor; - let info; - - def = jsdocDictionary.lookUp(tag.title); - - expect(def).toBeObject(); - - info = parseType(tag.text, def.canHaveName, def.canHaveType); - - ['optional', 'nullable', 'variable', 'defaultvalue'].forEach(prop => { - if (hasOwnProp.call(info, prop)) { - expect(tag.value[prop]).toBe(info[prop]); - } - }); - - if (info.type && info.type.length) { - expect(tag.value.type).toBeObject(); - expect(tag.value.type.names).toEqual(info.type); - - expect(tag.value.type.parsedType).toBeObject(); - - descriptor = Object.getOwnPropertyDescriptor(tag.value.type, 'parsedType'); - expect(descriptor.enumerable).toBe( Boolean(env.opts.debug) ); - } - } - - it('if the tag has a type, tag.value should contain the type information', () => { - [true, false].forEach(bool => { - env.opts.debug = bool; - createTags(); - - verifyTagType(tagType); - verifyTagType(tagArg); - verifyTagType(tagParam); - }); - }); - - it('if the tag has a description beyond the name/type, this should be in tag.value.description', () => { - expect(tagType.value.description).toBeUndefined(); - expect(tagArg.value.description).toBe(desc); - }); - - it('if the tag can have a name, it should be stored in tag.value.name', () => { - expect(tagArg.value.name).toBe('foo'); - expect(tagType.value.name).toBeUndefined(); - }); - - it('if the tag has a type without modifiers, tag.value should not include properties for the modifiers', () => { - ['optional', 'nullable', 'variable', 'defaultvalue'].forEach(modifier => { - expect( hasOwnProp.call(tagParamWithType.value, modifier) ).toBeFalse(); - }); - }); - }); - - // further tests for this sort of thing are in jsdoc/tag/validator.js tests. - describe('tag validating', () => { - it('logs an error for tags with bad type expressions', () => { - function newTag() { - return new jsdocTag.Tag('param', '{!*!*!*!} foo'); - } - - expect(jsdoc.didLog(newTag, 'error')).toBeTrue(); - }); - - it('validates tags with no text', () => { - function newTag() { - return new jsdocTag.Tag('copyright'); - } - - expect(jsdoc.didLog(newTag, 'error')).toBeTrue(); - }); - }); + expect(jsdoc.didLog(newTags, 'error')).toBeFalse(); + expect(wsOnly.text).toBe('" "'); + expect(wsLeading.text).toBe('" foo"'); + expect(wsTrailing.text).toBe('"foo "'); + expect(wsBoth.text).toBe('" foo "'); + }); }); + + describe("'value' property", () => { + const debug = Boolean(env.opts.debug); + + afterEach(() => { + env.opts.debug = debug; + }); + + it("'value' property should equal tag text if tagDef.canHaveType and canHaveName are both false", () => { + // @example can't have type or name + expect(typeof tagExample.value).toBe('string'); + expect(tagExample.value).toBe(tagExample.text); + }); + + it("'value' property should be an object if tagDef can have type or name", () => { + expect(typeof tagType.value).toBe('object'); + expect(typeof tagArg.value).toBe('object'); + }); + + function verifyTagType(tag) { + let def; + let descriptor; + let info; + + def = jsdocDictionary.lookUp(tag.title); + + expect(def).toBeObject(); + + info = parseType(tag.text, def.canHaveName, def.canHaveType); + + ['optional', 'nullable', 'variable', 'defaultvalue'].forEach((prop) => { + if (hasOwnProp.call(info, prop)) { + expect(tag.value[prop]).toBe(info[prop]); + } + }); + + if (info.type && info.type.length) { + expect(tag.value.type).toBeObject(); + expect(tag.value.type.names).toEqual(info.type); + + expect(tag.value.type.parsedType).toBeObject(); + + descriptor = Object.getOwnPropertyDescriptor(tag.value.type, 'parsedType'); + expect(descriptor.enumerable).toBe(Boolean(env.opts.debug)); + } + } + + it('if the tag has a type, tag.value should contain the type information', () => { + [true, false].forEach((bool) => { + env.opts.debug = bool; + createTags(); + + verifyTagType(tagType); + verifyTagType(tagArg); + verifyTagType(tagParam); + }); + }); + + it('if the tag has a description beyond the name/type, this should be in tag.value.description', () => { + expect(tagType.value.description).toBeUndefined(); + expect(tagArg.value.description).toBe(desc); + }); + + it('if the tag can have a name, it should be stored in tag.value.name', () => { + expect(tagArg.value.name).toBe('foo'); + expect(tagType.value.name).toBeUndefined(); + }); + + it('if the tag has a type without modifiers, tag.value should not include properties for the modifiers', () => { + ['optional', 'nullable', 'variable', 'defaultvalue'].forEach((modifier) => { + expect(hasOwnProp.call(tagParamWithType.value, modifier)).toBeFalse(); + }); + }); + }); + + // further tests for this sort of thing are in jsdoc/tag/validator.js tests. + describe('tag validating', () => { + it('logs an error for tags with bad type expressions', () => { + function newTag() { + return new jsdocTag.Tag('param', '{!*!*!*!} foo'); + } + + expect(jsdoc.didLog(newTag, 'error')).toBeTrue(); + }); + + it('validates tags with no text', () => { + function newTag() { + return new jsdocTag.Tag('copyright'); + } + + expect(jsdoc.didLog(newTag, 'error')).toBeTrue(); + }); + }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js b/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js index 0cc22f66..4b97b901 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js +++ b/packages/jsdoc/test/specs/jsdoc/tag/dictionary.js @@ -1,287 +1,287 @@ describe('jsdoc/tag/dictionary', () => { - const dictionary = require('jsdoc/tag/dictionary'); - const Dictionary = dictionary.Dictionary; - const env = require('jsdoc/env'); + const dictionary = require('jsdoc/tag/dictionary'); + const Dictionary = dictionary.Dictionary; + const env = require('jsdoc/env'); - let testDictionary; - const tagOptions = { - canHaveValue: true, - isNamespace: true - }; - let TAG_DEF; - const TAG_SYNONYM = '!!!testTagSynonym!!!'; - const TAG_TITLE = '!!!testTag!!!'; + let testDictionary; + const tagOptions = { + canHaveValue: true, + isNamespace: true, + }; + let TAG_DEF; + const TAG_SYNONYM = '!!!testTagSynonym!!!'; + const TAG_TITLE = '!!!testTag!!!'; + + beforeEach(() => { + testDictionary = new Dictionary(); + TAG_DEF = testDictionary.defineTag(TAG_TITLE, tagOptions).synonym(TAG_SYNONYM); + }); + + it('is an instance of dictionary.Dictionary', () => { + expect(dictionary instanceof dictionary.Dictionary).toBe(true); + }); + + it('has a defineSynonym method', () => { + expect(dictionary.defineSynonym).toBeFunction(); + }); + + it('has a defineTag method', () => { + expect(dictionary.defineTag).toBeFunction(); + }); + + it('has a defineTags method', () => { + expect(dictionary.defineTags).toBeFunction(); + }); + + it('has a fromConfig static method', () => { + expect(dictionary.Dictionary.fromConfig).toBeFunction(); + }); + + it('has a lookup method', () => { + expect(dictionary.lookup).toBeFunction(); + }); + + it('has a lookUp method', () => { + expect(dictionary.lookUp).toBeFunction(); + }); + + it('has an isNamespace method', () => { + expect(dictionary.isNamespace).toBeFunction(); + }); + + it('has a normalise method', () => { + expect(dictionary.normalise).toBeFunction(); + }); + + it('has a normalize method', () => { + expect(dictionary.normalize).toBeFunction(); + }); + + it('has a Dictionary constructor', () => { + expect(dictionary.Dictionary).toBeFunction(); + }); + + describe('defineSynonym', () => { + it('adds a synonym for the specified tag', () => { + dictionary.defineTag('foo', {}); + dictionary.defineSynonym('foo', 'bar'); + + expect(dictionary.normalize('bar')).toBe('foo'); + }); + }); + + describe('defineTag', () => { + it('returns an object with the correct "title" property', () => { + expect(TAG_DEF).toBeObject(); + expect(TAG_DEF.title).toBe(testDictionary.normalize(TAG_TITLE)); + }); + + it('returns an object that contains all of the tag properties', () => { + Object.keys(tagOptions).forEach((opt) => { + expect(TAG_DEF[opt]).toBe(tagOptions[opt]); + }); + }); + + it('works correctly without an options object', () => { + const NEW_TITLE = '!!!testTagNoOptions!!!'; + + function makeTag() { + return testDictionary.defineTag(NEW_TITLE); + } + + expect(makeTag).not.toThrow(); + expect(makeTag().title).toBe(testDictionary.normalize(NEW_TITLE)); + }); + + it('adds synonyms', () => { + const tagDef = { + mustHaveValue: true, + synonyms: ['bar'], + }; + + testDictionary.defineTag('foo', tagDef); + + expect(testDictionary.normalize('bar')).toBe('foo'); + }); + }); + + describe('defineTags', () => { + it('behaves the same as adding tags individually', () => { + const dict1 = new Dictionary(); + const dict2 = new Dictionary(); + const fakeTag = { + mustHaveValue: true, + synonym: 'phony', + }; + + dict1.defineTag('fake', fakeTag); + dict2.defineTags({ fake: fakeTag }); + + expect(dict2.lookup('fake')).toEqual(dict1.lookup('fake')); + expect(dict2.lookup('phony')).toEqual(dict1.lookup('phony')); + }); + + it('returns the tags it added', () => { + const tags = { + tag1: { + tag1Attribute: 'foo', + }, + tag2: { + tag2Attribute: 'bar', + }, + }; + const actualTags = testDictionary.defineTags(tags); + + for (const tag of Object.keys(tags)) { + expect(actualTags[tag]).toBeObject(); + for (const attrib of Object.keys(tags[tag])) { + expect(tags[tag][attrib]).toBe(actualTags[tag][attrib]); + } + } + }); + }); + + describe('fromConfig', () => { + const CLOSURE_TAGNAME = 'final'; + const dictionaryConfig = env.conf.tags.dictionaries.slice(); + const JSDOC_TAGNAME = 'abstract'; beforeEach(() => { - testDictionary = new Dictionary(); - TAG_DEF = testDictionary.defineTag(TAG_TITLE, tagOptions).synonym(TAG_SYNONYM); + env.conf.tags.dictionaries = []; }); - it('is an instance of dictionary.Dictionary', () => { - expect(dictionary instanceof dictionary.Dictionary).toBe(true); + afterEach(() => { + env.conf.tags.dictionaries = dictionaryConfig.slice(); }); - it('has a defineSynonym method', () => { - expect(dictionary.defineSynonym).toBeFunction(); + it('logs an error if `env.conf.tags.dictionaries` is undefined', () => { + function defineTags() { + env.conf.tags.dictionaries = undefined; + Dictionary.fromConfig(env); + } + + expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); }); - it('has a defineTag method', () => { - expect(dictionary.defineTag).toBeFunction(); + it('logs an error if an unknown dictionary is requested', () => { + function defineTags() { + env.conf.tags.dictionaries = ['jsmarmoset']; + Dictionary.fromConfig(env); + } + + expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); }); - it('has a defineTags method', () => { - expect(dictionary.defineTags).toBeFunction(); + it('adds both JSDoc and Closure tags by default', () => { + env.conf.tags.dictionaries = dictionaryConfig.slice(); + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject(); + expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject(); }); - it('has a fromConfig static method', () => { - expect(dictionary.Dictionary.fromConfig).toBeFunction(); + it('adds only the JSDoc tags if requested', () => { + env.conf.tags.dictionaries = ['jsdoc']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject(); + expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeFalse(); }); - it('has a lookup method', () => { - expect(dictionary.lookup).toBeFunction(); + it('adds only the Closure tags if requested', () => { + env.conf.tags.dictionaries = ['closure']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeFalse(); + expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject(); }); - it('has a lookUp method', () => { - expect(dictionary.lookUp).toBeFunction(); + it('prefers tagdefs from the first dictionary on the list', () => { + env.conf.tags.dictionaries = ['closure', 'jsdoc']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup('deprecated').synonyms).not.toBeDefined(); }); - it('has an isNamespace method', () => { - expect(dictionary.isNamespace).toBeFunction(); + it('adds tag synonyms', () => { + env.conf.tags.dictionaries = ['jsdoc']; + testDictionary = Dictionary.fromConfig(env); + + expect(testDictionary.lookup('extends')).toBeObject(); + expect(testDictionary.normalize('extends')).toBe('augments'); + }); + }); + + describe('lookup', () => { + it("retrieves the definition using the tag's canonical name", () => { + expect(testDictionary.lookup(TAG_TITLE)).toBe(TAG_DEF); }); - it('has a normalise method', () => { - expect(dictionary.normalise).toBeFunction(); + it('retrieves the definition using a synonym for the tag', () => { + expect(testDictionary.lookup(TAG_SYNONYM)).toBe(TAG_DEF); }); - it('has a normalize method', () => { - expect(dictionary.normalize).toBeFunction(); + it('returns `false` when a tag is not found', () => { + expect(testDictionary.lookup('lkjas1l24jk')).toBeFalse(); + }); + }); + + describe('lookUp', () => { + it('calls `lookup`', () => { + const lookupSpy = spyOn(testDictionary, 'lookup'); + + testDictionary.lookUp('foo'); + + expect(lookupSpy).toHaveBeenCalled(); + }); + }); + + describe('isNamespace', () => { + it("returns whether a tag is a namespace using the tag's canonical name", () => { + expect(testDictionary.isNamespace(TAG_TITLE)).toBeTrue(); }); - it('has a Dictionary constructor', () => { - expect(dictionary.Dictionary).toBeFunction(); + it('returns whether a tag is a namespace when using a synonym for the tag', () => { + expect(testDictionary.isNamespace(TAG_SYNONYM)).toBeTrue(); }); - describe('defineSynonym', () => { - it('adds a synonym for the specified tag', () => { - dictionary.defineTag('foo', {}); - dictionary.defineSynonym('foo', 'bar'); - - expect(dictionary.normalize('bar')).toBe('foo'); - }); + it('returns `false` for nonexistent tags', () => { + expect(testDictionary.isNamespace('lkjasd90034')).toBeFalse(); }); - describe('defineTag', () => { - it('returns an object with the correct "title" property', () => { - expect(TAG_DEF).toBeObject(); - expect(TAG_DEF.title).toBe(testDictionary.normalize(TAG_TITLE)); - }); + it('returns `false` for non-namespace tags', () => { + expect(testDictionary.isNamespace('see')).toBeFalse(); + }); + }); - it('returns an object that contains all of the tag properties', () => { - Object.keys(tagOptions).forEach(opt => { - expect(TAG_DEF[opt]).toBe(tagOptions[opt]); - }); - }); + describe('normalise', () => { + it('calls `normalize`', () => { + const normalizeSpy = spyOn(testDictionary, 'normalize'); - it('works correctly without an options object', () => { - const NEW_TITLE = '!!!testTagNoOptions!!!'; + testDictionary.normalise('foo'); - function makeTag() { - return testDictionary.defineTag(NEW_TITLE); - } + expect(normalizeSpy).toHaveBeenCalled(); + }); + }); - expect(makeTag).not.toThrow(); - expect(makeTag().title).toBe(testDictionary.normalize(NEW_TITLE)); - }); - - it('adds synonyms', () => { - const tagDef = { - mustHaveValue: true, - synonyms: ['bar'] - }; - - testDictionary.defineTag('foo', tagDef); - - expect(testDictionary.normalize('bar')).toBe('foo'); - }); + describe('normalize', () => { + it('returns the title if it is not a synonym', () => { + expect(testDictionary.normalize('FooBar')).toBe('foobar'); + expect(testDictionary.normalize(TAG_TITLE)).toBe(TAG_DEF.title); }); - describe('defineTags', () => { - it('behaves the same as adding tags individually', () => { - const dict1 = new Dictionary(); - const dict2 = new Dictionary(); - const fakeTag = { - mustHaveValue: true, - synonym: 'phony' - }; - - dict1.defineTag('fake', fakeTag); - dict2.defineTags({ fake: fakeTag }); - - expect(dict2.lookup('fake')).toEqual(dict1.lookup('fake')); - expect(dict2.lookup('phony')).toEqual(dict1.lookup('phony')); - }); - - it('returns the tags it added', () => { - const tags = { - tag1: { - tag1Attribute: 'foo' - }, - tag2: { - tag2Attribute: 'bar' - } - }; - const actualTags = testDictionary.defineTags(tags); - - for (const tag of Object.keys(tags)) { - expect(actualTags[tag]).toBeObject(); - for (const attrib of Object.keys(tags[tag])) { - expect(tags[tag][attrib]).toBe(actualTags[tag][attrib]); - } - } - }); + it('returns the canonical name if the synonym is normalized', () => { + expect(testDictionary.normalize(TAG_SYNONYM)).toBe(TAG_DEF.title); }); + }); - describe('fromConfig', () => { - const CLOSURE_TAGNAME = 'final'; - const dictionaryConfig = env.conf.tags.dictionaries.slice(); - const JSDOC_TAGNAME = 'abstract'; + describe('Dictionary', () => { + it('is a constructor', () => { + function newDictionary() { + return new dictionary.Dictionary(); + } - beforeEach(() => { - env.conf.tags.dictionaries = []; - }); - - afterEach(() => { - env.conf.tags.dictionaries = dictionaryConfig.slice(); - }); - - it('logs an error if `env.conf.tags.dictionaries` is undefined', () => { - function defineTags() { - env.conf.tags.dictionaries = undefined; - Dictionary.fromConfig(env); - } - - expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); - }); - - it('logs an error if an unknown dictionary is requested', () => { - function defineTags() { - env.conf.tags.dictionaries = ['jsmarmoset']; - Dictionary.fromConfig(env); - } - - expect(jsdoc.didLog(defineTags, 'error')).toBeTrue(); - }); - - it('adds both JSDoc and Closure tags by default', () => { - env.conf.tags.dictionaries = dictionaryConfig.slice(); - testDictionary = Dictionary.fromConfig(env); - - expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject(); - expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject(); - }); - - it('adds only the JSDoc tags if requested', () => { - env.conf.tags.dictionaries = ['jsdoc']; - testDictionary = Dictionary.fromConfig(env); - - expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject(); - expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeFalse(); - }); - - it('adds only the Closure tags if requested', () => { - env.conf.tags.dictionaries = ['closure']; - testDictionary = Dictionary.fromConfig(env); - - expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeFalse(); - expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject(); - }); - - it('prefers tagdefs from the first dictionary on the list', () => { - env.conf.tags.dictionaries = ['closure', 'jsdoc']; - testDictionary = Dictionary.fromConfig(env); - - expect(testDictionary.lookup('deprecated').synonyms).not.toBeDefined(); - }); - - it('adds tag synonyms', () => { - env.conf.tags.dictionaries = ['jsdoc']; - testDictionary = Dictionary.fromConfig(env); - - expect(testDictionary.lookup('extends')).toBeObject(); - expect(testDictionary.normalize('extends')).toBe('augments'); - }); - }); - - describe('lookup', () => { - it("retrieves the definition using the tag's canonical name", () => { - expect(testDictionary.lookup(TAG_TITLE)).toBe(TAG_DEF); - }); - - it('retrieves the definition using a synonym for the tag', () => { - expect(testDictionary.lookup(TAG_SYNONYM)).toBe(TAG_DEF); - }); - - it('returns `false` when a tag is not found', () => { - expect(testDictionary.lookup('lkjas1l24jk')).toBeFalse(); - }); - }); - - describe('lookUp', () => { - it('calls `lookup`', () => { - const lookupSpy = spyOn(testDictionary, 'lookup'); - - testDictionary.lookUp('foo'); - - expect(lookupSpy).toHaveBeenCalled(); - }); - }); - - describe('isNamespace', () => { - it("returns whether a tag is a namespace using the tag's canonical name", () => { - expect(testDictionary.isNamespace(TAG_TITLE)).toBeTrue(); - }); - - it('returns whether a tag is a namespace when using a synonym for the tag', () => { - expect(testDictionary.isNamespace(TAG_SYNONYM)).toBeTrue(); - }); - - it('returns `false` for nonexistent tags', () => { - expect(testDictionary.isNamespace('lkjasd90034')).toBeFalse(); - }); - - it('returns `false` for non-namespace tags', () => { - expect(testDictionary.isNamespace('see')).toBeFalse(); - }); - }); - - describe('normalise', () => { - it('calls `normalize`', () => { - const normalizeSpy = spyOn(testDictionary, 'normalize'); - - testDictionary.normalise('foo'); - - expect(normalizeSpy).toHaveBeenCalled(); - }); - }); - - describe('normalize', () => { - it('returns the title if it is not a synonym', () => { - expect(testDictionary.normalize('FooBar')).toBe('foobar'); - expect(testDictionary.normalize(TAG_TITLE)).toBe(TAG_DEF.title); - }); - - it('returns the canonical name if the synonym is normalized', () => { - expect(testDictionary.normalize(TAG_SYNONYM)).toBe(TAG_DEF.title); - }); - }); - - describe('Dictionary', () => { - it('is a constructor', () => { - function newDictionary() { - return new dictionary.Dictionary(); - } - - expect(newDictionary).not.toThrow(); - }); + expect(newDictionary).not.toThrow(); }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js b/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js index fc1ec52d..160677af 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js +++ b/packages/jsdoc/test/specs/jsdoc/tag/dictionary/definitions.js @@ -1,35 +1,35 @@ describe('jsdoc/tag/dictionary/definitions', () => { - const definitions = require('jsdoc/tag/dictionary/definitions'); + const definitions = require('jsdoc/tag/dictionary/definitions'); - it('has a baseTags object', () => { - expect(definitions.baseTags).toBeObject(); - }); + it('has a baseTags object', () => { + expect(definitions.baseTags).toBeObject(); + }); - it('has a closureTags object', () => { - expect(definitions.closureTags).toBeObject(); - }); + it('has a closureTags object', () => { + expect(definitions.closureTags).toBeObject(); + }); - it('has an internalTags object', () => { - expect(definitions.internalTags).toBeObject(); - }); + it('has an internalTags object', () => { + expect(definitions.internalTags).toBeObject(); + }); - it('has a jsdocTags object', () => { - expect(definitions.jsdocTags).toBeObject(); - }); + it('has a jsdocTags object', () => { + expect(definitions.jsdocTags).toBeObject(); + }); - describe('baseTags', () => { - // Nothing to test except which tags are on the list, which would duplicate the code. - }); + describe('baseTags', () => { + // Nothing to test except which tags are on the list, which would duplicate the code. + }); - describe('closureTags', () => { - // Nothing to test except which tags are on the list, which would duplicate the code. - }); + describe('closureTags', () => { + // Nothing to test except which tags are on the list, which would duplicate the code. + }); - describe('internalTags', () => { - // Nothing to test except which tags are on the list, which would duplicate the code. - }); + describe('internalTags', () => { + // Nothing to test except which tags are on the list, which would duplicate the code. + }); - describe('jsdocTags', () => { - // Nothing to test except which tags are on the list, which would duplicate the code. - }); + describe('jsdocTags', () => { + // Nothing to test except which tags are on the list, which would duplicate the code. + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/tag/validator.js b/packages/jsdoc/test/specs/jsdoc/tag/validator.js index 9d879901..24b87014 100644 --- a/packages/jsdoc/test/specs/jsdoc/tag/validator.js +++ b/packages/jsdoc/test/specs/jsdoc/tag/validator.js @@ -1,125 +1,125 @@ describe('jsdoc/tag/validator', () => { - const _ = require('lodash'); - const env = require('jsdoc/env'); - const { EventBus } = require('@jsdoc/util'); - const tag = require('jsdoc/tag'); - const validator = require('jsdoc/tag/validator'); + const _ = require('lodash'); + const env = require('jsdoc/env'); + const { EventBus } = require('@jsdoc/util'); + const tag = require('jsdoc/tag'); + const validator = require('jsdoc/tag/validator'); - it('should exist', () => { - expect(validator).toBeObject(); + it('should exist', () => { + expect(validator).toBeObject(); + }); + + it('should export a validate function', () => { + expect(validator.validate).toBeFunction(); + }); + + describe('validate', () => { + const dictionary = require('jsdoc/tag/dictionary'); + + const allowUnknown = Boolean(env.conf.tags.allowUnknownTags); + const badTag = { title: 'lkjasdlkjfb' }; + const badTag2 = new tag.Tag('type', '{string} I am a string!'); + const meta = { + filename: 'asdf.js', + lineno: 1, + comment: 'Better luck next time.', + }; + const goodTag = new tag.Tag('name', 'MyDocletName', meta); // mustHaveValue + const goodTag2 = new tag.Tag('ignore', '', meta); // mustNotHaveValue + + function validateTag(theTag) { + validator.validate(theTag, dictionary.lookUp(theTag.title), meta); + } + + afterEach(() => { + env.conf.tags.allowUnknownTags = allowUnknown; }); - it('should export a validate function', () => { - expect(validator.validate).toBeFunction(); + it('logs an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is false', () => { + function validate() { + env.conf.tags.allowUnknownTags = false; + validateTag(badTag); + } + + expect(jsdoc.didLog(validate, 'error')).toBeTrue(); }); - describe('validate', () => { - const dictionary = require('jsdoc/tag/dictionary'); + it('logs an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is does not include it', () => { + function validate() { + env.conf.tags.allowUnknownTags = []; + validateTag(badTag); + } - const allowUnknown = Boolean(env.conf.tags.allowUnknownTags); - const badTag = { title: 'lkjasdlkjfb' }; - const badTag2 = new tag.Tag('type', '{string} I am a string!'); - const meta = { - filename: 'asdf.js', - lineno: 1, - comment: 'Better luck next time.' - }; - const goodTag = new tag.Tag('name', 'MyDocletName', meta); // mustHaveValue - const goodTag2 = new tag.Tag('ignore', '', meta); // mustNotHaveValue - - function validateTag(theTag) { - validator.validate(theTag, dictionary.lookUp(theTag.title), meta); - } - - afterEach(() => { - env.conf.tags.allowUnknownTags = allowUnknown; - }); - - it('logs an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is false', () => { - function validate() { - env.conf.tags.allowUnknownTags = false; - validateTag(badTag); - } - - expect(jsdoc.didLog(validate, 'error')).toBeTrue(); - }); - - it('logs an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is does not include it', () => { - function validate() { - env.conf.tags.allowUnknownTags = []; - validateTag(badTag); - } - - expect(jsdoc.didLog(validate, 'error')).toBeTrue(); - }); - - it('does not log an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is true', () => { - function validate() { - env.conf.tags.allowUnknownTags = true; - validateTag(badTag); - } - - expect(jsdoc.didLog(validate, 'error')).toBeFalse(); - }); - - it('does not log an error if the tag is not in the dictionary and conf.tags.allowUnknownTags includes it', () => { - function validate() { - env.conf.tags.allowUnknownTags = [badTag.title]; - validateTag(badTag); - } - - expect(jsdoc.didLog(validate, 'error')).toBeFalse(); - }); - - it('does not log an error for valid tags', () => { - function validate() { - validateTag(goodTag); - validateTag(goodTag2); - } - - expect(jsdoc.didLog(validate, 'error')).toBeFalse(); - }); - - it('logs an error if the tag has no text but mustHaveValue is true', () => { - function validate() { - const missingName = _.cloneDeep(goodTag); - - missingName.text = null; - validateTag(missingName); - } - - expect(jsdoc.didLog(validate, 'error')).toBeTrue(); - }); - - it('logs a warning if the tag has text but mustNotHaveValue is true', () => { - function validate() { - const missingText = _.cloneDeep(goodTag2); - - missingText.mustNotHaveValue = true; - missingText.text = missingText.text || 'asdf'; - validateTag(missingText); - } - - expect(jsdoc.didLog(validate, 'warn')).toBeTrue(); - }); - - it('logs a warning if the tag has a description but mustNotHaveDescription is true', () => { - function validate() { - validateTag(badTag2); - } - - expect(jsdoc.didLog(validate, 'warn')).toBeTrue(); - }); - - it('logs meta.comment when present', () => { - const bus = new EventBus('jsdoc'); - const events = []; - - bus.once('logger:error', e => events.push(e)); - env.conf.tags.allowUnknownTags = false; - validateTag(badTag); - - expect(events[0]).toContain(meta.comment); - }); + expect(jsdoc.didLog(validate, 'error')).toBeTrue(); }); + + it('does not log an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is true', () => { + function validate() { + env.conf.tags.allowUnknownTags = true; + validateTag(badTag); + } + + expect(jsdoc.didLog(validate, 'error')).toBeFalse(); + }); + + it('does not log an error if the tag is not in the dictionary and conf.tags.allowUnknownTags includes it', () => { + function validate() { + env.conf.tags.allowUnknownTags = [badTag.title]; + validateTag(badTag); + } + + expect(jsdoc.didLog(validate, 'error')).toBeFalse(); + }); + + it('does not log an error for valid tags', () => { + function validate() { + validateTag(goodTag); + validateTag(goodTag2); + } + + expect(jsdoc.didLog(validate, 'error')).toBeFalse(); + }); + + it('logs an error if the tag has no text but mustHaveValue is true', () => { + function validate() { + const missingName = _.cloneDeep(goodTag); + + missingName.text = null; + validateTag(missingName); + } + + expect(jsdoc.didLog(validate, 'error')).toBeTrue(); + }); + + it('logs a warning if the tag has text but mustNotHaveValue is true', () => { + function validate() { + const missingText = _.cloneDeep(goodTag2); + + missingText.mustNotHaveValue = true; + missingText.text = missingText.text || 'asdf'; + validateTag(missingText); + } + + expect(jsdoc.didLog(validate, 'warn')).toBeTrue(); + }); + + it('logs a warning if the tag has a description but mustNotHaveDescription is true', () => { + function validate() { + validateTag(badTag2); + } + + expect(jsdoc.didLog(validate, 'warn')).toBeTrue(); + }); + + it('logs meta.comment when present', () => { + const bus = new EventBus('jsdoc'); + const events = []; + + bus.once('logger:error', (e) => events.push(e)); + env.conf.tags.allowUnknownTags = false; + validateTag(badTag); + + expect(events[0]).toContain(meta.comment); + }); + }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/template.js b/packages/jsdoc/test/specs/jsdoc/template.js index a79e4b36..c15edcf1 100644 --- a/packages/jsdoc/test/specs/jsdoc/template.js +++ b/packages/jsdoc/test/specs/jsdoc/template.js @@ -1,3 +1,3 @@ xdescribe('jsdoc/template', () => { - // TODO + // TODO }); diff --git a/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js b/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js index 9dad4af3..a6551fec 100644 --- a/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js +++ b/packages/jsdoc/test/specs/jsdoc/util/templateHelper.js @@ -1,1717 +1,1750 @@ /* eslint-disable quotes */ const hasOwnProp = Object.prototype.hasOwnProperty; -describe("jsdoc/util/templateHelper", () => { - const _ = require('lodash'); - const dictionary = require('jsdoc/tag/dictionary'); - const doclet = require('jsdoc/doclet'); - const env = require('jsdoc/env'); - const helper = require('jsdoc/util/templateHelper'); - const { taffy } = require('taffydb'); +describe('jsdoc/util/templateHelper', () => { + const _ = require('lodash'); + const dictionary = require('jsdoc/tag/dictionary'); + const doclet = require('jsdoc/doclet'); + const env = require('jsdoc/env'); + const helper = require('jsdoc/util/templateHelper'); + const { taffy } = require('taffydb'); - helper.registerLink('test', 'path/to/test.html'); + helper.registerLink('test', 'path/to/test.html'); - it("should exist", () => { - expect(helper).toBeObject(); + it('should exist', () => { + expect(helper).toBeObject(); + }); + + it("should export a 'globalName' property", () => { + expect(helper.globalName).toBeString(); + }); + + it("should export a 'fileExtension' property", () => { + expect(helper.fileExtension).toBeString(); + }); + + it("should export a 'SCOPE_TO_PUNC' property", () => { + expect(helper.SCOPE_TO_PUNC).toBeObject(); + }); + + it("should export a 'getUniqueFilename' function", () => { + expect(helper.getUniqueFilename).toBeFunction(); + }); + + it("should export a 'getUniqueId' function", () => { + expect(helper.getUniqueId).toBeFunction(); + }); + + it("should export a 'longnameToUrl' property", () => { + expect(helper.longnameToUrl).toBeObject(); + }); + + it("should export a 'linkto' function", () => { + expect(helper.linkto).toBeFunction(); + }); + + it("should export an 'htmlsafe' function", () => { + expect(helper.htmlsafe).toBeFunction(); + }); + + it("should export a 'find' function", () => { + expect(helper.find).toBeFunction(); + }); + + it("should export a 'getMembers' function", () => { + expect(helper.getMembers).toBeFunction(); + }); + + it("should export a 'getAttribs' function", () => { + expect(helper.getAttribs).toBeFunction(); + }); + + it("should export a 'getSignatureTypes' function", () => { + expect(helper.getSignatureTypes).toBeFunction(); + }); + + it("should export a 'getSignatureParams' function", () => { + expect(helper.getSignatureParams).toBeFunction(); + }); + + it("should export a 'getSignatureReturns' function", () => { + expect(helper.getSignatureReturns).toBeFunction(); + }); + + it("should export a 'getAncestors' function", () => { + expect(helper.getAncestors).toBeFunction(); + }); + + it("should export a 'getAncestorLinks' function", () => { + expect(helper.getAncestorLinks).toBeFunction(); + }); + + it("should export a 'addEventListeners' function", () => { + expect(helper.addEventListeners).toBeFunction(); + }); + + it("should export a 'prune' function", () => { + expect(helper.prune).toBeFunction(); + }); + + it("should export a 'registerLink' function", () => { + expect(helper.registerLink).toBeFunction(); + }); + + it("should export a 'resolveLinks' function", () => { + expect(helper.resolveLinks).toBeFunction(); + }); + + it("should export a 'resolveAuthorLinks' function", () => { + expect(helper.resolveAuthorLinks).toBeFunction(); + }); + + it("should export a 'createLink' function", () => { + expect(helper.createLink).toBeFunction(); + }); + + it('should export a "longnamesToTree" function', () => { + expect(helper.longnamesToTree).toBeFunction(); + }); + + describe('globalName', () => { + it("should equal 'global'", () => { + expect(helper.globalName).toBe('global'); + }); + }); + + describe('fileExtension', () => { + it("should equal '.html'", () => { + expect(helper.fileExtension).toBe('.html'); + }); + }); + + describe('SCOPE_TO_PUNC', () => { + it("should map 'static' to '.', 'inner', to '~', 'instance' to '#'", () => { + expect(helper.SCOPE_TO_PUNC).toEqual({ + static: '.', + inner: '~', + instance: '#', + }); + }); + }); + + describe('getUniqueFilename', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - it("should export a 'globalName' property", () => { - expect(helper.globalName).toBeString(); + // TODO: needs more tests for unusual values and things that get special treatment (such as + // inner members) + it('should convert a simple string into the string plus the default extension', () => { + const filename = helper.getUniqueFilename('BackusNaur'); + + expect(filename).toBe('BackusNaur.html'); }); - it("should export a 'fileExtension' property", () => { - expect(helper.fileExtension).toBeString(); + it('should replace slashes with underscores', () => { + const filename = helper.getUniqueFilename('tick/tock'); + + expect(filename).toBe('tick_tock.html'); }); - it("should export a 'SCOPE_TO_PUNC' property", () => { - expect(helper.SCOPE_TO_PUNC).toBeObject(); + it('should replace other problematic characters with underscores', () => { + const filename = helper.getUniqueFilename('a very strange \\/?*:|\'"<> filename'); + + expect(filename).toBe('a very strange __________ filename.html'); }); - it("should export a 'getUniqueFilename' function", () => { - expect(helper.getUniqueFilename).toBeFunction(); + it('should not allow a filename to start with an underscore', () => { + expect(helper.getUniqueFilename('')).toBe('-_.html'); }); - it("should export a 'getUniqueId' function", () => { - expect(helper.getUniqueId).toBeFunction(); + it('should not return the same filename twice', () => { + const name = 'polymorphic'; + const filename1 = helper.getUniqueFilename(name); + const filename2 = helper.getUniqueFilename(name); + + expect(filename1).not.toBe(filename2); }); - it("should export a 'longnameToUrl' property", () => { - expect(helper.longnameToUrl).toBeObject(); + it('should not consider the same name with different letter case to be unique', () => { + const camel = 'myJavaScriptIdentifier'; + const pascal = 'MyJavaScriptIdentifier'; + const filename1 = helper.getUniqueFilename(camel); + const filename2 = helper.getUniqueFilename(pascal); + + expect(filename1.toLowerCase()).not.toBe(filename2.toLowerCase()); }); - it("should export a 'linkto' function", () => { - expect(helper.linkto).toBeFunction(); + it('should remove variations from the longname before generating the filename', () => { + const filename = helper.getUniqueFilename('MyClass(foo, bar)'); + + expect(filename).toBe('MyClass.html'); }); - it("should export an 'htmlsafe' function", () => { - expect(helper.htmlsafe).toBeFunction(); + it('should generate the correct filename for built-in namespaces', () => { + const filenameEvent = helper.getUniqueFilename('event:userDidSomething'); + const filenameExternal = helper.getUniqueFilename('external:NotInThisPackage'); + const filenameModule = helper.getUniqueFilename('module:some/sort/of/module'); + const filenamePackage = helper.getUniqueFilename('package:node-solve-all-your-problems'); + + expect(filenameEvent).toBe('event-userDidSomething.html'); + expect(filenameExternal).toBe('external-NotInThisPackage.html'); + expect(filenameModule).toBe('module-some_sort_of_module.html'); + expect(filenamePackage).toBe('package-node-solve-all-your-problems.html'); }); - it("should export a 'find' function", () => { - expect(helper.find).toBeFunction(); + it('should generate the correct filename for user-specified namespaces', () => { + let filename; + const dict = new dictionary.Dictionary(); + + dict.defineTag('anaphylaxis', { + isNamespace: true, + }); + doclet._replaceDictionary(dict); + + filename = helper.getUniqueFilename('anaphylaxis:peanut'); + + expect(filename).toBe('anaphylaxis-peanut.html'); + }); + }); + + describe('getUniqueId', () => { + it('should return the provided string in normal cases', () => { + const id = helper.getUniqueId('futon.html', 'backrest'); + + expect(id).toBe('backrest'); }); - it("should export a 'getMembers' function", () => { - expect(helper.getMembers).toBeFunction(); + it('should return an empty string if no base ID is provided', () => { + const id = helper.getUniqueId('futon.html', ''); + + expect(id).toBe(''); }); - it("should export a 'getAttribs' function", () => { - expect(helper.getAttribs).toBeFunction(); + it('should remove whitespace characters', () => { + const id = helper.getUniqueId('futon.html', 'a very long identifier'); + + expect(id).toBe('averylongidentifier'); }); - it("should export a 'getSignatureTypes' function", () => { - expect(helper.getSignatureTypes).toBeFunction(); + it('should not return the same ID twice for a given file', () => { + const filename = 'futon.html'; + const name = 'polymorphic'; + const id1 = helper.getUniqueId(filename, name); + const id2 = helper.getUniqueId(filename, name); + + expect(id1).not.toBe(id2); }); - it("should export a 'getSignatureParams' function", () => { - expect(helper.getSignatureParams).toBeFunction(); + it('should allow duplicate IDs if they are in different files', () => { + const name = 'magnificence'; + const id1 = helper.getUniqueId('supersensational.html', name); + const id2 = helper.getUniqueId('razzledazzle.html', name); + + expect(id1).toBe(id2); }); - it("should export a 'getSignatureReturns' function", () => { - expect(helper.getSignatureReturns).toBeFunction(); + it('should not consider the same name with different letter case to be unique', () => { + const camel = 'myJavaScriptIdentifier'; + const pascal = 'MyJavaScriptIdentifier'; + const filename = 'mercutio.html'; + const id1 = helper.getUniqueId(filename, camel); + const id2 = helper.getUniqueId(filename, pascal); + + expect(id1.toLowerCase()).not.toBe(id2.toLowerCase()); + }); + }); + + describe('longnameToUrl', () => { + afterEach(() => { + delete helper.longnameToUrl.foo2; + delete helper.longnameToUrl.MySymbol; }); - it("should export a 'getAncestors' function", () => { - expect(helper.getAncestors).toBeFunction(); + it('is an object', () => { + expect(typeof helper.longnameToUrl).toBe('object'); }); - it("should export a 'getAncestorLinks' function", () => { - expect(helper.getAncestorLinks).toBeFunction(); + it('has an entry added into it by calling registerLink', () => { + helper.registerLink('MySymbol', 'asdf.html'); + + expect(helper.longnameToUrl.MySymbol).toBeDefined(); + expect(helper.longnameToUrl.MySymbol).toBe('asdf.html'); }); - it("should export a 'addEventListeners' function", () => { - expect(helper.addEventListeners).toBeFunction(); + it('adding an entry to it allows me to link with linkto', () => { + helper.longnameToUrl.foo2 = 'bar.html'; + + expect(helper.linkto('foo2')).toBe('foo2'); + }); + }); + + describe('linkto', () => { + beforeEach(() => { + helper.longnameToUrl.linktoTest = 'test.html'; + helper.longnameToUrl.LinktoFakeClass = 'fakeclass.html'; + helper.longnameToUrl['Foo#bar(baz)'] = 'foo-bar-baz.html'; }); - it("should export a 'prune' function", () => { - expect(helper.prune).toBeFunction(); + afterEach(() => { + delete helper.longnameToUrl.linktoTest; + delete helper.longnameToUrl.LinktoFakeClass; + delete helper.longnameToUrl['Foo#bar(baz)']; }); - it("should export a 'registerLink' function", () => { - expect(helper.registerLink).toBeFunction(); + it('returns the longname if only the longname is specified and has no URL', () => { + const link = helper.linkto('example'); + + expect(link).toBe('example'); }); - it("should export a 'resolveLinks' function", () => { - expect(helper.resolveLinks).toBeFunction(); + it('returns the link text if only the link text is specified', () => { + const link = helper.linkto(null, 'link text'); + + expect(link).toBe('link text'); }); - it("should export a 'resolveAuthorLinks' function", () => { - expect(helper.resolveAuthorLinks).toBeFunction(); + it( + 'returns the link text if the longname does not have a URL, and both the longname and ' + + 'link text are specified', + () => { + const link = helper.linkto('example', 'link text'); + + expect(link).toBe('link text'); + } + ); + + it('uses the longname as the link text if no link text is provided', () => { + const link = helper.linkto('linktoTest'); + + expect(link).toBe('linktoTest'); }); - it("should export a 'createLink' function", () => { - expect(helper.createLink).toBeFunction(); + it('uses the link text if it is specified', () => { + const link = helper.linkto('linktoTest', 'link text'); + + expect(link).toBe('link text'); }); - it('should export a "longnamesToTree" function', () => { - expect(helper.longnamesToTree).toBeFunction(); + it('includes a "class" attribute in the link if a class is specified', () => { + const link = helper.linkto('linktoTest', 'link text', 'myclass'); + + expect(link).toBe('link text'); }); - describe("globalName", () => { - it("should equal 'global'", () => { - expect(helper.globalName).toBe('global'); - }); + it('is careful with longnames that are reserved words in JS', () => { + // we don't have a registered link for 'constructor' so it should return the text 'link text'. + const link = helper.linkto('constructor', 'link text'); + + expect(link).toBe('link text'); }); - describe("fileExtension", () => { - it("should equal '.html'", () => { - expect(helper.fileExtension).toBe('.html'); - }); + it('works correctly with type applications if only the longname is specified', () => { + const link = helper.linkto('Array.'); + + expect(link).toBe('Array.<LinktoFakeClass>'); }); - describe("SCOPE_TO_PUNC", () => { - it("should map 'static' to '.', 'inner', to '~', 'instance' to '#'", () => { - expect(helper.SCOPE_TO_PUNC).toEqual({ - static: '.', - inner: '~', - instance: '#' - }); - }); + it('works correctly with type applications if a class is not specified', () => { + const link = helper.linkto('Array.', 'link text'); + + expect(link).toBe('Array.<LinktoFakeClass>'); }); - describe("getUniqueFilename", () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('works correctly with type applications if a class is specified', () => { + const link = helper.linkto('Array.', 'link text', 'myclass'); - // TODO: needs more tests for unusual values and things that get special treatment (such as - // inner members) - it('should convert a simple string into the string plus the default extension', () => { - const filename = helper.getUniqueFilename('BackusNaur'); - - expect(filename).toBe('BackusNaur.html'); - }); - - it('should replace slashes with underscores', () => { - const filename = helper.getUniqueFilename('tick/tock'); - - expect(filename).toBe('tick_tock.html'); - }); - - it('should replace other problematic characters with underscores', () => { - const filename = helper.getUniqueFilename('a very strange \\/?*:|\'"<> filename'); - - expect(filename).toBe('a very strange __________ filename.html'); - }); - - it('should not allow a filename to start with an underscore', () => { - expect( helper.getUniqueFilename('') ).toBe('-_.html'); - }); - - it('should not return the same filename twice', () => { - const name = 'polymorphic'; - const filename1 = helper.getUniqueFilename(name); - const filename2 = helper.getUniqueFilename(name); - - expect(filename1).not.toBe(filename2); - }); - - it('should not consider the same name with different letter case to be unique', () => { - const camel = 'myJavaScriptIdentifier'; - const pascal = 'MyJavaScriptIdentifier'; - const filename1 = helper.getUniqueFilename(camel); - const filename2 = helper.getUniqueFilename(pascal); - - expect( filename1.toLowerCase() ).not.toBe( filename2.toLowerCase() ); - }); - - it('should remove variations from the longname before generating the filename', () => { - const filename = helper.getUniqueFilename('MyClass(foo, bar)'); - - expect(filename).toBe('MyClass.html'); - }); - - it('should generate the correct filename for built-in namespaces', () => { - const filenameEvent = helper.getUniqueFilename('event:userDidSomething'); - const filenameExternal = helper.getUniqueFilename('external:NotInThisPackage'); - const filenameModule = helper.getUniqueFilename('module:some/sort/of/module'); - const filenamePackage = helper.getUniqueFilename('package:node-solve-all-your-problems'); - - expect(filenameEvent).toBe('event-userDidSomething.html'); - expect(filenameExternal).toBe('external-NotInThisPackage.html'); - expect(filenameModule).toBe('module-some_sort_of_module.html'); - expect(filenamePackage).toBe('package-node-solve-all-your-problems.html'); - }); - - it('should generate the correct filename for user-specified namespaces', () => { - let filename; - const dict = new dictionary.Dictionary(); - - dict.defineTag('anaphylaxis', { - isNamespace: true - }); - doclet._replaceDictionary(dict); - - filename = helper.getUniqueFilename('anaphylaxis:peanut'); - - expect(filename).toBe('anaphylaxis-peanut.html'); - }); + expect(link).toBe( + 'Array.<LinktoFakeClass' + '>' + ); }); - describe('getUniqueId', () => { - it('should return the provided string in normal cases', () => { - const id = helper.getUniqueId('futon.html', 'backrest'); + it('works correctly with type applications that include a type union', () => { + const link = helper.linkto('Array.<(linktoTest|LinktoFakeClass)>', 'link text'); - expect(id).toBe('backrest'); - }); - - it('should return an empty string if no base ID is provided', () => { - const id = helper.getUniqueId('futon.html', ''); - - expect(id).toBe(''); - }); - - it('should remove whitespace characters', () => { - const id = helper.getUniqueId('futon.html', 'a very long identifier'); - - expect(id).toBe('averylongidentifier'); - }); - - it('should not return the same ID twice for a given file', () => { - const filename = 'futon.html'; - const name = 'polymorphic'; - const id1 = helper.getUniqueId(filename, name); - const id2 = helper.getUniqueId(filename, name); - - expect(id1).not.toBe(id2); - }); - - it('should allow duplicate IDs if they are in different files', () => { - const name = 'magnificence'; - const id1 = helper.getUniqueId('supersensational.html', name); - const id2 = helper.getUniqueId('razzledazzle.html', name); - - expect(id1).toBe(id2); - }); - - it('should not consider the same name with different letter case to be unique', () => { - const camel = 'myJavaScriptIdentifier'; - const pascal = 'MyJavaScriptIdentifier'; - const filename = 'mercutio.html'; - const id1 = helper.getUniqueId(filename, camel); - const id2 = helper.getUniqueId(filename, pascal); - - expect( id1.toLowerCase() ).not.toBe( id2.toLowerCase() ); - }); + expect(link).toBe( + 'Array.<(linktoTest|' + + 'LinktoFakeClass)>' + ); }); - describe("longnameToUrl", () => { - afterEach(() => { - delete helper.longnameToUrl.foo2; - delete helper.longnameToUrl.MySymbol; - }); + it('works correctly with type unions that are not enclosed in parentheses', () => { + const link = helper.linkto('linktoTest|LinktoFakeClass', 'link text'); - it("is an object", () => { - expect(typeof helper.longnameToUrl).toBe('object'); - }); - - it("has an entry added into it by calling registerLink", () => { - helper.registerLink('MySymbol', 'asdf.html'); - - expect(helper.longnameToUrl.MySymbol).toBeDefined(); - expect(helper.longnameToUrl.MySymbol).toBe('asdf.html'); - }); - - it("adding an entry to it allows me to link with linkto", () => { - helper.longnameToUrl.foo2 = 'bar.html'; - - expect(helper.linkto('foo2')).toBe('foo2'); - }); + expect(link).toBe( + '(linktoTest|' + 'LinktoFakeClass)' + ); }); - describe("linkto", () => { - beforeEach(() => { - helper.longnameToUrl.linktoTest = 'test.html'; - helper.longnameToUrl.LinktoFakeClass = 'fakeclass.html'; - helper.longnameToUrl['Foo#bar(baz)'] = 'foo-bar-baz.html'; - }); + it('does not try to parse a longname starting with as a type application', () => { + function linkto() { + helper.linkto('~foo'); + } - afterEach(() => { - delete helper.longnameToUrl.linktoTest; - delete helper.longnameToUrl.LinktoFakeClass; - delete helper.longnameToUrl['Foo#bar(baz)']; - }); - - it('returns the longname if only the longname is specified and has no URL', () => { - const link = helper.linkto('example'); - - expect(link).toBe('example'); - }); - - it('returns the link text if only the link text is specified', () => { - const link = helper.linkto(null, 'link text'); - - expect(link).toBe('link text'); - }); - - it('returns the link text if the longname does not have a URL, and both the longname and ' + - 'link text are specified', () => { - const link = helper.linkto('example', 'link text'); - - expect(link).toBe('link text'); - }); - - it('uses the longname as the link text if no link text is provided', () => { - const link = helper.linkto('linktoTest'); - - expect(link).toBe('linktoTest'); - }); - - it('uses the link text if it is specified', () => { - const link = helper.linkto('linktoTest', 'link text'); - - expect(link).toBe('link text'); - }); - - it('includes a "class" attribute in the link if a class is specified', () => { - const link = helper.linkto('linktoTest', 'link text', 'myclass'); - - expect(link).toBe('link text'); - }); - - it('is careful with longnames that are reserved words in JS', () => { - // we don't have a registered link for 'constructor' so it should return the text 'link text'. - const link = helper.linkto('constructor', 'link text'); - - expect(link).toBe('link text'); - }); - - it('works correctly with type applications if only the longname is specified', () => { - const link = helper.linkto('Array.'); - - expect(link).toBe('Array.<LinktoFakeClass>'); - }); - - it('works correctly with type applications if a class is not specified', () => { - const link = helper.linkto('Array.', 'link text'); - - expect(link).toBe('Array.<LinktoFakeClass>'); - }); - - it('works correctly with type applications if a class is specified', () => { - const link = helper.linkto('Array.', 'link text', 'myclass'); - - expect(link).toBe('Array.<LinktoFakeClass' + - '>'); - }); - - it('works correctly with type applications that include a type union', () => { - const link = helper.linkto('Array.<(linktoTest|LinktoFakeClass)>', 'link text'); - - expect(link).toBe('Array.<(linktoTest|' + - 'LinktoFakeClass)>'); - }); - - it('works correctly with type unions that are not enclosed in parentheses', () => { - const link = helper.linkto('linktoTest|LinktoFakeClass', 'link text'); - - expect(link).toBe('(linktoTest|' + - 'LinktoFakeClass)'); - }); - - it('does not try to parse a longname starting with as a type application', - () => { - function linkto() { - helper.linkto('~foo'); - } - - expect(jsdoc.didLog(linkto, 'error')).toBeFalse(); - }); - - it('does not treat a longname with a variation as a type application', () => { - const link = helper.linkto('Foo#bar(baz)', 'link text'); - - expect(link).toBe('link text'); - }); - - it('returns a link when a URL is specified', () => { - const link = helper.linkto('http://example.com'); - - expect(link).toBe('http://example.com'); - }); - - it('returns a link if a URL wrapped in angle brackets is specified', () => { - const link = helper.linkto(''); - - expect(link).toBe('http://example.com'); - }); - - it('returns a link with link text if a URL and link text are specified', () => { - const link = helper.linkto('http://example.com', 'text'); - - expect(link).toBe('text'); - }); - - it('returns a link with a fragment ID if a URL and fragment ID are specified', () => { - const link = helper.linkto('LinktoFakeClass', null, null, 'fragment'); - - expect(link).toBe('LinktoFakeClass'); - }); - - it('returns the original text if an HTML tag is specified', () => { - const text = 'text'; - const link = helper.linkto(text); - - expect(link).toBe(text); - }); - - it('returns the original text if an inline {@link} tag is specified', () => { - let link; - const text = '{@link Foo}'; - - function getLink() { - link = helper.linkto(text); - } - - // make sure we're not trying to parse the inline link as a type expression - expect(getLink).not.toThrow(); - // linkto doesn't process {@link} tags - expect(link).toBe(text); - }); + expect(jsdoc.didLog(linkto, 'error')).toBeFalse(); }); - describe("htmlsafe", () => { - it('should convert all occurences of < to <', () => { - const inp = '

    Potentially dangerous.

    '; - const out = helper.htmlsafe(inp); + it('does not treat a longname with a variation as a type application', () => { + const link = helper.linkto('Foo#bar(baz)', 'link text'); - expect(out).toBe('<h1>Potentially dangerous.</h1>'); - }); - - it('should convert all occurrences of & to &', () => { - const input = 'foo && bar & baz;'; - - expect( helper.htmlsafe(input) ).toBe('foo && bar & baz;'); - }); - - it('should not double-convert ampersands', () => { - const input = '

    Foo & Friends

    '; - - expect( helper.htmlsafe(input) ).toBe('<h1>Foo & Friends</h1>'); - }); - - it('should convert non-strings to strings', () => { - function htmlsafe() { - return helper.htmlsafe(false); - } - - expect(htmlsafe).not.toThrow(); - expect(htmlsafe()).toBe('false'); - }); + expect(link).toBe('link text'); }); - describe("find", () => { - const array = [ - // match - { - number: 2, - A: true - }, - // match - { - number: 1, - A: true, - D: 'hello', - Q: false - }, - // match - { - number: 3, - A: 'maybe', - squiggle: '?' - }, - // no match (number not in spec) - { - number: 4, - A: true - }, - // no match (missing top-level property) - { - A: true - } - ]; - const matches = array.slice(0, 3); - const spec = { - number: [1, 2, 3], - A: [true, 'maybe'] - }; + it('returns a link when a URL is specified', () => { + const link = helper.linkto('http://example.com'); - it('should find the requested items', () => { - expect( helper.find(taffy(array), spec) ).toEqual(matches); - }); + expect(link).toBe('http://example.com'); }); - // we can't use toEqual() because TaffyDB adds its own stuff to the array it returns. - // instead, we make sure arrays a and b are the same length, and that each object in - // array b has all the properties of the corresponding object in array a - // used for getMembers and prune tests. - function compareObjectArrays(a, b) { - expect(a.length).toEqual(b.length); + it('returns a link if a URL wrapped in angle brackets is specified', () => { + const link = helper.linkto(''); - for (let i = 0, l = a.length; i < l; i++) { - for (const prop in a[i]) { - if ( hasOwnProp.call(a[i], prop) ) { - expect(b[i][prop]).toBeDefined(); - expect(a[i][prop]).toEqual(b[i][prop]); - } - } + expect(link).toBe('http://example.com'); + }); + + it('returns a link with link text if a URL and link text are specified', () => { + const link = helper.linkto('http://example.com', 'text'); + + expect(link).toBe('text'); + }); + + it('returns a link with a fragment ID if a URL and fragment ID are specified', () => { + const link = helper.linkto('LinktoFakeClass', null, null, 'fragment'); + + expect(link).toBe('LinktoFakeClass'); + }); + + it('returns the original text if an HTML tag is specified', () => { + const text = 'text'; + const link = helper.linkto(text); + + expect(link).toBe(text); + }); + + it('returns the original text if an inline {@link} tag is specified', () => { + let link; + const text = '{@link Foo}'; + + function getLink() { + link = helper.linkto(text); + } + + // make sure we're not trying to parse the inline link as a type expression + expect(getLink).not.toThrow(); + // linkto doesn't process {@link} tags + expect(link).toBe(text); + }); + }); + + describe('htmlsafe', () => { + it('should convert all occurences of < to <', () => { + const inp = '

    Potentially dangerous.

    '; + const out = helper.htmlsafe(inp); + + expect(out).toBe('<h1>Potentially dangerous.</h1>'); + }); + + it('should convert all occurrences of & to &', () => { + const input = 'foo && bar & baz;'; + + expect(helper.htmlsafe(input)).toBe('foo && bar & baz;'); + }); + + it('should not double-convert ampersands', () => { + const input = '

    Foo & Friends

    '; + + expect(helper.htmlsafe(input)).toBe('<h1>Foo & Friends</h1>'); + }); + + it('should convert non-strings to strings', () => { + function htmlsafe() { + return helper.htmlsafe(false); + } + + expect(htmlsafe).not.toThrow(); + expect(htmlsafe()).toBe('false'); + }); + }); + + describe('find', () => { + const array = [ + // match + { + number: 2, + A: true, + }, + // match + { + number: 1, + A: true, + D: 'hello', + Q: false, + }, + // match + { + number: 3, + A: 'maybe', + squiggle: '?', + }, + // no match (number not in spec) + { + number: 4, + A: true, + }, + // no match (missing top-level property) + { + A: true, + }, + ]; + const matches = array.slice(0, 3); + const spec = { + number: [1, 2, 3], + A: [true, 'maybe'], + }; + + it('should find the requested items', () => { + expect(helper.find(taffy(array), spec)).toEqual(matches); + }); + }); + + // we can't use toEqual() because TaffyDB adds its own stuff to the array it returns. + // instead, we make sure arrays a and b are the same length, and that each object in + // array b has all the properties of the corresponding object in array a + // used for getMembers and prune tests. + function compareObjectArrays(a, b) { + expect(a.length).toEqual(b.length); + + for (let i = 0, l = a.length; i < l; i++) { + for (const prop in a[i]) { + if (hasOwnProp.call(a[i], prop)) { + expect(b[i][prop]).toBeDefined(); + expect(a[i][prop]).toEqual(b[i][prop]); } + } } - describe("getMembers", () => { - // instead parse a file from fixtures and verify it? - const classes = [ - // global - { - kind: 'class' - }, - // not global - { - kind: 'class', - memberof: 'SomeNamespace' - } - ]; - const externals = [ - { - kind: 'external', - name: 'foo' - } - ]; - const events = [ - { - kind: 'event' - } - ]; - const mixins = [ - { - kind: 'mixin' - } - ]; - const modules = [ - { - kind: 'module' - } - ]; - const namespaces = [ - { - kind: 'namespace' - } - ]; - const miscGlobal = [ - { - kind: 'function' - }, - { - kind: 'member' - }, - { - kind: 'constant' - }, - { - kind: 'typedef' - } - ]; - const miscNonGlobal = [ - { - kind: 'constant', - memberof: 'module:one/two' - }, - { - kind: 'function', - name: 'module:foo', - longname: 'module:foo' - }, - { - kind: 'member', - name: 'module:bar', - longname: 'module:bar' - } - ]; - const misc = miscGlobal.concat(miscNonGlobal); - const array = [ - ...classes, - ...externals, - ...events, - ...mixins, - ...modules, - ...namespaces, - ...misc - ]; - const data = taffy(array); - const members = helper.getMembers(data); + } + describe('getMembers', () => { + // instead parse a file from fixtures and verify it? + const classes = [ + // global + { + kind: 'class', + }, + // not global + { + kind: 'class', + memberof: 'SomeNamespace', + }, + ]; + const externals = [ + { + kind: 'external', + name: 'foo', + }, + ]; + const events = [ + { + kind: 'event', + }, + ]; + const mixins = [ + { + kind: 'mixin', + }, + ]; + const modules = [ + { + kind: 'module', + }, + ]; + const namespaces = [ + { + kind: 'namespace', + }, + ]; + const miscGlobal = [ + { + kind: 'function', + }, + { + kind: 'member', + }, + { + kind: 'constant', + }, + { + kind: 'typedef', + }, + ]; + const miscNonGlobal = [ + { + kind: 'constant', + memberof: 'module:one/two', + }, + { + kind: 'function', + name: 'module:foo', + longname: 'module:foo', + }, + { + kind: 'member', + name: 'module:bar', + longname: 'module:bar', + }, + ]; + const misc = miscGlobal.concat(miscNonGlobal); + const array = [ + ...classes, + ...externals, + ...events, + ...mixins, + ...modules, + ...namespaces, + ...misc, + ]; + const data = taffy(array); + const members = helper.getMembers(data); - // check the output object has properties as expected. - it("should have a 'classes' property", () => { - expect(members.classes).toBeArray(); - }); - - it("should have a 'externals' property", () => { - expect(members.externals).toBeArray(); - }); - - it("should have a 'events' property", () => { - expect(members.events).toBeArray(); - }); - - it("should have a 'globals' property", () => { - expect(members.globals).toBeArray(); - }); - - it("should have a 'mixins' property", () => { - expect(members.mixins).toBeArray(); - }); - - it("should have a 'modules' property", () => { - expect(members.modules).toBeArray(); - }); - - it("should have a 'namespaces' property", () => { - expect(members.namespaces).toBeArray(); - }); - - // check that things were found properly. - it("classes are detected", () => { - compareObjectArrays(classes, members.classes); - }); - - it("externals are detected", () => { - compareObjectArrays(externals, members.externals); - }); - - it("events are detected", () => { - compareObjectArrays(events, members.events); - }); - - it("mixins are detected", () => { - compareObjectArrays(mixins, members.mixins); - }); - - it("modules are detected", () => { - compareObjectArrays(modules, members.modules); - }); - - it("namespaces are detected", () => { - compareObjectArrays(namespaces, members.namespaces); - }); - - it("globals are detected", () => { - compareObjectArrays(miscGlobal, members.globals); - }); + // check the output object has properties as expected. + it("should have a 'classes' property", () => { + expect(members.classes).toBeArray(); }); - describe("getAttribs", () => { - let doc; - let attribs; + it("should have a 'externals' property", () => { + expect(members.externals).toBeArray(); + }); - it('should return an array', () => { - doc = new doclet.Doclet('/** ljklajsdf */', {}); - attribs = helper.getAttribs(doc); + it("should have a 'events' property", () => { + expect(members.events).toBeArray(); + }); - expect(attribs).toBeEmptyArray(); - }); + it("should have a 'globals' property", () => { + expect(members.globals).toBeArray(); + }); - // tests is an object of test[doclet src] = - // if false, we expect attribs to either not contain anything in whatNotToContain, - // or be empty (if whatNotToContain was not provided). - function doTests(tests, whatNotToContain) { - for (const src in tests) { - if ( hasOwnProp.call(tests, src) ) { - doc = new doclet.Doclet(`/** ${src} */`, {}); - attribs = helper.getAttribs(doc); + it("should have a 'mixins' property", () => { + expect(members.mixins).toBeArray(); + }); - if (tests[src]) { - expect(attribs).toContain(tests[src]); - } else if (Array.isArray(whatNotToContain)) { - for (let i = 0; i < whatNotToContain.length; ++i) { - expect(attribs).not.toContain(whatNotToContain[i]); - } - } else { - expect(attribs.length).toBe(0); - } - } + it("should have a 'modules' property", () => { + expect(members.modules).toBeArray(); + }); + + it("should have a 'namespaces' property", () => { + expect(members.namespaces).toBeArray(); + }); + + // check that things were found properly. + it('classes are detected', () => { + compareObjectArrays(classes, members.classes); + }); + + it('externals are detected', () => { + compareObjectArrays(externals, members.externals); + }); + + it('events are detected', () => { + compareObjectArrays(events, members.events); + }); + + it('mixins are detected', () => { + compareObjectArrays(mixins, members.mixins); + }); + + it('modules are detected', () => { + compareObjectArrays(modules, members.modules); + }); + + it('namespaces are detected', () => { + compareObjectArrays(namespaces, members.namespaces); + }); + + it('globals are detected', () => { + compareObjectArrays(miscGlobal, members.globals); + }); + }); + + describe('getAttribs', () => { + let doc; + let attribs; + + it('should return an array', () => { + doc = new doclet.Doclet('/** ljklajsdf */', {}); + attribs = helper.getAttribs(doc); + + expect(attribs).toBeEmptyArray(); + }); + + // tests is an object of test[doclet src] = + // if false, we expect attribs to either not contain anything in whatNotToContain, + // or be empty (if whatNotToContain was not provided). + function doTests(tests, whatNotToContain) { + for (const src in tests) { + if (hasOwnProp.call(tests, src)) { + doc = new doclet.Doclet(`/** ${src} */`, {}); + attribs = helper.getAttribs(doc); + + if (tests[src]) { + expect(attribs).toContain(tests[src]); + } else if (Array.isArray(whatNotToContain)) { + for (let i = 0; i < whatNotToContain.length; ++i) { + expect(attribs).not.toContain(whatNotToContain[i]); } + } else { + expect(attribs.length).toBe(0); + } } + } + } - it('should detect if a doclet is virtual', () => { - const tests = { - 'My constant. \n @virtual': 'abstract', - 'asdf': false - }; + it('should detect if a doclet is virtual', () => { + const tests = { + 'My constant. \n @virtual': 'abstract', + asdf: false, + }; - doTests(tests); - }); - - it("should detect if a doclet's access is not public", () => { - const tests = {'@private': 'private', - '@access private': 'private', - '@protected': 'protected', - '@access protected': 'protected', - '@public': false, - '@access public': false, - 'asdf': false - }; - - doTests(tests); - }); - - it("should detect if a doclet's scope is inner or static AND it is a function or member or constant", () => { - const tests = { - // by default these are members - '@inner': 'inner', - '@instance': false, - '@global': false, - '@static': 'static', - '@name Asdf.fdsa': 'static', - '@name Outer~inner': 'inner', - '@name Fdsa#asdf': false, - '@name .log': false, - // some tests with functions and constants - '@const Asdf#FOO': false, - '@const Asdf\n@inner': 'inner', - '@function Asdf#myFunction': false, - '@function Fdsa.MyFunction': 'static', - '@function Fdsa': false, - // these are not functions or members or constants, they should not have their scope recorded. - '@namespace Fdsa\n@inner': false, - '@class asdf': false - }; - - doTests(tests, ['inner', 'static', 'global', 'instance']); - }); - - it("should detect if a doclet is readonly (and its kind is 'member')", () => { - const tests = { - 'asdf\n @readonly': 'readonly', - 'asdf': false, - '@name Fdsa#foo\n@readonly': 'readonly', - // kind is not 'member'. - '@const asdf\n@readonly': 'constant', - '@function asdf\n@readonly': false, - '@function Asdf#bar\n@readonly': false - }; - - doTests(tests, 'readonly'); - }); - - it("should detect if the doclet is a for constant", () => { - const tests = { - 'Enum. @enum\n@constant': 'constant', - '@function Foo#BAR\n@const': 'constant', - '@const Asdf': 'constant' - }; - - doTests(tests, 'constant'); - }); - - it('should detect if a doclet is async', () => { - const tests = { '@async': 'async' }; - - doTests(tests, 'async'); - }); - - it('should detect if a doclet is a generator function', () => { - const tests = { '@generator': 'generator' }; - - doTests(tests, 'generator'); - }); - - it("should detect multiple attributes", () => { - const fdsaFoo = new doclet.Doclet('/** @const module:fdsa~FOO\n@readonly\n@private */', {}); - - attribs = helper.getAttribs(fdsaFoo); - - expect(attribs).toContain('private'); - // expect(attribs).toContain('readonly'); // kind is 'constant' not 'member'. - expect(attribs).toContain('constant'); - expect(attribs).toContain('inner'); - }); - - it('should return an empty array for null values', () => { - let emptyAttribs; - - function getAttribs() { - return helper.getAttribs(); - } - - expect(getAttribs).not.toThrow(); - - emptyAttribs = getAttribs(); - - expect(emptyAttribs).toBeEmptyArray(); - }); + doTests(tests); }); - describe("getSignatureTypes", () => { - afterEach(() => { - delete helper.longnameToUrl.MyClass; - }); + it("should detect if a doclet's access is not public", () => { + const tests = { + '@private': 'private', + '@access private': 'private', + '@protected': 'protected', + '@access protected': 'protected', + '@public': false, + '@access public': false, + asdf: false, + }; - // returns links to allowed types for a doclet. - it("returns an empty array if the doclet has no specified type", () => { - const doc = new doclet.Doclet('/** @const ASDF */', {}); - const types = helper.getSignatureTypes(doc); - - expect(types).toBeEmptyArray(); - }); - - it("returns a string array of the doclet's types", () => { - const doc = new doclet.Doclet('/** @const {number|Array.} ASDF */', {}); - const types = helper.getSignatureTypes(doc); - - expect(types).toBeArrayOfSize(2); - expect(types).toContain('number'); - expect(types).toContain(helper.htmlsafe('Array.')); - }); - - it("creates links for types if relevant", () => { - let doc; - let types; - - // make some links. - helper.longnameToUrl.MyClass = 'MyClass.html'; - - doc = new doclet.Doclet('/** @const {MyClass} ASDF */', {}); - types = helper.getSignatureTypes(doc); - - expect(types).toBeArrayOfSize(1); - expect(types).toContain('MyClass'); - }); - - it("uses the cssClass parameter for links if it is provided", () => { - let doc; - let types; - - // make some links. - helper.longnameToUrl.MyClass = 'MyClass.html'; - - doc = new doclet.Doclet('/** @const {MyClass} ASDF */', {}); - types = helper.getSignatureTypes(doc, 'myCSSClass'); - - expect(types).toBeArrayOfSize(1); - expect(types).toContain('MyClass'); - }); + doTests(tests); }); - describe("getSignatureParams", () => { - // retrieves parameter names. - // if css class is provided, optional parameters are wrapped in a with that class. - it("returns an empty array if the doclet has no specified type", () => { - const doc = new doclet.Doclet('/** @function myFunction */', {}); - const params = helper.getSignatureParams(doc); + it("should detect if a doclet's scope is inner or static AND it is a function or member or constant", () => { + const tests = { + // by default these are members + '@inner': 'inner', + '@instance': false, + '@global': false, + '@static': 'static', + '@name Asdf.fdsa': 'static', + '@name Outer~inner': 'inner', + '@name Fdsa#asdf': false, + '@name .log': false, + // some tests with functions and constants + '@const Asdf#FOO': false, + '@const Asdf\n@inner': 'inner', + '@function Asdf#myFunction': false, + '@function Fdsa.MyFunction': 'static', + '@function Fdsa': false, + // these are not functions or members or constants, they should not have their scope recorded. + '@namespace Fdsa\n@inner': false, + '@class asdf': false, + }; - expect(params).toBeEmptyArray(); - }); - - it("returns a string array of the doclet's parameter names", () => { - const doc = new doclet.Doclet('/** @function myFunction\n @param {string} foo - asdf. */', {}); - const params = helper.getSignatureParams(doc); - - expect(params).toBeArrayOfSize(1); - expect(params).toContain('foo'); - }); - - it("wraps optional parameters in if optClass is provided", () => { - const doc = new doclet.Doclet( - '/** @function myFunction\n' + - ' * @param {boolean} foo - explanation.\n' + - ' * @param {number} [bar=1] - another explanation.\n' + - ' * @param {string} [baz] - another explanation.\n' + - ' */', {}); - const params = helper.getSignatureParams(doc, 'cssClass'); - - expect(params).toBeArrayOfSize(3); - expect(params).toContain('foo'); - expect(params).toContain('bar'); - expect(params).toContain('baz'); - }); - - it("doesn't wrap optional parameters in if optClass is not provided", () => { - const doc = new doclet.Doclet( - '/** @function myFunction\n' + - ' * @param {boolean} foo - explanation.\n' + - ' * @param {number} [bar=1] - another explanation.\n' + - ' * @param {string} [baz] - another explanation.\n' + - ' */', {}); - const params = helper.getSignatureParams(doc); - - expect(params).toBeArrayOfSize(3); - expect(params).toContain('foo'); - expect(params).toContain('bar'); - expect(params).toContain('baz'); - }); + doTests(tests, ['inner', 'static', 'global', 'instance']); }); - describe("getSignatureReturns", () => { - afterEach(() => { - delete helper.longnameToUrl.MyClass; - }); + it("should detect if a doclet is readonly (and its kind is 'member')", () => { + const tests = { + 'asdf\n @readonly': 'readonly', + asdf: false, + '@name Fdsa#foo\n@readonly': 'readonly', + // kind is not 'member'. + '@const asdf\n@readonly': 'constant', + '@function asdf\n@readonly': false, + '@function Asdf#bar\n@readonly': false, + }; - it("returns a value with correctly escaped HTML", () => { - const mockDoclet = { - returns: [ - { - type: { - names: [ - 'Array.' - ] - } - } - ] - }; - const html = helper.getSignatureReturns(mockDoclet); - - expect(html).not.toContain('Array.'); - expect(html).toContain('Array.<string>'); - }); - - it("returns an empty array if the doclet has no returns", () => { - const doc = new doclet.Doclet('/** @function myFunction */', {}); - const returns = helper.getSignatureReturns(doc); - - expect(returns).toBeEmptyArray(); - }); - - it("returns an empty array if the doclet has @returns but with no type", () => { - const doc = new doclet.Doclet('/** @function myFunction\n@returns an interesting result.*/', {}); - const returns = helper.getSignatureReturns(doc); - - expect(returns).toBeEmptyArray(); - }); - - it('uses the value of the `yields` property', () => { - const doc = new doclet.Doclet('/** @yields {string} A string. */', {}); - const html = helper.getSignatureReturns(doc); - - expect(html).toContain('string'); - }); - - it('prefers `yields` over `returns`', () => { - const doc = new doclet.Doclet('/** @yields {string}\n@returns {number} */', {}); - const html = helper.getSignatureReturns(doc); - - expect(html).toContain('string'); - expect(html).not.toContain('number'); - }); - - it("creates links for return types if relevant", () => { - let doc; - let returns; - - // make some links. - helper.longnameToUrl.MyClass = 'MyClass.html'; - - doc = new doclet.Doclet('/** @function myFunction\n@returns {number|MyClass} an interesting result.*/', {}); - returns = helper.getSignatureReturns(doc); - - expect(returns).toBeArrayOfSize(2); - expect(returns).toContain('MyClass'); - expect(returns).toContain('number'); - }); - - it("uses the cssClass parameter for links if it is provided", () => { - let doc; - let returns; - - // make some links. - helper.longnameToUrl.MyClass = 'MyClass.html'; - - doc = new doclet.Doclet('/** @function myFunction\n@returns {number|MyClass} an interesting result.*/', {}); - returns = helper.getSignatureReturns(doc, 'myCssClass'); - - expect(returns).toBeArrayOfSize(2); - expect(returns).toContain('MyClass'); - expect(returns).toContain('number'); - }); + doTests(tests, 'readonly'); }); - xdescribe('getAncestors', () => { - // TODO + it('should detect if the doclet is a for constant', () => { + const tests = { + 'Enum. @enum\n@constant': 'constant', + '@function Foo#BAR\n@const': 'constant', + '@const Asdf': 'constant', + }; + + doTests(tests, 'constant'); }); - describe("getAncestorLinks", () => { - // make a hierarchy. - const lackeys = new doclet.Doclet('/** @member lackeys\n@memberof module:mafia/gangs.Sharks~Henchman\n@instance*/', {}); - const henchman = new doclet.Doclet('/** @class Henchman\n@memberof module:mafia/gangs.Sharks\n@inner */', {}); - const gang = new doclet.Doclet('/** @namespace module:mafia/gangs.Sharks */', {}); - const mafia = new doclet.Doclet('/** @module mafia/gangs */', {}); - const data = taffy([lackeys, henchman, gang, mafia]); + it('should detect if a doclet is async', () => { + const tests = { '@async': 'async' }; - afterEach(() => { - delete helper.longnameToUrl['module:mafia/gangs']; - delete helper.longnameToUrl['module:mafia/gangs.Sharks~Henchman']; - }); - - // register some links - it("returns an empty array if there are no ancestors", () => { - const links = helper.getAncestorLinks(data, mafia); - - expect(links).toBeEmptyArray(); - }); - - it("returns an array of ancestor names (with preceding punctuation) if there are ancestors, the direct ancestor with following punctuation too", () => { - let links = helper.getAncestorLinks(data, lackeys); - - expect(links).toBeArrayOfSize(3); - expect(links).toContain('~Henchman#'); - expect(links).toContain('.Sharks'); - expect(links).toContain('mafia/gangs'); - - links = helper.getAncestorLinks(data, henchman); - - expect(links).toBeArrayOfSize(2); - expect(links).toContain('.Sharks~'); - expect(links).toContain('mafia/gangs'); - - links = helper.getAncestorLinks(data, gang); - - expect(links).toBeArrayOfSize(1); - expect(links).toContain('mafia/gangs.'); - }); - - it("adds links if they exist", () => { - let links; - - // register some links - helper.longnameToUrl['module:mafia/gangs'] = 'mafia_gangs.html'; - helper.longnameToUrl['module:mafia/gangs.Sharks~Henchman'] = 'henchman.html'; - - links = helper.getAncestorLinks(data, lackeys); - - expect(links).toBeArrayOfSize(3); - expect(links).toContain('~Henchman#'); - expect(links).toContain('.Sharks'); - expect(links).toContain('mafia/gangs'); - }); - - it("adds cssClass to any link", () => { - let links; - - // register some links - helper.longnameToUrl['module:mafia/gangs'] = 'mafia_gangs.html'; - helper.longnameToUrl['module:mafia/gangs.Sharks~Henchman'] = 'henchman.html'; - - links = helper.getAncestorLinks(data, lackeys, 'myClass'); - - expect(links).toBeArrayOfSize(3); - expect(links).toContain('~Henchman#'); - expect(links).toContain('.Sharks'); - expect(links).toContain('mafia/gangs'); - }); + doTests(tests, 'async'); }); - describe("addEventListeners", () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/listenstag.js'); - const doclets = (taffy(_.cloneDeep(docSet.doclets))); - const ev = helper.find(doclets, {longname: 'module:myModule.event:MyEvent'})[0]; - const ev2 = helper.find(doclets, {longname: 'module:myModule~Events.event:Event2'})[0]; - const ev3 = helper.find(doclets, {longname: 'module:myModule#event:Event3'})[0]; + it('should detect if a doclet is a generator function', () => { + const tests = { '@generator': 'generator' }; - helper.addEventListeners(doclets); - - it("adds a 'listeners' array to events with the longnames of the listeners", () => { - expect(ev.listeners).toBeArrayOfSize(2); - expect(ev.listeners).toContain('module:myModule~MyHandler'); - expect(ev.listeners).toContain('module:myModule~AnotherHandler'); - - expect(ev2.listeners).toBeArrayOfSize(1); - expect(ev2.listeners).toContain('module:myModule~MyHandler'); - }); - - it("does not add listeners for events with no listeners", () => { - expect(ev3.listeners).toBeUndefined(); - }); - - it("does not make spurious doclets if something @listens to a non-existent symbol", () => { - expect(helper.find(doclets, {longname: 'event:fakeEvent'})).toBeEmptyArray(); - }); + doTests(tests, 'generator'); }); - describe("prune", () => { - const access = env.opts.access; - const priv = Boolean(env.opts.private); + it('should detect multiple attributes', () => { + const fdsaFoo = new doclet.Doclet('/** @const module:fdsa~FOO\n@readonly\n@private */', {}); - afterEach(() => { - env.opts.access = access; - env.opts.private = priv; - }); + attribs = helper.getAttribs(fdsaFoo); - const array = [ - // keep - {undocumented: false}, - // keep - {ignore: false}, - // keep - {memberof: 'SomeClass'}, - // prune - {undocumented: true}, - // prune - {ignore: true}, - // prune - {memberof: ''} - ]; - const keep = [ - // keep - {undocumented: false}, - // keep - {ignore: false}, - // keep - {memberof: 'SomeClass'} - ]; - const arrayPrivate = [ - // prune (unless env.opts.private is truthy) - {access: 'private'} - ]; - const arrayMixed = [ - {access: 'package'}, - {access: 'public'}, - {asdf: true}, - {access: 'protected'}, - {access: 'private'} - ]; - - it('should prune the correct members', () => { - const pruned = helper.prune( taffy(array) )().get(); - - compareObjectArrays(keep, pruned); - }); - - it('should prune private members if env.opts.private is falsy', () => { - let pruned; - - env.opts.private = false; - pruned = helper.prune( taffy(arrayPrivate) )().get(); - - compareObjectArrays([], pruned); - }); - - it('should only keep package-private members if env.opts.access only contains "package"', () => { - let pruned; - const keepPackage = [{access: 'package'}]; - - env.opts.access = 'package'; - pruned = helper.prune( taffy(arrayMixed) )().get(); - - compareObjectArrays(keepPackage, pruned); - }); - - it('should only keep public members if env.opts.access only contains "public"', () => { - let pruned; - const keepPublic = [{access: 'public'}]; - - env.opts.access = 'public'; - pruned = helper.prune( taffy(arrayMixed) )().get(); - - compareObjectArrays(keepPublic, pruned); - }); - - it('should only keep undefined members if env.opts.access only contains "undefined"', () => { - let pruned; - const keepUndefined = [{asdf: true}]; - - env.opts.access = 'undefined'; - pruned = helper.prune( taffy(arrayMixed) )().get(); - - compareObjectArrays(keepUndefined, pruned); - }); - - it('should only keep protected members if env.opts.access only contains "protected"', () => { - let pruned; - const keepProtected = [{access: 'protected'}]; - - env.opts.access = 'protected'; - pruned = helper.prune( taffy(arrayMixed) )().get(); - - compareObjectArrays(keepProtected, pruned); - }); - - it('should only keep private members if env.opts.access only contains "private"', () => { - let pruned; - const keepPrivate = [{access: 'private'}]; - - env.opts.access = 'private'; - pruned = helper.prune( taffy(arrayMixed) )().get(); - - compareObjectArrays(keepPrivate, pruned); - }); - - it('should keep public and protected members if env.opts.access contains "public" and "protected"', () => { - let pruned; - const keepPublicProtected = [{ - access: 'public' - }, { - access: 'protected' - }]; - - env.opts.access = ['public', 'protected']; - pruned = helper.prune( taffy(arrayMixed) )().get(); - - compareObjectArrays(keepPublicProtected, pruned); - }); - - it('should keep everything if env.opts.access contains "all"', () => { - let pruned; - - env.opts.access = 'all'; - pruned = helper.prune( taffy(arrayMixed) )().get(); - - compareObjectArrays(arrayMixed, pruned); - }); - - it('should not prune private members if env.opts.private is truthy', () => { - let pruned; - - env.opts.private = true; - pruned = helper.prune( taffy(arrayPrivate) )().get(); - - compareObjectArrays(arrayPrivate, pruned); - }); + expect(attribs).toContain('private'); + // expect(attribs).toContain('readonly'); // kind is 'constant' not 'member'. + expect(attribs).toContain('constant'); + expect(attribs).toContain('inner'); }); - describe("registerLink", () => { - afterEach(() => { - delete helper.longnameToUrl.MySymbol; - }); + it('should return an empty array for null values', () => { + let emptyAttribs; - it("adds an entry to exports.longnameToUrl", () => { - helper.longnameToUrl.MySymbol = 'asdf.html'; + function getAttribs() { + return helper.getAttribs(); + } - expect(helper.longnameToUrl.MySymbol).toBe('asdf.html'); - }); + expect(getAttribs).not.toThrow(); - it("allows linkto to work", () => { - helper.registerLink('MySymbol', 'asdf.html'); + emptyAttribs = getAttribs(); - expect(helper.linkto('MySymbol')).toBe('MySymbol'); - }); + expect(emptyAttribs).toBeEmptyArray(); + }); + }); + + describe('getSignatureTypes', () => { + afterEach(() => { + delete helper.longnameToUrl.MyClass; }); - describe("resolveLinks", () => { - let conf; + // returns links to allowed types for a doclet. + it('returns an empty array if the doclet has no specified type', () => { + const doc = new doclet.Doclet('/** @const ASDF */', {}); + const types = helper.getSignatureTypes(doc); - beforeEach(() => { - conf = _.cloneDeep(env.conf.templates); - }); - - afterEach(() => { - env.conf.templates = conf; - delete helper.longnameToUrl['my.long.namespace']; - }); - - it('should translate {@link test} into a HTML link.', () => { - const input = 'This is a {@link test}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a test.'); - }); - - it('should translate {@link unknown} into a simple text.', () => { - const input = 'This is a {@link unknown}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a unknown.'); - }); - - it('should translate {@link test} into a HTML links multiple times.', () => { - const input = 'This is a {@link test} and {@link test}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a test and test.'); - }); - - it('should translate [hello there]{@link test} into a HTML link with the custom content.', () => { - const input = 'This is a [hello there]{@link test}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a hello there.'); - }); - - it('should translate [dummy text] and [hello there]{@link test} into an HTML link with the custom content.', () => { - const input = 'This is [dummy text] and [hello there]{@link test}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is [dummy text] and hello there.'); - }); - - it('should translate [dummy text] and [more] and [hello there]{@link test} into an HTML link with the custom content.', () => { - const input = 'This is [dummy text] and [more] and [hello there]{@link test}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is [dummy text] and [more] and hello there.'); - }); - - it('should ignore [hello there].', () => { - const input = 'This is a [hello there].'; - const output = helper.resolveLinks(input); - - expect(output).toBe(input); - }); - - it('should translate http links in the tag', () => { - const input = 'Link to {@link http://github.com}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to http://github.com'); - }); - - it('should translate ftp links in the tag', () => { - const input = 'Link to {@link ftp://foo.bar}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to ftp://foo.bar'); - }); - - it('should allow pipe to be used as delimiter between href and text (external link)', () => { - const input = 'Link to {@link http://github.com|Github}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to Github'); - }); - - it('should allow pipe to be used as delimiter between href and text (symbol link)', () => { - const input = 'Link to {@link test|Test}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to Test'); - }); - - it('should allow first space to be used as delimiter between href and text (external link)', () => { - const input = 'Link to {@link http://github.com Github}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to Github'); - }); - - it('should allow first space to be used as delimiter between href and text (symbol link)', () => { - const input = 'Link to {@link test My Caption}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to My Caption'); - }); - - it('if pipe and space are present in link tag, use pipe as the delimiter', () => { - const input = 'Link to {@link test|My Caption}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to My Caption'); - }); - - it('Test of {@linkcode } which should be in monospace', () => { - const input = 'Link to {@linkcode test}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - it('Test of {@linkplain } which should be in normal font', () => { - const input = 'Link to {@linkplain test}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - it('should be careful with linking to links whose names are reserved JS keywords', () => { - const input = 'Link to {@link constructor}'; - const output = helper.resolveLinks(input); - - expect(output).toBe('Link to constructor'); - }); - - it('should allow linebreaks between link tag and content', () => { - const input = 'This is a {@link\ntest}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a test.'); - }); - - it('should allow linebreaks to separate url from link text', () => { - const input = 'This is a {@link\ntest\ntest}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a test.'); - }); - - it('should normalize additional newlines to spaces', () => { - const input = 'This is a {@link\ntest\ntest\n\ntest}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a test test.'); - }); - - it('should allow tabs between link tag and content', () => { - const input = 'This is a {@link\ttest}.'; - const output = helper.resolveLinks(input); - - expect(output).toBe('This is a test.'); - }); - - // conf.monospaceLinks. check that - // a) it works - it('if conf.monospaceLinks is true, all {@link} should be monospace', () => { - const input = 'Link to {@link test}'; - let output; - - env.conf.templates.monospaceLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - // b) linkcode and linkplain are still respected - it('if conf.monospaceLinks is true, all {@linkcode} should still be monospace', () => { - const input = 'Link to {@linkcode test}'; - let output; - - env.conf.templates.monospaceLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - it('if conf.monospaceLinks is true, all {@linkplain} should still be plain', () => { - const input = 'Link to {@linkplain test}'; - let output; - - env.conf.templates.monospaceLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - // conf.cleverLinks. check that - // a) it works - it('if conf.cleverLinks is true, {@link symbol} should be in monospace', () => { - const input = 'Link to {@link test}'; - let output; - - env.conf.templates.cleverLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - it('if conf.cleverLinks is true, {@link URL} should be in plain text', () => { - const input = 'Link to {@link http://github.com}'; - let output; - - env.conf.templates.cleverLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe('Link to http://github.com'); - }); - - // b) linkcode and linkplain are still respected - it('if conf.cleverLinks is true, all {@linkcode} should still be clever', () => { - const input = 'Link to {@linkcode test}'; - let output; - - env.conf.templates.cleverLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - it('if conf.cleverLinks is true, all {@linkplain} should still be plain', () => { - const input = 'Link to {@linkplain test}'; - let output; - - env.conf.templates.cleverLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe('Link to test'); - }); - - // c) if monospaceLinks is additionally `true` it is ignored in favour - // of cleverLinks - it('if conf.cleverLinks is true and so is conf.monospaceLinks, cleverLinks overrides', () => { - const input = 'Link to {@link test} and {@link http://github.com}'; - let output; - - env.conf.templates.cleverLinks = true; - env.conf.templates.monospaceLinks = true; - output = helper.resolveLinks(input); - - expect(output).toBe( - 'Link to test and ' + - 'http://github.com' - ); - }); - - it('if conf.useShortNamesInLinks is true, it uses the short name in links', () => { - const input = 'Link to {@link my.long.namespace}'; - let output; - - env.conf.templates.useShortNamesInLinks = true; - helper.registerLink('my.long.namespace', 'asdf.html'); - output = helper.resolveLinks(input); - - expect(output).toBe('Link to namespace'); - }); + expect(types).toBeEmptyArray(); }); - describe("createLink", () => { - it('should create a url for a simple global.', () => { - const mockDoclet = { - kind: 'function', - longname: 'foo', - name: 'foo', - scope: 'global' - }; - const url = helper.createLink(mockDoclet); + it("returns a string array of the doclet's types", () => { + const doc = new doclet.Doclet('/** @const {number|Array.} ASDF */', {}); + const types = helper.getSignatureTypes(doc); - expect(url).toBe('global.html#foo'); - }); - - it('should create a url for a namespace.', () => { - const mockDoclet = { - kind: 'namespace', - longname: 'foo', - name: 'foo' - }; - const url = helper.createLink(mockDoclet); - - expect(url).toBe('foo.html'); - }); - - it('should create a url for a member of a namespace.', () => { - const mockDoclet = { - kind: 'function', - longname: 'ns.foo', - name: 'foo', - memberof: 'ns' - }; - const url = helper.createLink(mockDoclet); - - expect(url).toBe('ns.html#foo'); - }); - - const nestedNamespaceDoclet = { - kind: 'function', - longname: 'ns1.ns2.foo', - name: 'foo', - memberof: 'ns1.ns2' - }; - let nestedNamespaceUrl; - - it('should create a url for a member of a nested namespace.', () => { - nestedNamespaceUrl = helper.createLink(nestedNamespaceDoclet); - - expect(nestedNamespaceUrl).toBe('ns1.ns2.html#foo'); - }); - - it('should return the same value when called twice with the same doclet.', () => { - const newUrl = helper.createLink(nestedNamespaceDoclet); - - expect(newUrl).toBe(nestedNamespaceUrl); - }); - - it('should create a url for a name with invalid characters.', () => { - const mockDoclet = { - kind: 'function', - longname: 'ns1."!"."*foo"', - name: '"*foo"', - memberof: 'ns1."!"' - }; - const url = helper.createLink(mockDoclet); - - expect(url).toEqual('ns1._!_.html#%22*foo%22'); - }); - - it('should create a url for a function that is the only symbol exported by a module.', - () => { - const mockDoclet = { - kind: 'function', - longname: 'module:bar', - name: 'module:bar' - }; - const url = helper.createLink(mockDoclet); - - expect(url).toEqual('module-bar.html'); - }); - - it('should create a url for a doclet with the wrong kind (caused by incorrect JSDoc tags', () => { - const moduleDoclet = { - kind: 'module', - longname: 'module:baz', - name: 'module:baz' - }; - const badDoclet = { - kind: 'member', - longname: 'module:baz', - name: 'module:baz' - }; - const moduleDocletUrl = helper.createLink(moduleDoclet); - const badDocletUrl = helper.createLink(badDoclet); - - expect(moduleDocletUrl).toBe('module-baz.html'); - expect(badDocletUrl).toBe('module-baz.html'); - }); - - it('should create a url for a function that is a member of a doclet with the wrong kind', () => { - const badModuleDoclet = { - kind: 'member', - longname: 'module:qux', - name: 'module:qux' - }; - const memberDoclet = { - kind: 'function', - name: 'frozzle', - memberof: 'module:qux', - scope: 'instance', - longname: 'module:qux#frozzle' - }; - const badModuleDocletUrl = helper.createLink(badModuleDoclet); - const memberDocletUrl = helper.createLink(memberDoclet); - - expect(badModuleDocletUrl).toBe('module-qux.html'); - expect(memberDocletUrl).toBe('module-qux.html#frozzle'); - }); - - it('should include the scope punctuation in the fragment ID for static members', () => { - const functionDoclet = { - kind: 'function', - longname: 'Milk.pasteurize', - name: 'pasteurize', - memberof: 'Milk', - scope: 'static' - }; - const docletUrl = helper.createLink(functionDoclet); - - expect(docletUrl).toBe('Milk.html#.pasteurize'); - }); - - it('should include the scope punctuation in the fragment ID for inner members', () => { - const functionDoclet = { - kind: 'function', - longname: 'Milk~removeSticksAndLeaves', - name: 'removeSticksAndLeaves', - memberof: 'Milk', - scope: 'inner' - }; - const docletUrl = helper.createLink(functionDoclet); - - expect(docletUrl).toBe('Milk.html#~removeSticksAndLeaves'); - }); - - it('should omit the scope punctuation from the fragment ID for instance members', () => { - const propertyDoclet = { - kind: 'member', - longname: 'Milk#calcium', - name: 'calcium', - memberof: 'Milk', - scope: 'instance' - }; - const docletUrl = helper.createLink(propertyDoclet); - - expect(docletUrl).toBe('Milk.html#calcium'); - }); - - it('should include the variation, if present, in the fragment ID', () => { - const variationDoclet = { - kind: 'function', - longname: 'Milk#fat(percent)', - name: 'fat', - memberof: 'Milk', - scope: 'instance', - variation: '(percent)' - }; - const docletUrl = helper.createLink(variationDoclet); - - expect(docletUrl).toBe('Milk.html#fat(percent)'); - }); + expect(types).toBeArrayOfSize(2); + expect(types).toContain('number'); + expect(types).toContain(helper.htmlsafe('Array.')); }); - describe("resolveAuthorLinks", () => { - it('should not crash JSDoc if no text is specified', () => { - function resolve() { - helper.resolveAuthorLinks(); - } + it('creates links for types if relevant', () => { + let doc; + let types; - expect(resolve).not.toThrow(); - }); + // make some links. + helper.longnameToUrl.MyClass = 'MyClass.html'; - // convert Jane Doe to a mailto link. - it('should convert email addresses in angle brackets *after* a name to mailto links', () => { - const str = ' John Doe '; - const out = helper.resolveAuthorLinks(str); + doc = new doclet.Doclet('/** @const {MyClass} ASDF */', {}); + types = helper.getSignatureTypes(doc); - expect(out).toBe('John Doe'); - }); - - it('should HTML-safe author names', () => { - const str = ' John '; - const out = helper.resolveAuthorLinks(str); - - expect(out).toBe(`${helper.htmlsafe('John`); - }); - - it('should simply return the input string, HTML-safe, if no email is detected', () => { - const str = 'John Doe '; - const out = helper.resolveAuthorLinks(str); - - expect(out).toBe(helper.htmlsafe(str)); - }); + expect(types).toBeArrayOfSize(1); + expect(types).toContain('MyClass'); }); - xdescribe('longnamesToTree', () => { - // TODO + it('uses the cssClass parameter for links if it is provided', () => { + let doc; + let types; + + // make some links. + helper.longnameToUrl.MyClass = 'MyClass.html'; + + doc = new doclet.Doclet('/** @const {MyClass} ASDF */', {}); + types = helper.getSignatureTypes(doc, 'myCSSClass'); + + expect(types).toBeArrayOfSize(1); + expect(types).toContain('MyClass'); }); + }); + + describe('getSignatureParams', () => { + // retrieves parameter names. + // if css class is provided, optional parameters are wrapped in a with that class. + it('returns an empty array if the doclet has no specified type', () => { + const doc = new doclet.Doclet('/** @function myFunction */', {}); + const params = helper.getSignatureParams(doc); + + expect(params).toBeEmptyArray(); + }); + + it("returns a string array of the doclet's parameter names", () => { + const doc = new doclet.Doclet( + '/** @function myFunction\n @param {string} foo - asdf. */', + {} + ); + const params = helper.getSignatureParams(doc); + + expect(params).toBeArrayOfSize(1); + expect(params).toContain('foo'); + }); + + it('wraps optional parameters in if optClass is provided', () => { + const doc = new doclet.Doclet( + '/** @function myFunction\n' + + ' * @param {boolean} foo - explanation.\n' + + ' * @param {number} [bar=1] - another explanation.\n' + + ' * @param {string} [baz] - another explanation.\n' + + ' */', + {} + ); + const params = helper.getSignatureParams(doc, 'cssClass'); + + expect(params).toBeArrayOfSize(3); + expect(params).toContain('foo'); + expect(params).toContain('bar'); + expect(params).toContain('baz'); + }); + + it("doesn't wrap optional parameters in if optClass is not provided", () => { + const doc = new doclet.Doclet( + '/** @function myFunction\n' + + ' * @param {boolean} foo - explanation.\n' + + ' * @param {number} [bar=1] - another explanation.\n' + + ' * @param {string} [baz] - another explanation.\n' + + ' */', + {} + ); + const params = helper.getSignatureParams(doc); + + expect(params).toBeArrayOfSize(3); + expect(params).toContain('foo'); + expect(params).toContain('bar'); + expect(params).toContain('baz'); + }); + }); + + describe('getSignatureReturns', () => { + afterEach(() => { + delete helper.longnameToUrl.MyClass; + }); + + it('returns a value with correctly escaped HTML', () => { + const mockDoclet = { + returns: [ + { + type: { + names: ['Array.'], + }, + }, + ], + }; + const html = helper.getSignatureReturns(mockDoclet); + + expect(html).not.toContain('Array.'); + expect(html).toContain('Array.<string>'); + }); + + it('returns an empty array if the doclet has no returns', () => { + const doc = new doclet.Doclet('/** @function myFunction */', {}); + const returns = helper.getSignatureReturns(doc); + + expect(returns).toBeEmptyArray(); + }); + + it('returns an empty array if the doclet has @returns but with no type', () => { + const doc = new doclet.Doclet( + '/** @function myFunction\n@returns an interesting result.*/', + {} + ); + const returns = helper.getSignatureReturns(doc); + + expect(returns).toBeEmptyArray(); + }); + + it('uses the value of the `yields` property', () => { + const doc = new doclet.Doclet('/** @yields {string} A string. */', {}); + const html = helper.getSignatureReturns(doc); + + expect(html).toContain('string'); + }); + + it('prefers `yields` over `returns`', () => { + const doc = new doclet.Doclet('/** @yields {string}\n@returns {number} */', {}); + const html = helper.getSignatureReturns(doc); + + expect(html).toContain('string'); + expect(html).not.toContain('number'); + }); + + it('creates links for return types if relevant', () => { + let doc; + let returns; + + // make some links. + helper.longnameToUrl.MyClass = 'MyClass.html'; + + doc = new doclet.Doclet( + '/** @function myFunction\n@returns {number|MyClass} an interesting result.*/', + {} + ); + returns = helper.getSignatureReturns(doc); + + expect(returns).toBeArrayOfSize(2); + expect(returns).toContain('MyClass'); + expect(returns).toContain('number'); + }); + + it('uses the cssClass parameter for links if it is provided', () => { + let doc; + let returns; + + // make some links. + helper.longnameToUrl.MyClass = 'MyClass.html'; + + doc = new doclet.Doclet( + '/** @function myFunction\n@returns {number|MyClass} an interesting result.*/', + {} + ); + returns = helper.getSignatureReturns(doc, 'myCssClass'); + + expect(returns).toBeArrayOfSize(2); + expect(returns).toContain('MyClass'); + expect(returns).toContain('number'); + }); + }); + + xdescribe('getAncestors', () => { + // TODO + }); + + describe('getAncestorLinks', () => { + // make a hierarchy. + const lackeys = new doclet.Doclet( + '/** @member lackeys\n@memberof module:mafia/gangs.Sharks~Henchman\n@instance*/', + {} + ); + const henchman = new doclet.Doclet( + '/** @class Henchman\n@memberof module:mafia/gangs.Sharks\n@inner */', + {} + ); + const gang = new doclet.Doclet('/** @namespace module:mafia/gangs.Sharks */', {}); + const mafia = new doclet.Doclet('/** @module mafia/gangs */', {}); + const data = taffy([lackeys, henchman, gang, mafia]); + + afterEach(() => { + delete helper.longnameToUrl['module:mafia/gangs']; + delete helper.longnameToUrl['module:mafia/gangs.Sharks~Henchman']; + }); + + // register some links + it('returns an empty array if there are no ancestors', () => { + const links = helper.getAncestorLinks(data, mafia); + + expect(links).toBeEmptyArray(); + }); + + it('returns an array of ancestor names (with preceding punctuation) if there are ancestors, the direct ancestor with following punctuation too', () => { + let links = helper.getAncestorLinks(data, lackeys); + + expect(links).toBeArrayOfSize(3); + expect(links).toContain('~Henchman#'); + expect(links).toContain('.Sharks'); + expect(links).toContain('mafia/gangs'); + + links = helper.getAncestorLinks(data, henchman); + + expect(links).toBeArrayOfSize(2); + expect(links).toContain('.Sharks~'); + expect(links).toContain('mafia/gangs'); + + links = helper.getAncestorLinks(data, gang); + + expect(links).toBeArrayOfSize(1); + expect(links).toContain('mafia/gangs.'); + }); + + it('adds links if they exist', () => { + let links; + + // register some links + helper.longnameToUrl['module:mafia/gangs'] = 'mafia_gangs.html'; + helper.longnameToUrl['module:mafia/gangs.Sharks~Henchman'] = 'henchman.html'; + + links = helper.getAncestorLinks(data, lackeys); + + expect(links).toBeArrayOfSize(3); + expect(links).toContain('~Henchman#'); + expect(links).toContain('.Sharks'); + expect(links).toContain('mafia/gangs'); + }); + + it('adds cssClass to any link', () => { + let links; + + // register some links + helper.longnameToUrl['module:mafia/gangs'] = 'mafia_gangs.html'; + helper.longnameToUrl['module:mafia/gangs.Sharks~Henchman'] = 'henchman.html'; + + links = helper.getAncestorLinks(data, lackeys, 'myClass'); + + expect(links).toBeArrayOfSize(3); + expect(links).toContain('~Henchman#'); + expect(links).toContain('.Sharks'); + expect(links).toContain('mafia/gangs'); + }); + }); + + describe('addEventListeners', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/listenstag.js'); + const doclets = taffy(_.cloneDeep(docSet.doclets)); + const ev = helper.find(doclets, { longname: 'module:myModule.event:MyEvent' })[0]; + const ev2 = helper.find(doclets, { longname: 'module:myModule~Events.event:Event2' })[0]; + const ev3 = helper.find(doclets, { longname: 'module:myModule#event:Event3' })[0]; + + helper.addEventListeners(doclets); + + it("adds a 'listeners' array to events with the longnames of the listeners", () => { + expect(ev.listeners).toBeArrayOfSize(2); + expect(ev.listeners).toContain('module:myModule~MyHandler'); + expect(ev.listeners).toContain('module:myModule~AnotherHandler'); + + expect(ev2.listeners).toBeArrayOfSize(1); + expect(ev2.listeners).toContain('module:myModule~MyHandler'); + }); + + it('does not add listeners for events with no listeners', () => { + expect(ev3.listeners).toBeUndefined(); + }); + + it('does not make spurious doclets if something @listens to a non-existent symbol', () => { + expect(helper.find(doclets, { longname: 'event:fakeEvent' })).toBeEmptyArray(); + }); + }); + + describe('prune', () => { + const access = env.opts.access; + const priv = Boolean(env.opts.private); + + afterEach(() => { + env.opts.access = access; + env.opts.private = priv; + }); + + const array = [ + // keep + { undocumented: false }, + // keep + { ignore: false }, + // keep + { memberof: 'SomeClass' }, + // prune + { undocumented: true }, + // prune + { ignore: true }, + // prune + { memberof: '' }, + ]; + const keep = [ + // keep + { undocumented: false }, + // keep + { ignore: false }, + // keep + { memberof: 'SomeClass' }, + ]; + const arrayPrivate = [ + // prune (unless env.opts.private is truthy) + { access: 'private' }, + ]; + const arrayMixed = [ + { access: 'package' }, + { access: 'public' }, + { asdf: true }, + { access: 'protected' }, + { access: 'private' }, + ]; + + it('should prune the correct members', () => { + const pruned = helper.prune(taffy(array))().get(); + + compareObjectArrays(keep, pruned); + }); + + it('should prune private members if env.opts.private is falsy', () => { + let pruned; + + env.opts.private = false; + pruned = helper.prune(taffy(arrayPrivate))().get(); + + compareObjectArrays([], pruned); + }); + + it('should only keep package-private members if env.opts.access only contains "package"', () => { + let pruned; + const keepPackage = [{ access: 'package' }]; + + env.opts.access = 'package'; + pruned = helper.prune(taffy(arrayMixed))().get(); + + compareObjectArrays(keepPackage, pruned); + }); + + it('should only keep public members if env.opts.access only contains "public"', () => { + let pruned; + const keepPublic = [{ access: 'public' }]; + + env.opts.access = 'public'; + pruned = helper.prune(taffy(arrayMixed))().get(); + + compareObjectArrays(keepPublic, pruned); + }); + + it('should only keep undefined members if env.opts.access only contains "undefined"', () => { + let pruned; + const keepUndefined = [{ asdf: true }]; + + env.opts.access = 'undefined'; + pruned = helper.prune(taffy(arrayMixed))().get(); + + compareObjectArrays(keepUndefined, pruned); + }); + + it('should only keep protected members if env.opts.access only contains "protected"', () => { + let pruned; + const keepProtected = [{ access: 'protected' }]; + + env.opts.access = 'protected'; + pruned = helper.prune(taffy(arrayMixed))().get(); + + compareObjectArrays(keepProtected, pruned); + }); + + it('should only keep private members if env.opts.access only contains "private"', () => { + let pruned; + const keepPrivate = [{ access: 'private' }]; + + env.opts.access = 'private'; + pruned = helper.prune(taffy(arrayMixed))().get(); + + compareObjectArrays(keepPrivate, pruned); + }); + + it('should keep public and protected members if env.opts.access contains "public" and "protected"', () => { + let pruned; + const keepPublicProtected = [ + { + access: 'public', + }, + { + access: 'protected', + }, + ]; + + env.opts.access = ['public', 'protected']; + pruned = helper.prune(taffy(arrayMixed))().get(); + + compareObjectArrays(keepPublicProtected, pruned); + }); + + it('should keep everything if env.opts.access contains "all"', () => { + let pruned; + + env.opts.access = 'all'; + pruned = helper.prune(taffy(arrayMixed))().get(); + + compareObjectArrays(arrayMixed, pruned); + }); + + it('should not prune private members if env.opts.private is truthy', () => { + let pruned; + + env.opts.private = true; + pruned = helper.prune(taffy(arrayPrivate))().get(); + + compareObjectArrays(arrayPrivate, pruned); + }); + }); + + describe('registerLink', () => { + afterEach(() => { + delete helper.longnameToUrl.MySymbol; + }); + + it('adds an entry to exports.longnameToUrl', () => { + helper.longnameToUrl.MySymbol = 'asdf.html'; + + expect(helper.longnameToUrl.MySymbol).toBe('asdf.html'); + }); + + it('allows linkto to work', () => { + helper.registerLink('MySymbol', 'asdf.html'); + + expect(helper.linkto('MySymbol')).toBe('MySymbol'); + }); + }); + + describe('resolveLinks', () => { + let conf; + + beforeEach(() => { + conf = _.cloneDeep(env.conf.templates); + }); + + afterEach(() => { + env.conf.templates = conf; + delete helper.longnameToUrl['my.long.namespace']; + }); + + it('should translate {@link test} into a HTML link.', () => { + const input = 'This is a {@link test}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is a test.'); + }); + + it('should translate {@link unknown} into a simple text.', () => { + const input = 'This is a {@link unknown}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is a unknown.'); + }); + + it('should translate {@link test} into a HTML links multiple times.', () => { + const input = 'This is a {@link test} and {@link test}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe( + 'This is a test and test.' + ); + }); + + it('should translate [hello there]{@link test} into a HTML link with the custom content.', () => { + const input = 'This is a [hello there]{@link test}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is a hello there.'); + }); + + it('should translate [dummy text] and [hello there]{@link test} into an HTML link with the custom content.', () => { + const input = 'This is [dummy text] and [hello there]{@link test}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is [dummy text] and hello there.'); + }); + + it('should translate [dummy text] and [more] and [hello there]{@link test} into an HTML link with the custom content.', () => { + const input = 'This is [dummy text] and [more] and [hello there]{@link test}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe( + 'This is [dummy text] and [more] and hello there.' + ); + }); + + it('should ignore [hello there].', () => { + const input = 'This is a [hello there].'; + const output = helper.resolveLinks(input); + + expect(output).toBe(input); + }); + + it('should translate http links in the tag', () => { + const input = 'Link to {@link http://github.com}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to http://github.com'); + }); + + it('should translate ftp links in the tag', () => { + const input = 'Link to {@link ftp://foo.bar}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to ftp://foo.bar'); + }); + + it('should allow pipe to be used as delimiter between href and text (external link)', () => { + const input = 'Link to {@link http://github.com|Github}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to Github'); + }); + + it('should allow pipe to be used as delimiter between href and text (symbol link)', () => { + const input = 'Link to {@link test|Test}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to Test'); + }); + + it('should allow first space to be used as delimiter between href and text (external link)', () => { + const input = 'Link to {@link http://github.com Github}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to Github'); + }); + + it('should allow first space to be used as delimiter between href and text (symbol link)', () => { + const input = 'Link to {@link test My Caption}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to My Caption'); + }); + + it('if pipe and space are present in link tag, use pipe as the delimiter', () => { + const input = 'Link to {@link test|My Caption}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to My Caption'); + }); + + it('Test of {@linkcode } which should be in monospace', () => { + const input = 'Link to {@linkcode test}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + it('Test of {@linkplain } which should be in normal font', () => { + const input = 'Link to {@linkplain test}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + it('should be careful with linking to links whose names are reserved JS keywords', () => { + const input = 'Link to {@link constructor}'; + const output = helper.resolveLinks(input); + + expect(output).toBe('Link to constructor'); + }); + + it('should allow linebreaks between link tag and content', () => { + const input = 'This is a {@link\ntest}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is a test.'); + }); + + it('should allow linebreaks to separate url from link text', () => { + const input = 'This is a {@link\ntest\ntest}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is a test.'); + }); + + it('should normalize additional newlines to spaces', () => { + const input = 'This is a {@link\ntest\ntest\n\ntest}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is a test test.'); + }); + + it('should allow tabs between link tag and content', () => { + const input = 'This is a {@link\ttest}.'; + const output = helper.resolveLinks(input); + + expect(output).toBe('This is a test.'); + }); + + // conf.monospaceLinks. check that + // a) it works + it('if conf.monospaceLinks is true, all {@link} should be monospace', () => { + const input = 'Link to {@link test}'; + let output; + + env.conf.templates.monospaceLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + // b) linkcode and linkplain are still respected + it('if conf.monospaceLinks is true, all {@linkcode} should still be monospace', () => { + const input = 'Link to {@linkcode test}'; + let output; + + env.conf.templates.monospaceLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + it('if conf.monospaceLinks is true, all {@linkplain} should still be plain', () => { + const input = 'Link to {@linkplain test}'; + let output; + + env.conf.templates.monospaceLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + // conf.cleverLinks. check that + // a) it works + it('if conf.cleverLinks is true, {@link symbol} should be in monospace', () => { + const input = 'Link to {@link test}'; + let output; + + env.conf.templates.cleverLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + it('if conf.cleverLinks is true, {@link URL} should be in plain text', () => { + const input = 'Link to {@link http://github.com}'; + let output; + + env.conf.templates.cleverLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe('Link to http://github.com'); + }); + + // b) linkcode and linkplain are still respected + it('if conf.cleverLinks is true, all {@linkcode} should still be clever', () => { + const input = 'Link to {@linkcode test}'; + let output; + + env.conf.templates.cleverLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + it('if conf.cleverLinks is true, all {@linkplain} should still be plain', () => { + const input = 'Link to {@linkplain test}'; + let output; + + env.conf.templates.cleverLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe('Link to test'); + }); + + // c) if monospaceLinks is additionally `true` it is ignored in favour + // of cleverLinks + it('if conf.cleverLinks is true and so is conf.monospaceLinks, cleverLinks overrides', () => { + const input = 'Link to {@link test} and {@link http://github.com}'; + let output; + + env.conf.templates.cleverLinks = true; + env.conf.templates.monospaceLinks = true; + output = helper.resolveLinks(input); + + expect(output).toBe( + 'Link to test and ' + + 'http://github.com' + ); + }); + + it('if conf.useShortNamesInLinks is true, it uses the short name in links', () => { + const input = 'Link to {@link my.long.namespace}'; + let output; + + env.conf.templates.useShortNamesInLinks = true; + helper.registerLink('my.long.namespace', 'asdf.html'); + output = helper.resolveLinks(input); + + expect(output).toBe('Link to namespace'); + }); + }); + + describe('createLink', () => { + it('should create a url for a simple global.', () => { + const mockDoclet = { + kind: 'function', + longname: 'foo', + name: 'foo', + scope: 'global', + }; + const url = helper.createLink(mockDoclet); + + expect(url).toBe('global.html#foo'); + }); + + it('should create a url for a namespace.', () => { + const mockDoclet = { + kind: 'namespace', + longname: 'foo', + name: 'foo', + }; + const url = helper.createLink(mockDoclet); + + expect(url).toBe('foo.html'); + }); + + it('should create a url for a member of a namespace.', () => { + const mockDoclet = { + kind: 'function', + longname: 'ns.foo', + name: 'foo', + memberof: 'ns', + }; + const url = helper.createLink(mockDoclet); + + expect(url).toBe('ns.html#foo'); + }); + + const nestedNamespaceDoclet = { + kind: 'function', + longname: 'ns1.ns2.foo', + name: 'foo', + memberof: 'ns1.ns2', + }; + let nestedNamespaceUrl; + + it('should create a url for a member of a nested namespace.', () => { + nestedNamespaceUrl = helper.createLink(nestedNamespaceDoclet); + + expect(nestedNamespaceUrl).toBe('ns1.ns2.html#foo'); + }); + + it('should return the same value when called twice with the same doclet.', () => { + const newUrl = helper.createLink(nestedNamespaceDoclet); + + expect(newUrl).toBe(nestedNamespaceUrl); + }); + + it('should create a url for a name with invalid characters.', () => { + const mockDoclet = { + kind: 'function', + longname: 'ns1."!"."*foo"', + name: '"*foo"', + memberof: 'ns1."!"', + }; + const url = helper.createLink(mockDoclet); + + expect(url).toEqual('ns1._!_.html#%22*foo%22'); + }); + + it('should create a url for a function that is the only symbol exported by a module.', () => { + const mockDoclet = { + kind: 'function', + longname: 'module:bar', + name: 'module:bar', + }; + const url = helper.createLink(mockDoclet); + + expect(url).toEqual('module-bar.html'); + }); + + it('should create a url for a doclet with the wrong kind (caused by incorrect JSDoc tags', () => { + const moduleDoclet = { + kind: 'module', + longname: 'module:baz', + name: 'module:baz', + }; + const badDoclet = { + kind: 'member', + longname: 'module:baz', + name: 'module:baz', + }; + const moduleDocletUrl = helper.createLink(moduleDoclet); + const badDocletUrl = helper.createLink(badDoclet); + + expect(moduleDocletUrl).toBe('module-baz.html'); + expect(badDocletUrl).toBe('module-baz.html'); + }); + + it('should create a url for a function that is a member of a doclet with the wrong kind', () => { + const badModuleDoclet = { + kind: 'member', + longname: 'module:qux', + name: 'module:qux', + }; + const memberDoclet = { + kind: 'function', + name: 'frozzle', + memberof: 'module:qux', + scope: 'instance', + longname: 'module:qux#frozzle', + }; + const badModuleDocletUrl = helper.createLink(badModuleDoclet); + const memberDocletUrl = helper.createLink(memberDoclet); + + expect(badModuleDocletUrl).toBe('module-qux.html'); + expect(memberDocletUrl).toBe('module-qux.html#frozzle'); + }); + + it('should include the scope punctuation in the fragment ID for static members', () => { + const functionDoclet = { + kind: 'function', + longname: 'Milk.pasteurize', + name: 'pasteurize', + memberof: 'Milk', + scope: 'static', + }; + const docletUrl = helper.createLink(functionDoclet); + + expect(docletUrl).toBe('Milk.html#.pasteurize'); + }); + + it('should include the scope punctuation in the fragment ID for inner members', () => { + const functionDoclet = { + kind: 'function', + longname: 'Milk~removeSticksAndLeaves', + name: 'removeSticksAndLeaves', + memberof: 'Milk', + scope: 'inner', + }; + const docletUrl = helper.createLink(functionDoclet); + + expect(docletUrl).toBe('Milk.html#~removeSticksAndLeaves'); + }); + + it('should omit the scope punctuation from the fragment ID for instance members', () => { + const propertyDoclet = { + kind: 'member', + longname: 'Milk#calcium', + name: 'calcium', + memberof: 'Milk', + scope: 'instance', + }; + const docletUrl = helper.createLink(propertyDoclet); + + expect(docletUrl).toBe('Milk.html#calcium'); + }); + + it('should include the variation, if present, in the fragment ID', () => { + const variationDoclet = { + kind: 'function', + longname: 'Milk#fat(percent)', + name: 'fat', + memberof: 'Milk', + scope: 'instance', + variation: '(percent)', + }; + const docletUrl = helper.createLink(variationDoclet); + + expect(docletUrl).toBe('Milk.html#fat(percent)'); + }); + }); + + describe('resolveAuthorLinks', () => { + it('should not crash JSDoc if no text is specified', () => { + function resolve() { + helper.resolveAuthorLinks(); + } + + expect(resolve).not.toThrow(); + }); + + // convert Jane Doe to a mailto link. + it('should convert email addresses in angle brackets *after* a name to mailto links', () => { + const str = ' John Doe '; + const out = helper.resolveAuthorLinks(str); + + expect(out).toBe('John Doe'); + }); + + it('should HTML-safe author names', () => { + const str = ' John '; + const out = helper.resolveAuthorLinks(str); + + expect(out).toBe(`${helper.htmlsafe('John`); + }); + + it('should simply return the input string, HTML-safe, if no email is detected', () => { + const str = 'John Doe '; + const out = helper.resolveAuthorLinks(str); + + expect(out).toBe(helper.htmlsafe(str)); + }); + }); + + xdescribe('longnamesToTree', () => { + // TODO + }); }); diff --git a/packages/jsdoc/test/specs/plugins/plugins.js b/packages/jsdoc/test/specs/plugins/plugins.js index 268fded4..1d7db3d0 100644 --- a/packages/jsdoc/test/specs/plugins/plugins.js +++ b/packages/jsdoc/test/specs/plugins/plugins.js @@ -1,42 +1,42 @@ // TODO: consolidate with specs/jsdoc/parser and specs/jsdoc/plugins describe('plugins', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let docSet; - const pluginPaths = [ - path.normalize(`${env.dirname}/test/fixtures/testPlugin1`), - path.normalize(`${env.dirname}/test/fixtures/testPlugin2`) - ]; + let docSet; + const pluginPaths = [ + path.normalize(`${env.dirname}/test/fixtures/testPlugin1`), + path.normalize(`${env.dirname}/test/fixtures/testPlugin2`), + ]; - const parser = jsdoc.createParser(); + const parser = jsdoc.createParser(); - global.jsdocPluginsTest = global.jsdocPluginsTest || {}; + global.jsdocPluginsTest = global.jsdocPluginsTest || {}; - require('jsdoc/plugins').installPlugins(pluginPaths, parser); + require('jsdoc/plugins').installPlugins(pluginPaths, parser); - docSet = jsdoc.getDocSetFromFile('test/fixtures/plugins.js', parser, false); + docSet = jsdoc.getDocSetFromFile('test/fixtures/plugins.js', parser, false); - it("should fire the plugin's event handlers", () => { - expect(global.jsdocPluginsTest.plugin1.fileBegin).toBeTrue(); - expect(global.jsdocPluginsTest.plugin1.beforeParse).toBeTrue(); - expect(global.jsdocPluginsTest.plugin1.jsdocCommentFound).toBeTrue(); - expect(global.jsdocPluginsTest.plugin1.symbolFound).toBeTrue(); - expect(global.jsdocPluginsTest.plugin1.newDoclet).toBeTrue(); - expect(global.jsdocPluginsTest.plugin1.fileComplete).toBeTrue(); + it("should fire the plugin's event handlers", () => { + expect(global.jsdocPluginsTest.plugin1.fileBegin).toBeTrue(); + expect(global.jsdocPluginsTest.plugin1.beforeParse).toBeTrue(); + expect(global.jsdocPluginsTest.plugin1.jsdocCommentFound).toBeTrue(); + expect(global.jsdocPluginsTest.plugin1.symbolFound).toBeTrue(); + expect(global.jsdocPluginsTest.plugin1.newDoclet).toBeTrue(); + expect(global.jsdocPluginsTest.plugin1.fileComplete).toBeTrue(); - expect(global.jsdocPluginsTest.plugin2.fileBegin).toBeTrue(); - expect(global.jsdocPluginsTest.plugin2.beforeParse).toBeTrue(); - expect(global.jsdocPluginsTest.plugin2.jsdocCommentFound).toBeTrue(); - expect(global.jsdocPluginsTest.plugin2.symbolFound).toBeTrue(); - expect(global.jsdocPluginsTest.plugin2.newDoclet).toBeTrue(); - expect(global.jsdocPluginsTest.plugin2.fileComplete).toBeTrue(); - }); + expect(global.jsdocPluginsTest.plugin2.fileBegin).toBeTrue(); + expect(global.jsdocPluginsTest.plugin2.beforeParse).toBeTrue(); + expect(global.jsdocPluginsTest.plugin2.jsdocCommentFound).toBeTrue(); + expect(global.jsdocPluginsTest.plugin2.symbolFound).toBeTrue(); + expect(global.jsdocPluginsTest.plugin2.newDoclet).toBeTrue(); + expect(global.jsdocPluginsTest.plugin2.fileComplete).toBeTrue(); + }); - it("should add the plugin's tag definitions to the dictionary", () => { - const test = docSet.getByLongname('test'); + it("should add the plugin's tag definitions to the dictionary", () => { + const test = docSet.getByLongname('test'); - expect(test[0].longname).toBe('test'); - expect(test[0].foo).toBeTrue(); - }); + expect(test[0].longname).toBe('test'); + expect(test[0].foo).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/abstracttag.js b/packages/jsdoc/test/specs/tags/abstracttag.js index 0da35786..06f9d738 100644 --- a/packages/jsdoc/test/specs/tags/abstracttag.js +++ b/packages/jsdoc/test/specs/tags/abstracttag.js @@ -1,15 +1,15 @@ describe('@abstract tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/abstracttag.js'); - const thingy = docSet.getByLongname('Thingy')[0]; - const thingyPez = docSet.getByLongname('Thingy#pez')[0]; - const otherThingyPez = docSet.getByLongname('OtherThingy#pez')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/abstracttag.js'); + const thingy = docSet.getByLongname('Thingy')[0]; + const thingyPez = docSet.getByLongname('Thingy#pez')[0]; + const otherThingyPez = docSet.getByLongname('OtherThingy#pez')[0]; - it('should have an undefined "virtual" property with no "@abstract" tag', () => { - expect(thingy.virtual).toBeUndefined(); - }); + it('should have an undefined "virtual" property with no "@abstract" tag', () => { + expect(thingy.virtual).toBeUndefined(); + }); - it('should set the doclet\'s "virtual" property to true when "@abstract" tag is present', () => { - expect(thingyPez.virtual).toBeTrue(); - expect(otherThingyPez.virtual).toBeTrue(); - }); + it('should set the doclet\'s "virtual" property to true when "@abstract" tag is present', () => { + expect(thingyPez.virtual).toBeTrue(); + expect(otherThingyPez.virtual).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/accesstag.js b/packages/jsdoc/test/specs/tags/accesstag.js index 8712b323..dc1c5eba 100644 --- a/packages/jsdoc/test/specs/tags/accesstag.js +++ b/packages/jsdoc/test/specs/tags/accesstag.js @@ -1,31 +1,31 @@ describe('@access tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/accesstag.js'); - const foo = docSet.getByLongname('Thingy~foo')[0]; - const _bar = docSet.getByLongname('Thingy#_bar')[0]; - const _gnu = docSet.getByLongname('Thingy#_gnu')[0]; - const pez = docSet.getByLongname('Thingy#pez')[0]; - const foo2 = docSet.getByLongname('OtherThingy~foo')[0]; - const _bar2 = docSet.getByLongname('OtherThingy#_bar')[0]; - const _gnu2 = docSet.getByLongname('OtherThingy#_gnu')[0]; - const pez2 = docSet.getByLongname('OtherThingy#pez')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/accesstag.js'); + const foo = docSet.getByLongname('Thingy~foo')[0]; + const _bar = docSet.getByLongname('Thingy#_bar')[0]; + const _gnu = docSet.getByLongname('Thingy#_gnu')[0]; + const pez = docSet.getByLongname('Thingy#pez')[0]; + const foo2 = docSet.getByLongname('OtherThingy~foo')[0]; + const _bar2 = docSet.getByLongname('OtherThingy#_bar')[0]; + const _gnu2 = docSet.getByLongname('OtherThingy#_gnu')[0]; + const pez2 = docSet.getByLongname('OtherThingy#pez')[0]; - it('should set the doclet\'s \'access\' property to \'private\' when there is an @access private tag', () => { - expect(foo.access).toBe('private'); - expect(foo2.access).toBe('private'); - }); + it("should set the doclet's 'access' property to 'private' when there is an @access private tag", () => { + expect(foo.access).toBe('private'); + expect(foo2.access).toBe('private'); + }); - it('should set the doclet\'s \'access\' property to \'protected\' when there is an @access protected tag', () => { - expect(_bar.access).toBe('protected'); - expect(_bar2.access).toBe('protected'); - }); + it("should set the doclet's 'access' property to 'protected' when there is an @access protected tag", () => { + expect(_bar.access).toBe('protected'); + expect(_bar2.access).toBe('protected'); + }); - it('should set the doclet\'s \'access\' property to \'public\' when there is an @access public tag', () => { - expect(_gnu.access).toBe('public'); - expect(_gnu2.access).toBe('public'); - }); + it("should set the doclet's 'access' property to 'public' when there is an @access public tag", () => { + expect(_gnu.access).toBe('public'); + expect(_gnu2.access).toBe('public'); + }); - it('should set no \'access\' property on the doclet when there is no @access tag', () => { - expect(pez.access).toBeUndefined(); - expect(pez2.access).toBeUndefined(); - }); + it("should set no 'access' property on the doclet when there is no @access tag", () => { + expect(pez.access).toBeUndefined(); + expect(pez2.access).toBeUndefined(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/aliastag.js b/packages/jsdoc/test/specs/tags/aliastag.js index 5a8cc8e3..c218bdd8 100644 --- a/packages/jsdoc/test/specs/tags/aliastag.js +++ b/packages/jsdoc/test/specs/tags/aliastag.js @@ -1,11 +1,11 @@ describe('@alias tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias.js'); - // there are two doclets with longname myObject, we want the second one - const myObject = docSet.getByLongname('myObject')[1]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/alias.js'); + // there are two doclets with longname myObject, we want the second one + const myObject = docSet.getByLongname('myObject')[1]; - it('adds an "alias" property to the doclet with the tag\'s value', () => { - expect(myObject.alias).toBe('myObject'); - }); + it('adds an "alias" property to the doclet with the tag\'s value', () => { + expect(myObject.alias).toBe('myObject'); + }); - // further tests (ensuring alias has the proper effect): documentation/alias.js + // further tests (ensuring alias has the proper effect): documentation/alias.js }); diff --git a/packages/jsdoc/test/specs/tags/asynctag.js b/packages/jsdoc/test/specs/tags/asynctag.js index 02314daa..16bfdcc7 100644 --- a/packages/jsdoc/test/specs/tags/asynctag.js +++ b/packages/jsdoc/test/specs/tags/asynctag.js @@ -1,8 +1,8 @@ describe('@async tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/asynctag.js'); - const foo = docSet.getByLongname('foo')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/asynctag.js'); + const foo = docSet.getByLongname('foo')[0]; - it('should add an `async` property to the doclet', () => { - expect(foo.async).toBeTrue(); - }); + it('should add an `async` property to the doclet', () => { + expect(foo.async).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/augmentstag.js b/packages/jsdoc/test/specs/tags/augmentstag.js index 5189a890..dac59b4b 100644 --- a/packages/jsdoc/test/specs/tags/augmentstag.js +++ b/packages/jsdoc/test/specs/tags/augmentstag.js @@ -1,173 +1,173 @@ describe('@augments tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/augmentstag.js'); - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag2.js'); - const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag3.js'); - const docSet4 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag4.js'); - const docSet5 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag5.js'); - const docSet6 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag6.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/augmentstag.js'); + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag2.js'); + const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag3.js'); + const docSet4 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag4.js'); + const docSet5 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag5.js'); + const docSet6 = jsdoc.getDocSetFromFile('test/fixtures/augmentstag6.js'); - it('When a symbol has an @augments tag, the doclet has a augments property that includes that value.', () => { - const bar = docSet.getByLongname('Bar')[0]; + it('When a symbol has an @augments tag, the doclet has a augments property that includes that value.', () => { + const bar = docSet.getByLongname('Bar')[0]; - expect(bar.augments).toBeArray(); - expect(bar.augments[0]).toBe('Foo'); - }); + expect(bar.augments).toBeArray(); + expect(bar.augments[0]).toBe('Foo'); + }); - it('When an object is extended, the original is not modified', () => { - const fooProp3 = docSet.getByLongname('Foo#prop3')[0]; + it('When an object is extended, the original is not modified', () => { + const fooProp3 = docSet.getByLongname('Foo#prop3')[0]; - expect(fooProp3).toBeUndefined(); - }); + expect(fooProp3).toBeUndefined(); + }); - it('When an object is extended, it inherits properties set in parent constructor', () => { - const fooProp1 = docSet.getByLongname('Foo#prop1')[0]; - const barProp1 = docSet.getByLongname('Bar#prop1')[0]; + it('When an object is extended, it inherits properties set in parent constructor', () => { + const fooProp1 = docSet.getByLongname('Foo#prop1')[0]; + const barProp1 = docSet.getByLongname('Bar#prop1')[0]; - expect(fooProp1.memberof).toBe('Foo'); - expect(barProp1.memberof).toBe('Bar'); - expect(barProp1.description).toBe(fooProp1.description); - }); + expect(fooProp1.memberof).toBe('Foo'); + expect(barProp1.memberof).toBe('Bar'); + expect(barProp1.description).toBe(fooProp1.description); + }); - it('When an object is extended, it inherits properties set on parent prototype', () => { - const fooProp2 = docSet.getByLongname('Foo#prop2')[0]; - const barProp2 = docSet.getByLongname('Bar#prop2')[0]; + it('When an object is extended, it inherits properties set on parent prototype', () => { + const fooProp2 = docSet.getByLongname('Foo#prop2')[0]; + const barProp2 = docSet.getByLongname('Bar#prop2')[0]; - expect(fooProp2.memberof).toBe('Foo'); - expect(barProp2.memberof).toBe('Bar'); - expect(barProp2.description).toBe(fooProp2.description); - }); + expect(fooProp2.memberof).toBe('Foo'); + expect(barProp2.memberof).toBe('Bar'); + expect(barProp2.description).toBe(fooProp2.description); + }); - it('When an object is extended, it inherits methods set on parent prototype', () => { - const fooMethod1 = docSet.getByLongname('Foo#method1')[0]; - const barMethod1 = docSet.getByLongname('Bar#method1')[0]; + it('When an object is extended, it inherits methods set on parent prototype', () => { + const fooMethod1 = docSet.getByLongname('Foo#method1')[0]; + const barMethod1 = docSet.getByLongname('Bar#method1')[0]; - expect(fooMethod1.memberof).toBe('Foo'); - expect(barMethod1.memberof).toBe('Bar'); - expect(barMethod1.description).toBe(fooMethod1.description); - }); + expect(fooMethod1.memberof).toBe('Foo'); + expect(barMethod1.memberof).toBe('Bar'); + expect(barMethod1.description).toBe(fooMethod1.description); + }); - it('When an object is extended, it may override methods set on parent prototype', () => { - const fooMethod2 = docSet.getByLongname('Foo#method2')[0]; - const barMethod2 = docSet.getByLongname('Bar#method2')[0]; + it('When an object is extended, it may override methods set on parent prototype', () => { + const fooMethod2 = docSet.getByLongname('Foo#method2')[0]; + const barMethod2 = docSet.getByLongname('Bar#method2')[0]; - expect(fooMethod2.memberof).toBe('Foo'); - expect(fooMethod2.description).toBe('Second parent method.'); - expect(barMethod2.memberof).toBe('Bar'); - expect(barMethod2.description).toBe('Second child method.'); - }); + expect(fooMethod2.memberof).toBe('Foo'); + expect(fooMethod2.description).toBe('Second parent method.'); + expect(barMethod2.memberof).toBe('Bar'); + expect(barMethod2.description).toBe('Second child method.'); + }); - it('When an object is extended, and it overrides an ancestor method, the child does not include docs for the ancestor method.', () => { - const barMethod2All = docSet.getByLongname('Bar#method2'); + it('When an object is extended, and it overrides an ancestor method, the child does not include docs for the ancestor method.', () => { + const barMethod2All = docSet.getByLongname('Bar#method2'); - expect(barMethod2All).toBeArrayOfSize(1); - }); + expect(barMethod2All).toBeArrayOfSize(1); + }); - it('When an object is extended, and it overrides an ancestor, the child has an "overrides" property', () => { - const barMethod2 = docSet.getByLongname('Bar#method2')[0]; + it('When an object is extended, and it overrides an ancestor, the child has an "overrides" property', () => { + const barMethod2 = docSet.getByLongname('Bar#method2')[0]; - expect(barMethod2.overrides).toBe('Foo#method2'); - }); + expect(barMethod2.overrides).toBe('Foo#method2'); + }); - it('When an object is extended, it inherits properties set on grandparent prototype', () => { - const fooProp1 = docSet.getByLongname('Foo#prop1')[0]; - const barProp1 = docSet.getByLongname('Bar#prop1')[0]; - const bazProp1 = docSet.getByLongname('Baz#prop1')[0]; - const bazMethod1 = docSet.getByLongname('Baz#method1')[0]; + it('When an object is extended, it inherits properties set on grandparent prototype', () => { + const fooProp1 = docSet.getByLongname('Foo#prop1')[0]; + const barProp1 = docSet.getByLongname('Bar#prop1')[0]; + const bazProp1 = docSet.getByLongname('Baz#prop1')[0]; + const bazMethod1 = docSet.getByLongname('Baz#method1')[0]; - expect(fooProp1.memberof).toBe('Foo'); - expect(barProp1.memberof).toBe('Bar'); - expect(bazProp1.memberof).toBe('Baz'); - expect(bazProp1.description).toBe('Override prop1'); - expect(bazMethod1.memberof).toBe('Baz'); - }); + expect(fooProp1.memberof).toBe('Foo'); + expect(barProp1.memberof).toBe('Bar'); + expect(bazProp1.memberof).toBe('Baz'); + expect(bazProp1.description).toBe('Override prop1'); + expect(bazMethod1.memberof).toBe('Baz'); + }); - it('(Grand)children correctly identify the original source of inherited members', () => { - const fooProp1 = docSet.getByLongname('Foo#prop1')[0]; - const barProp1 = docSet.getByLongname('Bar#prop1')[0]; - const barProp3 = docSet.getByLongname('Bar#prop3')[0]; - const bazProp2 = docSet.getByLongname('Baz#prop2')[0]; - const bazProp3 = docSet.getByLongname('Baz#prop3')[0]; - const bazMethod1 = docSet.getByLongname('Baz#method1')[0]; - const bazMethod2 = docSet.getByLongname('Baz#method2')[0]; + it('(Grand)children correctly identify the original source of inherited members', () => { + const fooProp1 = docSet.getByLongname('Foo#prop1')[0]; + const barProp1 = docSet.getByLongname('Bar#prop1')[0]; + const barProp3 = docSet.getByLongname('Bar#prop3')[0]; + const bazProp2 = docSet.getByLongname('Baz#prop2')[0]; + const bazProp3 = docSet.getByLongname('Baz#prop3')[0]; + const bazMethod1 = docSet.getByLongname('Baz#method1')[0]; + const bazMethod2 = docSet.getByLongname('Baz#method2')[0]; - expect(fooProp1.inherits).toBeUndefined(); - expect(barProp3.inherits).toBeUndefined(); - expect(barProp1.inherits).toBe('Foo#prop1'); - expect(bazProp2.inherits).toBe('Foo#prop2'); - expect(bazProp3.inherits).toBe('Bar#prop3'); - expect(bazMethod1.inherits).toBe('Foo#method1'); - expect(bazMethod2.inherits).toBe('Bar#method2'); - }); + expect(fooProp1.inherits).toBeUndefined(); + expect(barProp3.inherits).toBeUndefined(); + expect(barProp1.inherits).toBe('Foo#prop1'); + expect(bazProp2.inherits).toBe('Foo#prop2'); + expect(bazProp3.inherits).toBe('Bar#prop3'); + expect(bazMethod1.inherits).toBe('Foo#method1'); + expect(bazMethod2.inherits).toBe('Bar#method2'); + }); - it('When the grandparent has a method, the parent overrides it, and the child inherits it, the child should not say it overrides anything', () => { - const bazMethod2 = docSet.getByLongname('Baz#method2')[0]; + it('When the grandparent has a method, the parent overrides it, and the child inherits it, the child should not say it overrides anything', () => { + const bazMethod2 = docSet.getByLongname('Baz#method2')[0]; - expect(bazMethod2.overrides).toBeUndefined(); - }); + expect(bazMethod2.overrides).toBeUndefined(); + }); - it('When the grandparent has a method, the parent inherits it, and the child overrides it, the child should say it overrides the parent', () => { - const bazMethod3 = docSet.getByLongname('Baz#method3')[0]; + it('When the grandparent has a method, the parent inherits it, and the child overrides it, the child should say it overrides the parent', () => { + const bazMethod3 = docSet.getByLongname('Baz#method3')[0]; - expect(bazMethod3.overrides).toBe('Bar#method3'); - }); + expect(bazMethod3.overrides).toBe('Bar#method3'); + }); - it('When an object is extended, and it overrides an ancestor property, the child does not include docs for the ancestor property.', () => { - const bazProp1All = docSet.getByLongname('Baz#prop1'); + it('When an object is extended, and it overrides an ancestor property, the child does not include docs for the ancestor property.', () => { + const bazProp1All = docSet.getByLongname('Baz#prop1'); - expect(bazProp1All).toBeArrayOfSize(1); - }); + expect(bazProp1All).toBeArrayOfSize(1); + }); - it('When a symbol has an @augments tag, and the parent is not documented, the doclet still has an augments property', () => { - const qux = docSet2.getByLongname('Qux')[0]; + it('When a symbol has an @augments tag, and the parent is not documented, the doclet still has an augments property', () => { + const qux = docSet2.getByLongname('Qux')[0]; - expect(qux.augments).toBeArray(); - expect(qux.augments[0]).toBe('UndocumentedThing'); - }); + expect(qux.augments).toBeArray(); + expect(qux.augments[0]).toBe('UndocumentedThing'); + }); - it('When a symbol @augments multiple parents, it inherits methods from all parents', () => { - const fooMethod1 = docSet3.getByLongname('Foo#method1')[0]; - const barMethod2 = docSet3.getByLongname('Bar#method2')[0]; - const fooBarMethod1 = docSet3.getByLongname('FooBar#method1')[0]; - const fooBarMethod2 = docSet3.getByLongname('FooBar#method2')[0]; + it('When a symbol @augments multiple parents, it inherits methods from all parents', () => { + const fooMethod1 = docSet3.getByLongname('Foo#method1')[0]; + const barMethod2 = docSet3.getByLongname('Bar#method2')[0]; + const fooBarMethod1 = docSet3.getByLongname('FooBar#method1')[0]; + const fooBarMethod2 = docSet3.getByLongname('FooBar#method2')[0]; - expect(fooBarMethod1).toBeDefined(); - expect(fooBarMethod2).toBeDefined(); - expect(fooBarMethod1.description).toBe(fooMethod1.description); - expect(fooBarMethod2.description).toBe(barMethod2.description); - }); + expect(fooBarMethod1).toBeDefined(); + expect(fooBarMethod2).toBeDefined(); + expect(fooBarMethod1.description).toBe(fooMethod1.description); + expect(fooBarMethod2.description).toBe(barMethod2.description); + }); - it('When a symbol overrides an inherited method without documenting the method, it uses the parent\'s docs', () => { - const baseMethod1 = docSet4.getByLongname('Base#test1')[0]; - const derivedMethod1All = docSet4.getByLongname('Derived#test1'); - const derivedMethod1 = derivedMethod1All[1]; + it("When a symbol overrides an inherited method without documenting the method, it uses the parent's docs", () => { + const baseMethod1 = docSet4.getByLongname('Base#test1')[0]; + const derivedMethod1All = docSet4.getByLongname('Derived#test1'); + const derivedMethod1 = derivedMethod1All[1]; - expect(derivedMethod1All).toBeArrayOfSize(2); - expect(derivedMethod1.undocumented).toBeUndefined(); - expect(derivedMethod1.description).toBe(baseMethod1.description); - }); + expect(derivedMethod1All).toBeArrayOfSize(2); + expect(derivedMethod1.undocumented).toBeUndefined(); + expect(derivedMethod1.description).toBe(baseMethod1.description); + }); - it('When a symbol inherits an explicitly named symbol, the inherited symbol is documented', () => { - const baseMethod3 = docSet4.getByLongname('Base#test3')[0]; - const derivedMethod3 = docSet4.getByLongname('Derived#test3')[0]; + it('When a symbol inherits an explicitly named symbol, the inherited symbol is documented', () => { + const baseMethod3 = docSet4.getByLongname('Base#test3')[0]; + const derivedMethod3 = docSet4.getByLongname('Derived#test3')[0]; - expect(derivedMethod3).toBeObject(); - expect(derivedMethod3.comment).toBe(baseMethod3.comment); - }); + expect(derivedMethod3).toBeObject(); + expect(derivedMethod3.comment).toBe(baseMethod3.comment); + }); - // https://github.com/jsdoc3/jsdoc/issues/911 - xit('When a symbol inherits two methods that would both have the same longname, the last one wins', () => { - const base1CommonMethod = docSet5.getByLongname('Base1#methodOfBaseCommon')[0]; - const classCommonMethod = docSet5.getByLongname('Class#methodOfBaseCommon'); + // https://github.com/jsdoc3/jsdoc/issues/911 + xit('When a symbol inherits two methods that would both have the same longname, the last one wins', () => { + const base1CommonMethod = docSet5.getByLongname('Base1#methodOfBaseCommon')[0]; + const classCommonMethod = docSet5.getByLongname('Class#methodOfBaseCommon'); - expect(classCommonMethod).toBeArrayOfSize(1); - expect(classCommonMethod[0].description).toBe(base1CommonMethod.description); - }); + expect(classCommonMethod).toBeArrayOfSize(1); + expect(classCommonMethod[0].description).toBe(base1CommonMethod.description); + }); - it('Interfaces can augment other interfaces', () => { - const connectionOpen = docSet6.getByLongname('IConnection#open')[0]; - const closableConnectionOpen = docSet6.getByLongname('IClosableConnection#open')[0]; + it('Interfaces can augment other interfaces', () => { + const connectionOpen = docSet6.getByLongname('IConnection#open')[0]; + const closableConnectionOpen = docSet6.getByLongname('IClosableConnection#open')[0]; - expect(closableConnectionOpen).toBeObject(); - expect(closableConnectionOpen.description).toBe(connectionOpen.description); - }); + expect(closableConnectionOpen).toBeObject(); + expect(closableConnectionOpen.description).toBe(connectionOpen.description); + }); }); diff --git a/packages/jsdoc/test/specs/tags/authortag.js b/packages/jsdoc/test/specs/tags/authortag.js index 06af0713..2ca3215c 100644 --- a/packages/jsdoc/test/specs/tags/authortag.js +++ b/packages/jsdoc/test/specs/tags/authortag.js @@ -1,16 +1,16 @@ describe('@author tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/authortag.js'); - const Thingy = docSet.getByLongname('Thingy')[0]; - const Thingy2 = docSet.getByLongname('Thingy2')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/authortag.js'); + const Thingy = docSet.getByLongname('Thingy')[0]; + const Thingy2 = docSet.getByLongname('Thingy2')[0]; - it('When a symbol has a @author tag, the doclet has a author property with that value.', () => { - expect(Thingy.author).toBeArray(); - expect(Thingy.author[0]).toBe('Michael Mathews '); - }); + it('When a symbol has a @author tag, the doclet has a author property with that value.', () => { + expect(Thingy.author).toBeArray(); + expect(Thingy.author[0]).toBe('Michael Mathews '); + }); - it('When a symbol has multiple @author tags, the doclet has a author property, an array with those values.', () => { - expect(Thingy2.author).toBeArray(); - expect(Thingy2.author).toContain('Jane Doe '); - expect(Thingy2.author).toContain('John Doe '); - }); + it('When a symbol has multiple @author tags, the doclet has a author property, an array with those values.', () => { + expect(Thingy2.author).toBeArray(); + expect(Thingy2.author).toContain('Jane Doe '); + expect(Thingy2.author).toContain('John Doe '); + }); }); diff --git a/packages/jsdoc/test/specs/tags/borrowstag.js b/packages/jsdoc/test/specs/tags/borrowstag.js index 5a63de16..27ecb231 100644 --- a/packages/jsdoc/test/specs/tags/borrowstag.js +++ b/packages/jsdoc/test/specs/tags/borrowstag.js @@ -1,36 +1,38 @@ -function filterUndocumented({undocumented}) { - return !(undocumented); +function filterUndocumented({ undocumented }) { + return !undocumented; } describe('@borrows tag', () => { - it('When a symbol has a @borrows-as tag, that is added to the symbol\'s "borrowed" property.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/borrowstag.js'); - const util = docSet.getByLongname('util').filter(filterUndocumented)[0]; + it('When a symbol has a @borrows-as tag, that is added to the symbol\'s "borrowed" property.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/borrowstag.js'); + const util = docSet.getByLongname('util').filter(filterUndocumented)[0]; - expect(util.borrowed).toBeArrayOfSize(1); - expect(util.borrowed[0].from).toBe('trstr'); - expect(util.borrowed[0].as).toBe('trim'); - }); + expect(util.borrowed).toBeArrayOfSize(1); + expect(util.borrowed[0].from).toBe('trstr'); + expect(util.borrowed[0].as).toBe('trim'); + }); - it('When a symbol has a @borrows tag, the borrowed symbol is added to the symbol.', () => { - const borrow = require('jsdoc/borrow'); - const docSet = jsdoc.getDocSetFromFile('test/fixtures/borrowstag2.js'); + it('When a symbol has a @borrows tag, the borrowed symbol is added to the symbol.', () => { + const borrow = require('jsdoc/borrow'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/borrowstag2.js'); - borrow.resolveBorrows(docSet.doclets); + borrow.resolveBorrows(docSet.doclets); - const strRtrim = docSet.getByLongname('str.rtrim').filter(({undocumented}) => !(undocumented))[0]; + const strRtrim = docSet + .getByLongname('str.rtrim') + .filter(({ undocumented }) => !undocumented)[0]; - expect(strRtrim).toBeObject(); - }); + expect(strRtrim).toBeObject(); + }); - it('When a symbol has a `@borrows X as Y` tag, X and Y may contain whitespace.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/borrowstag3.js'); - const util = docSet.getByLongname('util').filter(filterUndocumented)[0]; + it('When a symbol has a `@borrows X as Y` tag, X and Y may contain whitespace.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/borrowstag3.js'); + const util = docSet.getByLongname('util').filter(filterUndocumented)[0]; - expect(util.borrowed).toBeArrayOfSize(2); - expect(util.borrowed[0].from).toBe('trstr'); - expect(util.borrowed[0].as).toBe('trim string'); - expect(util.borrowed[1].from).toBe('util.hidden util'); - expect(util.borrowed[1].as).toBe('hidden'); - }); + expect(util.borrowed).toBeArrayOfSize(2); + expect(util.borrowed[0].from).toBe('trstr'); + expect(util.borrowed[0].as).toBe('trim string'); + expect(util.borrowed[1].from).toBe('util.hidden util'); + expect(util.borrowed[1].as).toBe('hidden'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/classdesctag.js b/packages/jsdoc/test/specs/tags/classdesctag.js index 22fc97c6..d1153423 100644 --- a/packages/jsdoc/test/specs/tags/classdesctag.js +++ b/packages/jsdoc/test/specs/tags/classdesctag.js @@ -1,18 +1,18 @@ describe('@classdesc tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/classdesctag.js'); - const foo = docSet.getByLongname('Foo')[0]; - const bar = docSet.getByLongname('Bar')[0]; - const baz = docSet.getByLongname('Baz')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/classdesctag.js'); + const foo = docSet.getByLongname('Foo')[0]; + const bar = docSet.getByLongname('Bar')[0]; + const baz = docSet.getByLongname('Baz')[0]; - it('should add a classdesc property to the doclet with the description', () => { - expect(foo.classdesc).toBe('A description of the class.'); - }); + it('should add a classdesc property to the doclet with the description', () => { + expect(foo.classdesc).toBe('A description of the class.'); + }); - it('should work when the @class and @constructor tags are also present, and @class has a value', () => { - expect(bar.classdesc).toBe('A description of the class.'); - }); + it('should work when the @class and @constructor tags are also present, and @class has a value', () => { + expect(bar.classdesc).toBe('A description of the class.'); + }); - it('should infer that a description after the @class tag is a classdesc if no @classdesc tag is present', () => { - expect(baz.classdesc).toBe('Description of the Baz class.'); - }); + it('should infer that a description after the @class tag is a classdesc if no @classdesc tag is present', () => { + expect(baz.classdesc).toBe('Description of the Baz class.'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/classtag.js b/packages/jsdoc/test/specs/tags/classtag.js index bb4a9eff..933f878c 100644 --- a/packages/jsdoc/test/specs/tags/classtag.js +++ b/packages/jsdoc/test/specs/tags/classtag.js @@ -1,79 +1,80 @@ -function filter({undocumented}) { - return !undocumented; +function filter({ undocumented }) { + return !undocumented; } describe('@class tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/classtag.js'); - const ticker = docSet.getByLongname('Ticker')[0]; - const news = docSet.getByLongname('NewsSource')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/classtag.js'); + const ticker = docSet.getByLongname('Ticker')[0]; + const news = docSet.getByLongname('NewsSource')[0]; - it('When a symbol has a @class tag, the doclet has a kind property set to "class".', () => { - expect(ticker.kind).toBe('class'); + it('When a symbol has a @class tag, the doclet has a kind property set to "class".', () => { + expect(ticker.kind).toBe('class'); + }); + + it('When a symbol has a @class tag with a value, the doclet has a name property set to that value.', () => { + expect(news.kind).toBe('class'); + expect(news.longname).toBe('NewsSource'); + }); + + describe('ES 2015 classes', () => { + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/classtag2.js'); + const subscription = docSet2.getByLongname('Subscription').filter(filter)[0]; + const expire = docSet2.getByLongname('Subscription#expire')[0]; + const subscriber = docSet2.getByLongname('Subscriber').filter(filter)[0]; + const hasCallback = docSet2.getByLongname('Subscriber#hasCallback')[0]; + const expiringSubscription = docSet2 + .getByLongname('subclasses.ExpiringSubscription') + .filter(filter)[0]; + const invalidSubscriptionFoo = docSet2.getByLongname('subclasses.InvalidSubscription#foo')[0]; + + it('When a symbol is a class declaration, the doclet does not require the @class tag', () => { + expect(subscription.kind).toBe('class'); + expect(subscription.name).toBe('Subscription'); + expect(subscription.classdesc).toBe('Describe the Subscription class here.'); }); - it('When a symbol has a @class tag with a value, the doclet has a name property set to that value.', () => { - expect(news.kind).toBe('class'); - expect(news.longname).toBe('NewsSource'); + it('When a symbol is a class declaration, the constructor info is merged into the doclet for the symbol', () => { + expect(subscription.description).toBe('Describe the constructor here.'); + expect(subscription.params).toBeArrayOfSize(1); + expect(subscription.params[0].name).toBe('name'); + expect(subscription.examples).toBeArrayOfSize(1); + expect(subscription.examples[0]).toBe('var subscription = new Subscription();'); }); - describe('ES 2015 classes', () => { - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/classtag2.js'); - const subscription = docSet2.getByLongname('Subscription').filter(filter)[0]; - const expire = docSet2.getByLongname('Subscription#expire')[0]; - const subscriber = docSet2.getByLongname('Subscriber').filter(filter)[0]; - const hasCallback = docSet2.getByLongname('Subscriber#hasCallback')[0]; - const expiringSubscription = docSet2.getByLongname('subclasses.ExpiringSubscription') - .filter(filter)[0]; - const invalidSubscriptionFoo = docSet2.getByLongname('subclasses.InvalidSubscription#foo')[0]; - - it('When a symbol is a class declaration, the doclet does not require the @class tag', () => { - expect(subscription.kind).toBe('class'); - expect(subscription.name).toBe('Subscription'); - expect(subscription.classdesc).toBe('Describe the Subscription class here.'); - }); - - it('When a symbol is a class declaration, the constructor info is merged into the doclet for the symbol', () => { - expect(subscription.description).toBe('Describe the constructor here.'); - expect(subscription.params).toBeArrayOfSize(1); - expect(subscription.params[0].name).toBe('name'); - expect(subscription.examples).toBeArrayOfSize(1); - expect(subscription.examples[0]).toBe('var subscription = new Subscription();'); - }); - - it('When a symbol is a class declaration, its members get the correct longname and memberof', () => { - expect(expire.kind).toBe('function'); - expect(expire.name).toBe('expire'); - expect(expire.memberof).toBe('Subscription'); - }); - - it('When a symbol is a class expression, the doclet does not require the @class tag', () => { - expect(subscriber.kind).toBe('class'); - expect(subscriber.name).toBe('Subscriber'); - expect(subscriber.classdesc).toBe('Describe the Subscriber class here.'); - }); - - it('When a symbol is a class expression, the constructor info is merged into the doclet for the symbol', () => { - expect(subscriber.description).toBe('Describe the constructor here.'); - expect(subscriber.params).toBeArrayOfSize(1); - expect(subscriber.params[0].name).toBe('name'); - }); - - it('When a symbol is a class expression, its members get the correct longname and memberof', () => { - expect(hasCallback.kind).toBe('function'); - expect(hasCallback.name).toBe('hasCallback'); - expect(hasCallback.memberof).toBe('Subscriber'); - }); - - it('When a class expression is assigned to an object property, it is parsed correctly', () => { - expect(expiringSubscription.kind).toBe('class'); - expect(expiringSubscription.name).toBe('ExpiringSubscription'); - expect(expiringSubscription.params[0].name).toBe('name'); - }); - - it('When a class is a static memberof something else, the class\' instance methods have the correct scope', () => { - expect(invalidSubscriptionFoo.kind).toBe('function'); - expect(invalidSubscriptionFoo.name).toBe('foo'); - expect(invalidSubscriptionFoo.scope).toBe('instance'); - }); + it('When a symbol is a class declaration, its members get the correct longname and memberof', () => { + expect(expire.kind).toBe('function'); + expect(expire.name).toBe('expire'); + expect(expire.memberof).toBe('Subscription'); }); + + it('When a symbol is a class expression, the doclet does not require the @class tag', () => { + expect(subscriber.kind).toBe('class'); + expect(subscriber.name).toBe('Subscriber'); + expect(subscriber.classdesc).toBe('Describe the Subscriber class here.'); + }); + + it('When a symbol is a class expression, the constructor info is merged into the doclet for the symbol', () => { + expect(subscriber.description).toBe('Describe the constructor here.'); + expect(subscriber.params).toBeArrayOfSize(1); + expect(subscriber.params[0].name).toBe('name'); + }); + + it('When a symbol is a class expression, its members get the correct longname and memberof', () => { + expect(hasCallback.kind).toBe('function'); + expect(hasCallback.name).toBe('hasCallback'); + expect(hasCallback.memberof).toBe('Subscriber'); + }); + + it('When a class expression is assigned to an object property, it is parsed correctly', () => { + expect(expiringSubscription.kind).toBe('class'); + expect(expiringSubscription.name).toBe('ExpiringSubscription'); + expect(expiringSubscription.params[0].name).toBe('name'); + }); + + it("When a class is a static memberof something else, the class' instance methods have the correct scope", () => { + expect(invalidSubscriptionFoo.kind).toBe('function'); + expect(invalidSubscriptionFoo.name).toBe('foo'); + expect(invalidSubscriptionFoo.scope).toBe('instance'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/constanttag.js b/packages/jsdoc/test/specs/tags/constanttag.js index 589fd16b..9497aa0e 100644 --- a/packages/jsdoc/test/specs/tags/constanttag.js +++ b/packages/jsdoc/test/specs/tags/constanttag.js @@ -1,62 +1,62 @@ describe('@constant tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constanttag.js'); - const FOO = docSet.getByLongname('FOO')[0]; - const BAR = docSet.getByLongname('BAR')[0]; - const BAZ = docSet.getByLongname('BAZ')[0]; - const QUX = docSet.getByLongname('QUX')[0]; - const SOCKET = docSet.getByLongname('SOCKET')[0]; - const ROCKET = docSet.getByLongname('ROCKET')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constanttag.js'); + const FOO = docSet.getByLongname('FOO')[0]; + const BAR = docSet.getByLongname('BAR')[0]; + const BAZ = docSet.getByLongname('BAZ')[0]; + const QUX = docSet.getByLongname('QUX')[0]; + const SOCKET = docSet.getByLongname('SOCKET')[0]; + const ROCKET = docSet.getByLongname('ROCKET')[0]; - it("sets the doclet's 'kind' property to 'constant'", () => { - expect(FOO).toBeObject(); - expect(FOO.kind).toBe('constant'); + it("sets the doclet's 'kind' property to 'constant'", () => { + expect(FOO).toBeObject(); + expect(FOO.kind).toBe('constant'); - expect(BAR).toBeObject(); - expect(BAR.kind).toBe('constant'); + expect(BAR).toBeObject(); + expect(BAR.kind).toBe('constant'); - expect(BAZ).toBeObject(); - expect(BAZ.kind).toBe('constant'); + expect(BAZ).toBeObject(); + expect(BAZ.kind).toBe('constant'); - expect(QUX).toBeObject(); - expect(QUX.kind).toBe('constant'); + expect(QUX).toBeObject(); + expect(QUX.kind).toBe('constant'); - expect(SOCKET).toBeObject(); - expect(SOCKET.kind).toBe('constant'); + expect(SOCKET).toBeObject(); + expect(SOCKET.kind).toBe('constant'); - expect(ROCKET).toBeObject(); - expect(ROCKET.kind).toBe('constant'); - }); + expect(ROCKET).toBeObject(); + expect(ROCKET.kind).toBe('constant'); + }); - it('If used as a standalone, takes the name from the code', () => { - expect(FOO.name).toBe('FOO'); - }); + it('If used as a standalone, takes the name from the code', () => { + expect(FOO.name).toBe('FOO'); + }); - it('If used with just a name, sets the doclet\'s name to that', () => { - expect(BAR.name).toBe('BAR'); - }); + it("If used with just a name, sets the doclet's name to that", () => { + expect(BAR.name).toBe('BAR'); + }); - it('If used with a name and a type, sets the doclet\'s name and type appropriately', () => { - expect(BAZ.name).toBe('BAZ'); - expect(BAZ.type).toBeObject(); - expect(BAZ.type.names).toBeArrayOfSize(1); - expect(BAZ.type.names[0]).toBe('string'); - }); + it("If used with a name and a type, sets the doclet's name and type appropriately", () => { + expect(BAZ.name).toBe('BAZ'); + expect(BAZ.type).toBeObject(); + expect(BAZ.type.names).toBeArrayOfSize(1); + expect(BAZ.type.names[0]).toBe('string'); + }); - it('If used with just a type, adds the type and takes the name from the code', () => { - expect(QUX.name).toBe('QUX'); - expect(QUX.type).toBeObject(); - expect(QUX.type.names).toBeArrayOfSize(1); - expect(QUX.type.names[0]).toBe('number'); - }); + it('If used with just a type, adds the type and takes the name from the code', () => { + expect(QUX.name).toBe('QUX'); + expect(QUX.type).toBeObject(); + expect(QUX.type.names).toBeArrayOfSize(1); + expect(QUX.type.names[0]).toBe('number'); + }); - it('If used with a name and type, ignores the name in the code', () => { - expect(SOCKET.name).toBe('SOCKET'); - expect(SOCKET.type).toBeObject(); - expect(SOCKET.type.names).toBeArrayOfSize(1); - expect(SOCKET.type.names[0]).toBe('Object'); - }); + it('If used with a name and type, ignores the name in the code', () => { + expect(SOCKET.name).toBe('SOCKET'); + expect(SOCKET.type).toBeObject(); + expect(SOCKET.type.names).toBeArrayOfSize(1); + expect(SOCKET.type.names[0]).toBe('Object'); + }); - it('If used with just a name, ignores the name in the code', () => { - expect(ROCKET.name).toBe('ROCKET'); - }); + it('If used with just a name, ignores the name in the code', () => { + expect(ROCKET.name).toBe('ROCKET'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/constructortag.js b/packages/jsdoc/test/specs/tags/constructortag.js index 41106f9e..a680c731 100644 --- a/packages/jsdoc/test/specs/tags/constructortag.js +++ b/packages/jsdoc/test/specs/tags/constructortag.js @@ -1,13 +1,13 @@ describe('@constructor tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructortag.js'); - const feed = docSet.getByLongname('Feed')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructortag.js'); + const feed = docSet.getByLongname('Feed')[0]; - it('When a symbol has an @constructor tag, it is documented as a class.', () => { - expect(feed.kind).toBe('class'); - }); + it('When a symbol has an @constructor tag, it is documented as a class.', () => { + expect(feed.kind).toBe('class'); + }); - it('When a symbol has an @constructor tag and a @class tag, the value of the @class tag becomes the classdesc property.', () => { - expect(feed.classdesc).toBe('Describe your class here.'); - expect(feed.description).toBe('Describe your constructor function here.'); - }); + it('When a symbol has an @constructor tag and a @class tag, the value of the @class tag becomes the classdesc property.', () => { + expect(feed.classdesc).toBe('Describe your class here.'); + expect(feed.description).toBe('Describe your constructor function here.'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/constructstag.js b/packages/jsdoc/test/specs/tags/constructstag.js index 56ec1e55..8cf33899 100644 --- a/packages/jsdoc/test/specs/tags/constructstag.js +++ b/packages/jsdoc/test/specs/tags/constructstag.js @@ -1,49 +1,49 @@ describe('@constructs tag', () => { - it('When a symbol has a @constructs tag, it is documented as a class with that name.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag.js'); - const textblock = docSet.getByLongname('TextBlock')[0]; + it('When a symbol has a @constructs tag, it is documented as a class with that name.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag.js'); + const textblock = docSet.getByLongname('TextBlock')[0]; - expect(textblock.kind).toBe('class'); - expect(textblock.longname).toBe('TextBlock'); - }); + expect(textblock.kind).toBe('class'); + expect(textblock.longname).toBe('TextBlock'); + }); - it('When a symbol has a @constructs tag, it is documented as a class.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag2.js'); - const menu = docSet.getByLongname('Menu')[0]; + it('When a symbol has a @constructs tag, it is documented as a class.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag2.js'); + const menu = docSet.getByLongname('Menu')[0]; - expect(menu.name).toBe('Menu'); - expect(menu.kind).toBe('class'); - }); + expect(menu.name).toBe('Menu'); + expect(menu.kind).toBe('class'); + }); - it('When a function symbol has a @constructs tag, any this-variables are ducumented as instance members of the class.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag3.js'); - const personName = docSet.getByLongname('Person#name')[0]; + it('When a function symbol has a @constructs tag, any this-variables are ducumented as instance members of the class.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag3.js'); + const personName = docSet.getByLongname('Person#name')[0]; - expect(personName.memberof).toBe('Person'); - expect(personName.scope).toBe('instance'); - }); + expect(personName.memberof).toBe('Person'); + expect(personName.scope).toBe('instance'); + }); - it('When a function symbol has a @constructs tag with no value, in a @lends block with a "Name#" value, the function is documented as a constructor of "Name".', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag4.js'); - const person = docSet.getByLongname('Person').filter(({undocumented}) => !(undocumented))[0]; + it('When a function symbol has a @constructs tag with no value, in a @lends block with a "Name#" value, the function is documented as a constructor of "Name".', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag4.js'); + const person = docSet.getByLongname('Person').filter(({ undocumented }) => !undocumented)[0]; - expect(person.kind).toBe('class'); - }); + expect(person.kind).toBe('class'); + }); - it('When a function symbol has a @constructs tag with no value, any this-variables are documented as instance members of the class.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag4.js'); - const personName = docSet.getByLongname('Person#name')[0]; + it('When a function symbol has a @constructs tag with no value, any this-variables are documented as instance members of the class.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag4.js'); + const personName = docSet.getByLongname('Person#name')[0]; - expect(personName.memberof).toBe('Person'); - expect(personName.scope).toBe('instance'); - }); + expect(personName.memberof).toBe('Person'); + expect(personName.scope).toBe('instance'); + }); - it('When a object literal property has a @constructs tag with no value, and the object has a @lends, the property is documented as the lent class.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag5.js'); - const duck = docSet.getByLongname('Duck').filter(({undocumented}) => !(undocumented))[0]; + it('When a object literal property has a @constructs tag with no value, and the object has a @lends, the property is documented as the lent class.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/constructstag5.js'); + const duck = docSet.getByLongname('Duck').filter(({ undocumented }) => !undocumented)[0]; - expect(duck.longname).toBe('Duck'); - expect(duck.kind).toBe('class'); - expect(duck.description).toBe('Constructs a duck.'); - }); + expect(duck.longname).toBe('Duck'); + expect(duck.kind).toBe('class'); + expect(duck.description).toBe('Constructs a duck.'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/copyrighttag.js b/packages/jsdoc/test/specs/tags/copyrighttag.js index 36cd0fc8..8cd3b1a3 100644 --- a/packages/jsdoc/test/specs/tags/copyrighttag.js +++ b/packages/jsdoc/test/specs/tags/copyrighttag.js @@ -1,8 +1,8 @@ describe('@copyright tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/copyrighttag.js'); - const Thingy = docSet.getByLongname('Thingy')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/copyrighttag.js'); + const Thingy = docSet.getByLongname('Thingy')[0]; - it('When a symbol has a @copyright tag, the doclet has a copyright property with that value.', () => { - expect(Thingy.copyright).toBe('(c) 2011 Michael Mathews'); - }); + it('When a symbol has a @copyright tag, the doclet has a copyright property with that value.', () => { + expect(Thingy.copyright).toBe('(c) 2011 Michael Mathews'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/defaulttag.js b/packages/jsdoc/test/specs/tags/defaulttag.js index 2de99f1d..0d3a283d 100644 --- a/packages/jsdoc/test/specs/tags/defaulttag.js +++ b/packages/jsdoc/test/specs/tags/defaulttag.js @@ -1,83 +1,83 @@ describe('@default tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/defaulttag.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/defaulttag.js'); - it('When symbol set to null has a @default tag with no text, the doclet\'s defaultValue property should be: null', () => { - const request = docSet.getByLongname('request')[0]; + it("When symbol set to null has a @default tag with no text, the doclet's defaultValue property should be: null", () => { + const request = docSet.getByLongname('request')[0]; - expect(request.defaultvalue).toBeNull(); - }); + expect(request.defaultvalue).toBeNull(); + }); - it('When symbol set to a string has a @default tag with no text, the doclet\'s defaultValue property should be that string', () => { - const response = docSet.getByLongname('response')[0]; + it("When symbol set to a string has a @default tag with no text, the doclet's defaultValue property should be that string", () => { + const response = docSet.getByLongname('response')[0]; - expect(response.defaultvalue).toBe('ok'); - }); + expect(response.defaultvalue).toBe('ok'); + }); - it('When symbol set to a number has a @default tag with no text, the doclet\'s defaultValue property should be that number.', () => { - const rcode = docSet.getByLongname('rcode')[0]; + it("When symbol set to a number has a @default tag with no text, the doclet's defaultValue property should be that number.", () => { + const rcode = docSet.getByLongname('rcode')[0]; - expect(rcode.defaultvalue).toBe(200); - }); + expect(rcode.defaultvalue).toBe(200); + }); - it('When symbol has a @default tag with text, the doclet\'s defaultValue property should be that text.', () => { - const win = docSet.getByLongname('win')[0]; + it("When symbol has a @default tag with text, the doclet's defaultValue property should be that text.", () => { + const win = docSet.getByLongname('win')[0]; - expect(win.defaultvalue).toBe('the parent window'); - }); + expect(win.defaultvalue).toBe('the parent window'); + }); - it('When symbol has a @default tag with true.', () => { - const rvalid = docSet.getByLongname('rvalid')[0]; + it('When symbol has a @default tag with true.', () => { + const rvalid = docSet.getByLongname('rvalid')[0]; - expect(rvalid.defaultvalue).toBeTrue(); - }); + expect(rvalid.defaultvalue).toBeTrue(); + }); - it('When symbol has a @default tag with false.', () => { - const rerrored = docSet.getByLongname('rerrored')[0]; + it('When symbol has a @default tag with false.', () => { + const rerrored = docSet.getByLongname('rerrored')[0]; - expect(rerrored.defaultvalue).toBeFalse(); - }); + expect(rerrored.defaultvalue).toBeFalse(); + }); - it('When symbol has a @default tag with a function call.', () => { - const header = docSet.getByLongname('header')[0]; + it('When symbol has a @default tag with a function call.', () => { + const header = docSet.getByLongname('header')[0]; - expect(header.defaultvalue).toBeUndefined(); - }); + expect(header.defaultvalue).toBeUndefined(); + }); - it('When symbol has a @default tag with an object, the doclet should contain the stringified object', () => { - const obj = docSet.getByLongname('obj')[0]; - const testObj = { - valueA: 'a', - valueB: false, - valueC: 7 - }; + it('When symbol has a @default tag with an object, the doclet should contain the stringified object', () => { + const obj = docSet.getByLongname('obj')[0]; + const testObj = { + valueA: 'a', + valueB: false, + valueC: 7, + }; - expect(obj.defaultvalue).toBe( JSON.stringify(testObj) ); - expect(obj.defaultvaluetype).toBe('object'); - }); + expect(obj.defaultvalue).toBe(JSON.stringify(testObj)); + expect(obj.defaultvaluetype).toBe('object'); + }); - it('When symbol has a @default tag with a multiline object, the doclet should contain the stringified object', () => { - const multilineObject = docSet.getByLongname('multilineObject')[0]; - const testObj = { - valueA: 'a', - valueB: false, - valueC: 7 - }; + it('When symbol has a @default tag with a multiline object, the doclet should contain the stringified object', () => { + const multilineObject = docSet.getByLongname('multilineObject')[0]; + const testObj = { + valueA: 'a', + valueB: false, + valueC: 7, + }; - expect(multilineObject.defaultvalue).toBe( JSON.stringify(testObj) ); - expect(multilineObject.defaultvaluetype).toBe('object'); - }); + expect(multilineObject.defaultvalue).toBe(JSON.stringify(testObj)); + expect(multilineObject.defaultvaluetype).toBe('object'); + }); - it('When symbol has a @default tag with an array, the doclet should contain the stringified array', () => { - const arr = docSet.getByLongname('arr')[0]; - const testArray = ['foo', true, 19]; + it('When symbol has a @default tag with an array, the doclet should contain the stringified array', () => { + const arr = docSet.getByLongname('arr')[0]; + const testArray = ['foo', true, 19]; - expect(arr.defaultvalue).toBe( JSON.stringify(testArray) ); - expect(arr.defaultvaluetype).toBe('array'); - }); + expect(arr.defaultvalue).toBe(JSON.stringify(testArray)); + expect(arr.defaultvaluetype).toBe('array'); + }); - it('When symbol has a @default tag and a @type tag, the default value should be set correctly', () => { - const defaultWithType = docSet.getByLongname('defaultWithType')[0]; + it('When symbol has a @default tag and a @type tag, the default value should be set correctly', () => { + const defaultWithType = docSet.getByLongname('defaultWithType')[0]; - expect(defaultWithType.defaultvalue).toBe('a'); - }); + expect(defaultWithType.defaultvalue).toBe('a'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/definetag.js b/packages/jsdoc/test/specs/tags/definetag.js index eb0252c3..b9de4a60 100644 --- a/packages/jsdoc/test/specs/tags/definetag.js +++ b/packages/jsdoc/test/specs/tags/definetag.js @@ -1,41 +1,41 @@ describe('@define tag', () => { - describe('JSDoc tags', () => { - const env = require('jsdoc/env'); + describe('JSDoc tags', () => { + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; - }); - - it('should not recognize the @define tag', () => { - function getDocSet() { - env.conf.tags.allowUnknownTags = false; - jsdoc.replaceTagDictionary('jsdoc'); - jsdoc.getDocSetFromFile('test/fixtures/definetag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; }); - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); + it('should not recognize the @define tag', () => { + function getDocSet() { + env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); + jsdoc.getDocSetFromFile('test/fixtures/definetag.js'); + } - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); - - it('should recognize the @define tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/definetag.js'); - const enableDebug = docSet.getByLongname('ENABLE_DEBUG')[0]; - - expect(enableDebug.kind).toBe('constant'); - expect(enableDebug.type).toBeObject(); - expect(enableDebug.type.names[0]).toBe('boolean'); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + }); + + it('should recognize the @define tag', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/definetag.js'); + const enableDebug = docSet.getByLongname('ENABLE_DEBUG')[0]; + + expect(enableDebug.kind).toBe('constant'); + expect(enableDebug.type).toBeObject(); + expect(enableDebug.type.names[0]).toBe('boolean'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/deprecatedtag.js b/packages/jsdoc/test/specs/tags/deprecatedtag.js index 72cb2aed..c8622dc3 100644 --- a/packages/jsdoc/test/specs/tags/deprecatedtag.js +++ b/packages/jsdoc/test/specs/tags/deprecatedtag.js @@ -1,13 +1,13 @@ describe('@deprecated tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/deprecatedtag.js'); - const foo = docSet.getByLongname('foo')[0]; - const bar = docSet.getByLongname('bar')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/deprecatedtag.js'); + const foo = docSet.getByLongname('foo')[0]; + const bar = docSet.getByLongname('bar')[0]; - it('When a symbol has a @deprecated tag with no value, the doclet has a deprecated property set to true.', () => { - expect(foo.deprecated).toBeTrue(); - }); + it('When a symbol has a @deprecated tag with no value, the doclet has a deprecated property set to true.', () => { + expect(foo.deprecated).toBeTrue(); + }); - it('When a symbol has a @deprecated tag with a value, the doclet has a deprecated property set to that value.', () => { - expect(bar.deprecated).toBe('since version 2.0'); - }); + it('When a symbol has a @deprecated tag with a value, the doclet has a deprecated property set to that value.', () => { + expect(bar.deprecated).toBe('since version 2.0'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/descriptiontag.js b/packages/jsdoc/test/specs/tags/descriptiontag.js index 3c35dc83..abefc59a 100644 --- a/packages/jsdoc/test/specs/tags/descriptiontag.js +++ b/packages/jsdoc/test/specs/tags/descriptiontag.js @@ -1,13 +1,13 @@ describe('@description tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/descriptiontag.js'); - const doc = docSet.getByLongname('x')[0]; - const doc2 = docSet.getByLongname('y')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/descriptiontag.js'); + const doc = docSet.getByLongname('x')[0]; + const doc2 = docSet.getByLongname('y')[0]; - it('sets the doclet\'s "description" property to the description', () => { - expect(doc2.description).toBe('lkjasdf'); - }); + it('sets the doclet\'s "description" property to the description', () => { + expect(doc2.description).toBe('lkjasdf'); + }); - it('overrides the default description', () => { - expect(doc.description).toBe('halb halb halb'); - }); + it('overrides the default description', () => { + expect(doc.description).toBe('halb halb halb'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/dicttag.js b/packages/jsdoc/test/specs/tags/dicttag.js index 11454e9f..7de438f1 100644 --- a/packages/jsdoc/test/specs/tags/dicttag.js +++ b/packages/jsdoc/test/specs/tags/dicttag.js @@ -1,42 +1,42 @@ describe('@dict tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @dict tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/dicttag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @dict tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/dicttag.js'); + } - it('should not recognize the @dict tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/dicttag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @dict tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/dicttag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/enumtag.js b/packages/jsdoc/test/specs/tags/enumtag.js index 5a125266..5a7cef7a 100644 --- a/packages/jsdoc/test/specs/tags/enumtag.js +++ b/packages/jsdoc/test/specs/tags/enumtag.js @@ -1,67 +1,67 @@ describe('@enum tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/enumtag.js'); - const tristate = docSet.getByLongname('TriState')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/enumtag.js'); + const tristate = docSet.getByLongname('TriState')[0]; - it('When a symbol has an @enum tag, it has a properties array.', () => { - expect(tristate.properties).toBeArray(); + it('When a symbol has an @enum tag, it has a properties array.', () => { + expect(tristate.properties).toBeArray(); + }); + + it('If no @type is given for the property, it is inherited from the enum.', () => { + expect(tristate.properties[0].type.names.join(', ')).toBe('number'); + }); + + it('If no comment is given for the property, it is still included in the enum.', () => { + expect(tristate.properties[1].longname).toBe('TriState.FALSE'); + expect(tristate.properties[1].undocumented).toBeUndefined(); + }); + + it('A property of an enum gets its defaultvalue set.', () => { + expect(tristate.properties[1].defaultvalue).toBe(-1); + }); + + it('If a @type is given for the property, it is reflected in the property value.', () => { + expect(tristate.properties[2].type.names.join(', ')).toBe('boolean'); + }); + + it('An enum does not contain any circular references.', () => { + function dump() { + return JSON.stringify(tristate); + } + + expect(dump).not.toThrow(); + }); + + describe('numeric object properties', () => { + it('When an enum is defined with numeric object properties, the enum is parsed correctly.', () => { + const zero = docSet.getByLongname('TrueFalseNumeric.0')[0]; + + expect(zero).toBeObject(); + expect(zero.description).toBe('false'); + }); + }); + + describe('chained assignments', () => { + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/enumtag2.js'); + const pentaState = docSet2.getByLongname('module:my/enums.PentaState')[0]; + const PENTASTATE = docSet2.getByLongname('module:my/enums.PENTASTATE')[0]; + const quadState = docSet2.getByLongname('module:my/enums.QuadState')[0]; + + it('When a symbol at the start of an assignment chain has an @enum tag, that symbol has a properties array.', () => { + expect(quadState.properties).toBeArrayOfSize(4); }); - it('If no @type is given for the property, it is inherited from the enum.', () => { - expect(tristate.properties[0].type.names.join(', ')).toBe('number'); + it('When multiple symbols in an assignment chain have @enum tags, each symbol has a properties array.', () => { + expect(pentaState.properties).toBeArrayOfSize(5); + expect(PENTASTATE.properties).toBeArrayOfSize(5); }); + }); - it('If no comment is given for the property, it is still included in the enum.', () => { - expect(tristate.properties[1].longname).toBe('TriState.FALSE'); - expect(tristate.properties[1].undocumented).toBeUndefined(); - }); - - it('A property of an enum gets its defaultvalue set.', () => { - expect(tristate.properties[1].defaultvalue).toBe(-1); - }); - - it('If a @type is given for the property, it is reflected in the property value.', () => { - expect(tristate.properties[2].type.names.join(', ')).toBe('boolean'); - }); - - it('An enum does not contain any circular references.', () => { - function dump() { - return JSON.stringify(tristate); - } - - expect(dump).not.toThrow(); - }); - - describe('numeric object properties', () => { - it('When an enum is defined with numeric object properties, the enum is parsed correctly.', () => { - const zero = docSet.getByLongname('TrueFalseNumeric.0')[0]; - - expect(zero).toBeObject(); - expect(zero.description).toBe('false'); - }); - }); - - describe('chained assignments', () => { - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/enumtag2.js'); - const pentaState = docSet2.getByLongname('module:my/enums.PentaState')[0]; - const PENTASTATE = docSet2.getByLongname('module:my/enums.PENTASTATE')[0]; - const quadState = docSet2.getByLongname('module:my/enums.QuadState')[0]; - - it('When a symbol at the start of an assignment chain has an @enum tag, that symbol has a properties array.', () => { - expect(quadState.properties).toBeArrayOfSize(4); - }); - - it('When multiple symbols in an assignment chain have @enum tags, each symbol has a properties array.', () => { - expect(pentaState.properties).toBeArrayOfSize(5); - expect(PENTASTATE.properties).toBeArrayOfSize(5); - }); - }); - - describe('combined with @exports tag', () => { - const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/enumtag3.js'); - const mymodule = docSet3.getByLongname('module:mymodule')[0]; - - it('When a symbol has both an @exports tag and an @enum tag, its kind is set to `module`', () => { - expect(mymodule.kind).toBe('module'); - }); + describe('combined with @exports tag', () => { + const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/enumtag3.js'); + const mymodule = docSet3.getByLongname('module:mymodule')[0]; + + it('When a symbol has both an @exports tag and an @enum tag, its kind is set to `module`', () => { + expect(mymodule.kind).toBe('module'); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/eventfirestag.js b/packages/jsdoc/test/specs/tags/eventfirestag.js index 9460aae6..3793747d 100644 --- a/packages/jsdoc/test/specs/tags/eventfirestag.js +++ b/packages/jsdoc/test/specs/tags/eventfirestag.js @@ -1,29 +1,32 @@ describe('@event and @fires/@emits tags', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/eventfirestag.js'); - const snowballMethod = docSet.getByLongname('Hurl#snowball')[0]; - const snowballEvent = docSet.getByLongname('Hurl#event:snowball')[0]; - const footballMatchMethod = docSet.getByLongname('Hurl#footballMatch')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/eventfirestag.js'); + const snowballMethod = docSet.getByLongname('Hurl#snowball')[0]; + const snowballEvent = docSet.getByLongname('Hurl#event:snowball')[0]; + const footballMatchMethod = docSet.getByLongname('Hurl#footballMatch')[0]; - // @event tag - it('When a symbol has an @event tag, the doclet is of kind "event".', () => { - expect(snowballEvent.kind).toBe('event'); - }); + // @event tag + it('When a symbol has an @event tag, the doclet is of kind "event".', () => { + expect(snowballEvent.kind).toBe('event'); + }); - // @fires/@emits tag - it('When a symbol has a @fires tag, the doclet has an array named "fires".', () => { - expect(snowballMethod.fires).toBeArray(); - }); + // @fires/@emits tag + it('When a symbol has a @fires tag, the doclet has an array named "fires".', () => { + expect(snowballMethod.fires).toBeArray(); + }); - it('When a symbol has an @emits tag, the doclet has an array named "fires".', () => { - expect(footballMatchMethod.fires).toBeArray(); - }); + it('When a symbol has an @emits tag, the doclet has an array named "fires".', () => { + expect(footballMatchMethod.fires).toBeArray(); + }); - it('When a symbol has a "fires" array, the members have the "event:" namespace.', () => { - expect(snowballMethod.fires[0]).toBe('Hurl#event:snowball'); - }); + it('When a symbol has a "fires" array, the members have the "event:" namespace.', () => { + expect(snowballMethod.fires[0]).toBe('Hurl#event:snowball'); + }); - it('When a symbol has a "fires" array with a name that already has an "event:" namespace, ' + - 'it does not have a second namespace applied.', () => { - expect(snowballMethod.fires[1]).toBe('Hurl#event:brick'); - }); + it( + 'When a symbol has a "fires" array with a name that already has an "event:" namespace, ' + + 'it does not have a second namespace applied.', + () => { + expect(snowballMethod.fires[1]).toBe('Hurl#event:brick'); + } + ); }); diff --git a/packages/jsdoc/test/specs/tags/exampletag.js b/packages/jsdoc/test/specs/tags/exampletag.js index f0d27827..b1ebd5b2 100644 --- a/packages/jsdoc/test/specs/tags/exampletag.js +++ b/packages/jsdoc/test/specs/tags/exampletag.js @@ -1,18 +1,18 @@ describe('@example tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exampletag.js'); - const doc = docSet.getByLongname('x')[0]; - const doc2 = docSet.getByLongname('y')[0]; - const txtRegExp = /console\.log\("foo"\);[\r\n]{1,2}console\.log\("bar"\)/; - const txt2RegExp = /Example 2<\/caption>[\r\n]{1,2}1 \+ 2;/; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exampletag.js'); + const doc = docSet.getByLongname('x')[0]; + const doc2 = docSet.getByLongname('y')[0]; + const txtRegExp = /console\.log\("foo"\);[\r\n]{1,2}console\.log\("bar"\)/; + const txt2RegExp = /Example 2<\/caption>[\r\n]{1,2}1 \+ 2;/; - it("creates an 'examples' property on the doclet with the example", () => { - expect(doc.examples).toBeArrayOfSize(1); - expect(doc.examples).toMatch(txtRegExp); - }); + it("creates an 'examples' property on the doclet with the example", () => { + expect(doc.examples).toBeArrayOfSize(1); + expect(doc.examples).toMatch(txtRegExp); + }); - it('can be specified multiple times on one doclet', () => { - expect(doc2.examples).toBeArrayOfSize(2); - expect(doc2.examples).toMatch(txtRegExp); - expect(doc2.examples).toMatch(txt2RegExp); - }); + it('can be specified multiple times on one doclet', () => { + expect(doc2.examples).toBeArrayOfSize(2); + expect(doc2.examples).toMatch(txtRegExp); + expect(doc2.examples).toMatch(txt2RegExp); + }); }); diff --git a/packages/jsdoc/test/specs/tags/exceptiontag.js b/packages/jsdoc/test/specs/tags/exceptiontag.js index 63437f16..df47bbbb 100644 --- a/packages/jsdoc/test/specs/tags/exceptiontag.js +++ b/packages/jsdoc/test/specs/tags/exceptiontag.js @@ -1,24 +1,24 @@ describe('@exception tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exceptiontag.js'); - const foo = docSet.getByLongname('foo')[0]; - const bar = docSet.getByLongname('bar')[0]; - const pez = docSet.getByLongname('pez')[0]; - const cos = docSet.getByLongname('cos')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exceptiontag.js'); + const foo = docSet.getByLongname('foo')[0]; + const bar = docSet.getByLongname('bar')[0]; + const pez = docSet.getByLongname('pez')[0]; + const cos = docSet.getByLongname('cos')[0]; - it('When a symbol has an @exception tag, the doclet has a exception property set to that value.', () => { - expect(foo.exceptions).toBeArrayOfSize(1); - expect(bar.exceptions).toBeArrayOfSize(1); - expect(pez.exceptions).toBeArrayOfSize(1); - }); + it('When a symbol has an @exception tag, the doclet has a exception property set to that value.', () => { + expect(foo.exceptions).toBeArrayOfSize(1); + expect(bar.exceptions).toBeArrayOfSize(1); + expect(pez.exceptions).toBeArrayOfSize(1); + }); - it('The description and type for the @exception tag are not added to the parent doclet.', () => { - expect(pez.description).not.toBeDefined(); - expect(pez.type).toBeUndefined(); - }); + it('The description and type for the @exception tag are not added to the parent doclet.', () => { + expect(pez.description).not.toBeDefined(); + expect(pez.type).toBeUndefined(); + }); - it('When a symbol has a description, plus an @exception tag with a description, neither description overwrites the other.', () => { - expect(cos.description).toBe('A description of the function.'); - expect(cos.exceptions).toBeArrayOfSize(1); - expect(cos.exceptions[0].description).toBe('A description of the exception.'); - }); + it('When a symbol has a description, plus an @exception tag with a description, neither description overwrites the other.', () => { + expect(cos.description).toBe('A description of the function.'); + expect(cos.exceptions).toBeArrayOfSize(1); + expect(cos.exceptions[0].description).toBe('A description of the exception.'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/exportstag.js b/packages/jsdoc/test/specs/tags/exportstag.js index 7a8df666..838a7d2f 100644 --- a/packages/jsdoc/test/specs/tags/exportstag.js +++ b/packages/jsdoc/test/specs/tags/exportstag.js @@ -1,210 +1,210 @@ describe('@exports tag', () => { - describe('object literals', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag.js'); - const shirt = docSet.getByLongname('module:my/shirt')[0]; - const color = docSet.getByLongname('module:my/shirt.color')[0]; - const tneck = docSet.getByLongname('module:my/shirt.Turtleneck')[0]; - const size = docSet.getByLongname('module:my/shirt.Turtleneck#size')[0]; + describe('object literals', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag.js'); + const shirt = docSet.getByLongname('module:my/shirt')[0]; + const color = docSet.getByLongname('module:my/shirt.color')[0]; + const tneck = docSet.getByLongname('module:my/shirt.Turtleneck')[0]; + const size = docSet.getByLongname('module:my/shirt.Turtleneck#size')[0]; - it('When an objlit symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { - expect(shirt).toBeObject(); - expect(shirt.alias).toBe('my/shirt'); - expect(shirt.undocumented).toBeUndefined(); - }); - - it('When an objlit symbol has an @exports tag, the doclet\'s longname includes the "module:" namespace.', () => { - expect(shirt.longname).toBe('module:my/shirt'); - }); - - it('When an objlit symbol has an @exports tag, the doclet kind is set to module.', () => { - expect(shirt.kind).toBe('module'); - }); - - it('When an objlit symbol has an @exports tag, the module doclet does not have a scope.', () => { - expect(shirt.scope).toBeUndefined(); - }); - - it('When an objlit symbol has an @exports tag, the objlit members are documented as members of the module.', () => { - expect(color).toBeObject(); - expect(color.memberof).toBe('module:my/shirt'); - - expect(tneck).toBeObject(); - expect(tneck.memberof).toBe('module:my/shirt'); - - expect(size).toBeObject(); - expect(size.memberof).toBe('module:my/shirt.Turtleneck'); - }); + it('When an objlit symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { + expect(shirt).toBeObject(); + expect(shirt.alias).toBe('my/shirt'); + expect(shirt.undocumented).toBeUndefined(); }); - describe('functions', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag2.js'); - const coat = docSet.getByLongname('module:my/coat')[0]; - const wool = docSet.getByLongname('module:my/coat#wool')[0]; - - it('When a function symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { - expect(coat).toBeObject(); - expect(coat.alias).toBe('my/coat'); - }); - - it('When a function symbol has an @exports tag, the doclet\'s longname includes the "module:" namespace.', () => { - expect(coat.longname).toBe('module:my/coat'); - }); - - it('When a function symbol has an @exports tag, the doclet kind is set to module.', () => { - expect(coat.kind).toBe('module'); - }); - - it('When a function symbol has an @exports tag, the module doclet does not have a scope.', () => { - expect(coat.scope).toBeUndefined(); - }); - - it('When a function symbol has an @exports tag, the this members are documented as instance members of the module.', () => { - expect(wool).toBeObject(); - expect(wool.memberof).toBe('module:my/coat'); - }); + it('When an objlit symbol has an @exports tag, the doclet\'s longname includes the "module:" namespace.', () => { + expect(shirt.longname).toBe('module:my/shirt'); }); - describe("functions and 'exports' object", () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag3.js'); - const html = docSet.getByLongname('module:html/utils')[0]; - const getstyle = docSet.getByLongname('module:html/utils.getStyleProperty')[0]; - const inhead = docSet.getByLongname('module:html/utils.isInHead')[0]; - - it('When a function symbol has an @exports tag, the module doclet does not have a scope.', () => { - expect(html.scope).toBeUndefined(); - }); - - it('When a function symbol has an @exports tag and there is an objlit named "exports" the members are documented as members of the module.', () => { - expect(getstyle).toBeObject(); - expect(getstyle.memberof).toBe('module:html/utils'); - }); - - it('When a function symbol has an @exports tag and there are members assigned to an "exports" name, the members are documented as members of the module.', () => { - expect(inhead).toBeObject(); - expect(inhead.memberof).toBe('module:html/utils'); - }); + it('When an objlit symbol has an @exports tag, the doclet kind is set to module.', () => { + expect(shirt.kind).toBe('module'); }); - describe('inner classes', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag4.js'); - const module = docSet.getByLongname('module:some/module')[0]; - const innerClass = docSet.getByLongname('module:some/module~myClass')[0]; - const method = docSet.getByLongname('module:some/module~myClass#myMethod')[0]; - - it('When a function symbol has an @exports tag, the module doclet does not have a scope.', () => { - expect(module.scope).toBeUndefined(); - }); - - it('An inner class declared as a function in a module should be documented.', () => { - expect(innerClass).toBeObject(); - }); - - it('A method of an inner class declared as a function in a module should be documented.', () => { - expect(method).toBeObject(); - }); + it('When an objlit symbol has an @exports tag, the module doclet does not have a scope.', () => { + expect(shirt.scope).toBeUndefined(); }); - describe('variable shadowing', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag5.js'); - const foo = docSet.getByLongname('module:Foo')[0]; - const method = docSet.getByLongname('module:Foo#bar')[0]; + it('When an objlit symbol has an @exports tag, the objlit members are documented as members of the module.', () => { + expect(color).toBeObject(); + expect(color.memberof).toBe('module:my/shirt'); - it('When a var has an @exports tag, the module doclet does not have a scope.', () => { - expect(foo.scope).toBeUndefined(); - }); + expect(tneck).toBeObject(); + expect(tneck.memberof).toBe('module:my/shirt'); - it('A variable defined in an inner scope should correctly shadow a variable in an outer scope.', () => { - expect(method.description).toBe('This should be in the Foo module doc.'); - }); + expect(size).toBeObject(); + expect(size.memberof).toBe('module:my/shirt.Turtleneck'); + }); + }); + + describe('functions', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag2.js'); + const coat = docSet.getByLongname('module:my/coat')[0]; + const wool = docSet.getByLongname('module:my/coat#wool')[0]; + + it('When a function symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { + expect(coat).toBeObject(); + expect(coat.alias).toBe('my/coat'); }); - describe("'exports' object as a parameter to 'define'", () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag6.js'); - const shirt = docSet.getByLongname('module:my/shirt')[0]; - const color = docSet.getByLongname('module:my/shirt.color')[0]; - const tneck = docSet.getByLongname('module:my/shirt.Turtleneck')[0]; - const size = docSet.getByLongname('module:my/shirt.Turtleneck#size')[0]; - - it('When a param has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { - expect(shirt).toBeObject(); - expect(shirt.alias).toBe('my/shirt'); - expect(shirt.undocumented).toBeUndefined(); - }); - - it('When a param has an @exports tag, the doclet\'s longname includes the "module:" namespace.', () => { - expect(shirt.longname).toBe('module:my/shirt'); - }); - - it('When a param has an @exports tag, the doclet kind is set to module.', () => { - expect(shirt.kind).toBe('module'); - }); - - it('When a param has an @exports tag, the module doclet does not have a scope.', () => { - expect(shirt.scope).toBeUndefined(); - }); - - it('When a param has an @exports tag, the properties added to the param are documented as members of the module.', () => { - expect(color).toBeObject(); - expect(color.memberof).toBe('module:my/shirt'); - - expect(tneck).toBeObject(); - expect(tneck.memberof).toBe('module:my/shirt'); - - expect(size).toBeObject(); - expect(size.memberof).toBe('module:my/shirt.Turtleneck'); - }); + it('When a function symbol has an @exports tag, the doclet\'s longname includes the "module:" namespace.', () => { + expect(coat.longname).toBe('module:my/coat'); }); - describe("alias to the 'exports' object", () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag7.js'); - const shirt = docSet.getByLongname('module:my/shirt')[0]; - const color = docSet.getByLongname('module:my/shirt.color')[0]; - const tneck = docSet.getByLongname('module:my/shirt.Turtleneck')[0]; - const size = docSet.getByLongname('module:my/shirt.Turtleneck#size')[0]; - const iron = docSet.getByLongname('module:my/shirt.Turtleneck#iron')[0]; - - it('When a symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { - expect(shirt).toBeObject(); - expect(shirt.alias).toBe('my/shirt'); - expect(shirt.undocumented).toBeUndefined(); - }); - - it('When a symbol has an @exports tag, the doclet kind is set to module.', () => { - expect(shirt.kind).toBe('module'); - }); - - it('When a symbol has an @exports tag, the module doclet does not have a scope.', () => { - expect(shirt.scope).toBeUndefined(); - }); - - it('When a symbol tagged with @exports is an alias to "exports", the symbol properties are documented as members of the module.', () => { - expect(color).toBeObject(); - expect(color.memberof).toBe('module:my/shirt'); - - expect(tneck).toBeObject(); - expect(tneck.memberof).toBe('module:my/shirt'); - }); - - it('When a symbol tagged with @exports is an alias to "exports", and a symbol property contains a class, the instance members of the class are documented correctly.', () => { - expect(size).toBeObject(); - expect(size.name).toBe('size'); - expect(size.memberof).toBe('module:my/shirt.Turtleneck'); - expect(size.scope).toBe('instance'); - - expect(iron).toBeObject(); - expect(iron.name).toBe('iron'); - expect(iron.memberof).toBe('module:my/shirt.Turtleneck'); - expect(iron.scope).toBe('instance'); - }); + it('When a function symbol has an @exports tag, the doclet kind is set to module.', () => { + expect(coat.kind).toBe('module'); }); - describe('"module:" namespace included in the name', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag8.js'); - const shirt = docSet.getByLongname('module:my/shirt')[0]; - - it('When the name for an @exports tag begins with the "module:" namespace, we remove the namespace', () => { - expect(shirt).toBeObject(); - expect(shirt.name).toBe('my/shirt'); - }); + it('When a function symbol has an @exports tag, the module doclet does not have a scope.', () => { + expect(coat.scope).toBeUndefined(); }); + + it('When a function symbol has an @exports tag, the this members are documented as instance members of the module.', () => { + expect(wool).toBeObject(); + expect(wool.memberof).toBe('module:my/coat'); + }); + }); + + describe("functions and 'exports' object", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag3.js'); + const html = docSet.getByLongname('module:html/utils')[0]; + const getstyle = docSet.getByLongname('module:html/utils.getStyleProperty')[0]; + const inhead = docSet.getByLongname('module:html/utils.isInHead')[0]; + + it('When a function symbol has an @exports tag, the module doclet does not have a scope.', () => { + expect(html.scope).toBeUndefined(); + }); + + it('When a function symbol has an @exports tag and there is an objlit named "exports" the members are documented as members of the module.', () => { + expect(getstyle).toBeObject(); + expect(getstyle.memberof).toBe('module:html/utils'); + }); + + it('When a function symbol has an @exports tag and there are members assigned to an "exports" name, the members are documented as members of the module.', () => { + expect(inhead).toBeObject(); + expect(inhead.memberof).toBe('module:html/utils'); + }); + }); + + describe('inner classes', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag4.js'); + const module = docSet.getByLongname('module:some/module')[0]; + const innerClass = docSet.getByLongname('module:some/module~myClass')[0]; + const method = docSet.getByLongname('module:some/module~myClass#myMethod')[0]; + + it('When a function symbol has an @exports tag, the module doclet does not have a scope.', () => { + expect(module.scope).toBeUndefined(); + }); + + it('An inner class declared as a function in a module should be documented.', () => { + expect(innerClass).toBeObject(); + }); + + it('A method of an inner class declared as a function in a module should be documented.', () => { + expect(method).toBeObject(); + }); + }); + + describe('variable shadowing', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag5.js'); + const foo = docSet.getByLongname('module:Foo')[0]; + const method = docSet.getByLongname('module:Foo#bar')[0]; + + it('When a var has an @exports tag, the module doclet does not have a scope.', () => { + expect(foo.scope).toBeUndefined(); + }); + + it('A variable defined in an inner scope should correctly shadow a variable in an outer scope.', () => { + expect(method.description).toBe('This should be in the Foo module doc.'); + }); + }); + + describe("'exports' object as a parameter to 'define'", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag6.js'); + const shirt = docSet.getByLongname('module:my/shirt')[0]; + const color = docSet.getByLongname('module:my/shirt.color')[0]; + const tneck = docSet.getByLongname('module:my/shirt.Turtleneck')[0]; + const size = docSet.getByLongname('module:my/shirt.Turtleneck#size')[0]; + + it('When a param has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { + expect(shirt).toBeObject(); + expect(shirt.alias).toBe('my/shirt'); + expect(shirt.undocumented).toBeUndefined(); + }); + + it('When a param has an @exports tag, the doclet\'s longname includes the "module:" namespace.', () => { + expect(shirt.longname).toBe('module:my/shirt'); + }); + + it('When a param has an @exports tag, the doclet kind is set to module.', () => { + expect(shirt.kind).toBe('module'); + }); + + it('When a param has an @exports tag, the module doclet does not have a scope.', () => { + expect(shirt.scope).toBeUndefined(); + }); + + it('When a param has an @exports tag, the properties added to the param are documented as members of the module.', () => { + expect(color).toBeObject(); + expect(color.memberof).toBe('module:my/shirt'); + + expect(tneck).toBeObject(); + expect(tneck.memberof).toBe('module:my/shirt'); + + expect(size).toBeObject(); + expect(size.memberof).toBe('module:my/shirt.Turtleneck'); + }); + }); + + describe("alias to the 'exports' object", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag7.js'); + const shirt = docSet.getByLongname('module:my/shirt')[0]; + const color = docSet.getByLongname('module:my/shirt.color')[0]; + const tneck = docSet.getByLongname('module:my/shirt.Turtleneck')[0]; + const size = docSet.getByLongname('module:my/shirt.Turtleneck#size')[0]; + const iron = docSet.getByLongname('module:my/shirt.Turtleneck#iron')[0]; + + it('When a symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', () => { + expect(shirt).toBeObject(); + expect(shirt.alias).toBe('my/shirt'); + expect(shirt.undocumented).toBeUndefined(); + }); + + it('When a symbol has an @exports tag, the doclet kind is set to module.', () => { + expect(shirt.kind).toBe('module'); + }); + + it('When a symbol has an @exports tag, the module doclet does not have a scope.', () => { + expect(shirt.scope).toBeUndefined(); + }); + + it('When a symbol tagged with @exports is an alias to "exports", the symbol properties are documented as members of the module.', () => { + expect(color).toBeObject(); + expect(color.memberof).toBe('module:my/shirt'); + + expect(tneck).toBeObject(); + expect(tneck.memberof).toBe('module:my/shirt'); + }); + + it('When a symbol tagged with @exports is an alias to "exports", and a symbol property contains a class, the instance members of the class are documented correctly.', () => { + expect(size).toBeObject(); + expect(size.name).toBe('size'); + expect(size.memberof).toBe('module:my/shirt.Turtleneck'); + expect(size.scope).toBe('instance'); + + expect(iron).toBeObject(); + expect(iron.name).toBe('iron'); + expect(iron.memberof).toBe('module:my/shirt.Turtleneck'); + expect(iron.scope).toBe('instance'); + }); + }); + + describe('"module:" namespace included in the name', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/exportstag8.js'); + const shirt = docSet.getByLongname('module:my/shirt')[0]; + + it('When the name for an @exports tag begins with the "module:" namespace, we remove the namespace', () => { + expect(shirt).toBeObject(); + expect(shirt.name).toBe('my/shirt'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/exporttag.js b/packages/jsdoc/test/specs/tags/exporttag.js index 9110065f..e3460263 100644 --- a/packages/jsdoc/test/specs/tags/exporttag.js +++ b/packages/jsdoc/test/specs/tags/exporttag.js @@ -1,42 +1,42 @@ describe('@export tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @export tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/exporttag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @export tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/exporttag.js'); + } - it('should not recognize the @export tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/exporttag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @export tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/exporttag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/externaltag.js b/packages/jsdoc/test/specs/tags/externaltag.js index 3daf885d..d4359cbe 100644 --- a/packages/jsdoc/test/specs/tags/externaltag.js +++ b/packages/jsdoc/test/specs/tags/externaltag.js @@ -1,34 +1,33 @@ describe('@external tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/externaltag.js'); - // TODO: why don't we test anything from docSet2? - // var docSet2 = jsdoc.getDocSetFromFile('test/fixtures/externaltag2.js'); - const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/externaltag3.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/externaltag.js'); + // TODO: why don't we test anything from docSet2? + // var docSet2 = jsdoc.getDocSetFromFile('test/fixtures/externaltag2.js'); + const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/externaltag3.js'); - const fooBarBazExternal = docSet3.getByLongname('external:"foo.bar.baz"')[0]; - const jQueryExternal = docSet.getByLongname('external:"jQuery.fn"')[0]; - const stringExternal = docSet.getByLongname('external:String')[0]; + const fooBarBazExternal = docSet3.getByLongname('external:"foo.bar.baz"')[0]; + const jQueryExternal = docSet.getByLongname('external:"jQuery.fn"')[0]; + const stringExternal = docSet.getByLongname('external:String')[0]; + it('An @external should have its own doclet', () => { + expect(stringExternal).toBeObject(); + }); - it('An @external should have its own doclet', () => { - expect(stringExternal).toBeObject(); - }); + it("An @external's name should be the same as its longname, minus 'external:'", () => { + expect(stringExternal.name).toBe('String'); + }); - it("An @external's name should be the same as its longname, minus 'external:'", () => { - expect(stringExternal.name).toBe('String'); - }); + it('An @external should have its kind set to "external"', () => { + expect(stringExternal.kind).toBe('external'); + }); - it('An @external should have its kind set to "external"', () => { - expect(stringExternal.kind).toBe('external'); - }); + it('An @external with a quoted name should get the correct name', () => { + expect(jQueryExternal).toBeObject(); + expect(jQueryExternal.name).toBe('"jQuery.fn"'); + }); - it('An @external with a quoted name should get the correct name', () => { - expect(jQueryExternal).toBeObject(); - expect(jQueryExternal.name).toBe('"jQuery.fn"'); - }); - - // TODO: enable after jsdoc3/jsdoc#652 is fixed - xit('An @external should work correctly when the type is in curly braces', () => { - expect(fooBarBazExternal).toBeObject(); - expect(fooBarBazExternal.name).toBe('"foo.bar.baz"'); - }); + // TODO: enable after jsdoc3/jsdoc#652 is fixed + xit('An @external should work correctly when the type is in curly braces', () => { + expect(fooBarBazExternal).toBeObject(); + expect(fooBarBazExternal.name).toBe('"foo.bar.baz"'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/externstag.js b/packages/jsdoc/test/specs/tags/externstag.js index ae490848..12c2bd5f 100644 --- a/packages/jsdoc/test/specs/tags/externstag.js +++ b/packages/jsdoc/test/specs/tags/externstag.js @@ -1,42 +1,42 @@ describe('@externs tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @externs tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/externstag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @externs tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/externstag.js'); + } - it('should not recognize the @externs tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/externstag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @externs tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/externstag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/fileoverviewtag.js b/packages/jsdoc/test/specs/tags/fileoverviewtag.js index 0084a0bf..d793262f 100644 --- a/packages/jsdoc/test/specs/tags/fileoverviewtag.js +++ b/packages/jsdoc/test/specs/tags/fileoverviewtag.js @@ -1,26 +1,26 @@ describe('@fileoverview tag', () => { - describe('JSDoc tags', () => { - // @fileoverview is a synonym of @file, so this is covered by the @file tag tests + describe('JSDoc tags', () => { + // @fileoverview is a synonym of @file, so this is covered by the @file tag tests + }); + + describe('Closure Compiler tags', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/fileoverviewtag.js'); + const fileDoc = docSet.getByLongname('[[string0]]')[0]; + + it("should set the doclet's name and longname to the file name", () => { + expect(fileDoc.name).toBe('[[string0]]'); }); - describe('Closure Compiler tags', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/fileoverviewtag.js'); - const fileDoc = docSet.getByLongname('[[string0]]')[0]; - - it('should set the doclet\'s name and longname to the file name', () => { - expect(fileDoc.name).toBe('[[string0]]'); - }); - - it('should set the doclet\'s kind to `file`', () => { - expect(fileDoc.kind).toBe('file'); - }); - - it('should use the value as a description', () => { - expect(fileDoc.description).toBe('Overview of this file.'); - }); - - it('should set `preserveName` to `true`', () => { - expect(fileDoc.preserveName).toBe(true); - }); + it("should set the doclet's kind to `file`", () => { + expect(fileDoc.kind).toBe('file'); }); + + it('should use the value as a description', () => { + expect(fileDoc.description).toBe('Overview of this file.'); + }); + + it('should set `preserveName` to `true`', () => { + expect(fileDoc.preserveName).toBe(true); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/filetag.js b/packages/jsdoc/test/specs/tags/filetag.js index c5e37beb..b226a1cc 100644 --- a/packages/jsdoc/test/specs/tags/filetag.js +++ b/packages/jsdoc/test/specs/tags/filetag.js @@ -1,3 +1,3 @@ xdescribe('@file tag', () => { - // TODO: add tests + // TODO: add tests }); diff --git a/packages/jsdoc/test/specs/tags/functiontag.js b/packages/jsdoc/test/specs/tags/functiontag.js index bfb8165d..33f20ad6 100644 --- a/packages/jsdoc/test/specs/tags/functiontag.js +++ b/packages/jsdoc/test/specs/tags/functiontag.js @@ -1,18 +1,18 @@ describe('@function tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/functiontag.js'); - const doc = docSet.getByLongname('Foo')[0]; - const doc2 = docSet.getByLongname('Bar')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/functiontag.js'); + const doc = docSet.getByLongname('Foo')[0]; + const doc2 = docSet.getByLongname('Bar')[0]; - it('sets the doclet\'s kind to "function"', () => { - expect(doc.kind).toBe('function'); - expect(doc2.kind).toBe('function'); - }); + it('sets the doclet\'s kind to "function"', () => { + expect(doc.kind).toBe('function'); + expect(doc2.kind).toBe('function'); + }); - it('sets the doclet\'s name to the tag value, if provided', () => { - expect(doc.name).toBe('Foo'); - expect(doc2.name).toBe('Bar'); - }); + it("sets the doclet's name to the tag value, if provided", () => { + expect(doc.name).toBe('Foo'); + expect(doc2.name).toBe('Bar'); + }); - // parameter etc tests take place elsewhere: on its own, all @func does is - // set doclet.kind to function and sets the doclet's name. + // parameter etc tests take place elsewhere: on its own, all @func does is + // set doclet.kind to function and sets the doclet's name. }); diff --git a/packages/jsdoc/test/specs/tags/generatortag.js b/packages/jsdoc/test/specs/tags/generatortag.js index bf7a98e0..67daf663 100644 --- a/packages/jsdoc/test/specs/tags/generatortag.js +++ b/packages/jsdoc/test/specs/tags/generatortag.js @@ -1,8 +1,8 @@ describe('@generator tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/generatortag.js'); - const idMaker = docSet.getByLongname('idMaker')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/generatortag.js'); + const idMaker = docSet.getByLongname('idMaker')[0]; - it('should mark the symbol as a generator function', () => { - expect(idMaker.generator).toBeTrue(); - }); + it('should mark the symbol as a generator function', () => { + expect(idMaker.generator).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/globaltag.js b/packages/jsdoc/test/specs/tags/globaltag.js index 0c0a7cf1..f4f38318 100644 --- a/packages/jsdoc/test/specs/tags/globaltag.js +++ b/packages/jsdoc/test/specs/tags/globaltag.js @@ -1,21 +1,21 @@ describe('@global tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/globaltag.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/globaltag.js'); - it('When an inner symbol has a @global tag it is documented as if it were global.', () => { - const found = docSet.getByLongname('foo').filter(({undocumented}) => !(undocumented)); + it('When an inner symbol has a @global tag it is documented as if it were global.', () => { + const found = docSet.getByLongname('foo').filter(({ undocumented }) => !undocumented); - expect(found[0].name).toBe('foo'); - expect(found[0].longname).toBe('foo'); - expect(found[0].memberof).toBeUndefined(); - expect(found[0].scope).toBe('global'); - }); + expect(found[0].name).toBe('foo'); + expect(found[0].longname).toBe('foo'); + expect(found[0].memberof).toBeUndefined(); + expect(found[0].scope).toBe('global'); + }); - it('When an nested symbol has a @global tag it is documented as if it were global.', () => { - const found = docSet.getByLongname('Bar').filter(({undocumented}) => !(undocumented)); + it('When an nested symbol has a @global tag it is documented as if it were global.', () => { + const found = docSet.getByLongname('Bar').filter(({ undocumented }) => !undocumented); - expect(found[0].name).toBe('Bar'); - expect(found[0].longname).toBe('Bar'); - expect(found[0].memberof).toBeUndefined(); - expect(found[0].scope).toBe('global'); - }); + expect(found[0].name).toBe('Bar'); + expect(found[0].longname).toBe('Bar'); + expect(found[0].memberof).toBeUndefined(); + expect(found[0].scope).toBe('global'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/hideconstructortag.js b/packages/jsdoc/test/specs/tags/hideconstructortag.js index 464f5504..55ddb117 100644 --- a/packages/jsdoc/test/specs/tags/hideconstructortag.js +++ b/packages/jsdoc/test/specs/tags/hideconstructortag.js @@ -1,14 +1,15 @@ describe('@hideconstructor tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/hideconstructortag.js'); - const toaster = docSet.getByLongname('Toaster')[0]; - const waffleIron = docSet.getByLongname('WaffleIron').filter(({undocumented}) => !undocumented)[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/hideconstructortag.js'); + const toaster = docSet.getByLongname('Toaster')[0]; + const waffleIron = docSet + .getByLongname('WaffleIron') + .filter(({ undocumented }) => !undocumented)[0]; - it('should add a `hideconstructor` attribute to pre-ES2015 classes', () => { - expect(toaster.hideconstructor).toBeTrue(); - }); + it('should add a `hideconstructor` attribute to pre-ES2015 classes', () => { + expect(toaster.hideconstructor).toBeTrue(); + }); - it('should add a `hideconstructor` attribute to ES2015 classes when the constructor is tagged', - () => { - expect(waffleIron.hideconstructor).toBeTrue(); - }); + it('should add a `hideconstructor` attribute to ES2015 classes when the constructor is tagged', () => { + expect(waffleIron.hideconstructor).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/ignoretag.js b/packages/jsdoc/test/specs/tags/ignoretag.js index 71f82799..2cb312e5 100644 --- a/packages/jsdoc/test/specs/tags/ignoretag.js +++ b/packages/jsdoc/test/specs/tags/ignoretag.js @@ -1,16 +1,16 @@ describe('@ignore tag', () => { - it('When a symbol has an @ignore tag, the doclet has a ignore property set to true.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/ignoretag.js'); - const foo = docSet.getByLongname('foo')[0]; + it('When a symbol has an @ignore tag, the doclet has a ignore property set to true.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/ignoretag.js'); + const foo = docSet.getByLongname('foo')[0]; - expect(foo.ignore).toBe(true); - }); + expect(foo.ignore).toBe(true); + }); - it('When a symbol has an @ignore tag with a value a warning is logged', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/ignoretag2.js'); - } + it('When a symbol has an @ignore tag with a value a warning is logged', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/ignoretag2.js'); + } - expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); - }); + expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/implementstag.js b/packages/jsdoc/test/specs/tags/implementstag.js index e379fd29..de29fdd5 100644 --- a/packages/jsdoc/test/specs/tags/implementstag.js +++ b/packages/jsdoc/test/specs/tags/implementstag.js @@ -1,30 +1,32 @@ describe('@implements tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/interface-implements.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/interface-implements.js'); - const myTester = docSet.getByLongname('MyTester')[0]; - const beforeEachMethod = docSet.getByLongname('MyTester#beforeEach')[0]; - const itMethod = docSet.getByLongname('MyTester#it').filter(({undocumented}) => !undocumented)[0]; - const processMethod = docSet.getByLongname('MyWorker#process')[0]; + const myTester = docSet.getByLongname('MyTester')[0]; + const beforeEachMethod = docSet.getByLongname('MyTester#beforeEach')[0]; + const itMethod = docSet + .getByLongname('MyTester#it') + .filter(({ undocumented }) => !undocumented)[0]; + const processMethod = docSet.getByLongname('MyWorker#process')[0]; - it('MyTester has an "implements" array', () => { - expect(myTester.implements).toBeArrayOfSize(1); - expect(myTester.implements[0]).toBe('ITester'); - }); + it('MyTester has an "implements" array', () => { + expect(myTester.implements).toBeArrayOfSize(1); + expect(myTester.implements[0]).toBe('ITester'); + }); - it('beforeEach has an "implements" array', () => { - expect(beforeEachMethod.implements).toBeArrayOfSize(1); - expect(beforeEachMethod.implements[0]).toBe('ITester#beforeEach'); - }); + it('beforeEach has an "implements" array', () => { + expect(beforeEachMethod.implements).toBeArrayOfSize(1); + expect(beforeEachMethod.implements[0]).toBe('ITester#beforeEach'); + }); - it('MyTester#it inherits the docs from ITester#it', () => { - expect(itMethod.description).toBe('it method.'); - }); + it('MyTester#it inherits the docs from ITester#it', () => { + expect(itMethod.description).toBe('it method.'); + }); - it('MyWorker\'s process() method does not implement an interface', () => { - expect(processMethod.implements).toBeUndefined(); - }); + it("MyWorker's process() method does not implement an interface", () => { + expect(processMethod.implements).toBeUndefined(); + }); - it('MyIncompleteWorker does not have any methods', () => { - expect(docSet.getByLongname('MyIncompleteWorker#work')).toBeEmptyArray(); - }); + it('MyIncompleteWorker does not have any methods', () => { + expect(docSet.getByLongname('MyIncompleteWorker#work')).toBeEmptyArray(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/implicitcasttag.js b/packages/jsdoc/test/specs/tags/implicitcasttag.js index 9bb1d069..f9c40aa0 100644 --- a/packages/jsdoc/test/specs/tags/implicitcasttag.js +++ b/packages/jsdoc/test/specs/tags/implicitcasttag.js @@ -1,42 +1,42 @@ describe('@implicitCast tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @implicitCast tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/implicitcasttag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @implicitCast tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/implicitcasttag.js'); + } - it('should not recognize the @implicitCast tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/implicitcasttag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @implicitCast tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/implicitcasttag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/inheritdoctag.js b/packages/jsdoc/test/specs/tags/inheritdoctag.js index 61be8928..35102761 100644 --- a/packages/jsdoc/test/specs/tags/inheritdoctag.js +++ b/packages/jsdoc/test/specs/tags/inheritdoctag.js @@ -1,39 +1,39 @@ describe('@inheritdoc tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/inheritdoctag.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/inheritdoctag.js'); - function ignored({ignore}) { - return ignore !== true; - } + function ignored({ ignore }) { + return ignore !== true; + } - it('should cause the symbol to be documented', () => { - const open = docSet.getByLongname('Socket#open'); + it('should cause the symbol to be documented', () => { + const open = docSet.getByLongname('Socket#open'); - expect(open).toBeArrayOfSize(2); - expect(open[0].ignore).toBeTrue(); - expect(open[1].ignore).toBeUndefined(); - expect(open[1].description).toBe('Open the connection.'); - }); + expect(open).toBeArrayOfSize(2); + expect(open[0].ignore).toBeTrue(); + expect(open[1].ignore).toBeUndefined(); + expect(open[1].description).toBe('Open the connection.'); + }); - it('should cause all other tags to be ignored', () => { - const close = docSet.getByLongname('Socket#close').filter(ignored)[0]; + it('should cause all other tags to be ignored', () => { + const close = docSet.getByLongname('Socket#close').filter(ignored)[0]; - expect(close.description).toBe('Close the connection.'); - expect(close.params).toBeUndefined(); - }); + expect(close.description).toBe('Close the connection.'); + expect(close.params).toBeUndefined(); + }); - it('should not say that the child symbol is abstract', () => { - const open = docSet.getByLongname('Socket#open').filter(ignored)[0]; - const parentOpen = docSet.getByLongname('Connection#open')[0]; + it('should not say that the child symbol is abstract', () => { + const open = docSet.getByLongname('Socket#open').filter(ignored)[0]; + const parentOpen = docSet.getByLongname('Connection#open')[0]; - expect(parentOpen.virtual).toBeTrue(); - expect(open.virtual).toBeUndefined(); - }); + expect(parentOpen.virtual).toBeTrue(); + expect(open.virtual).toBeUndefined(); + }); - it('should work with interface members whose names are specified in the comment', () => { - const connectionRead = docSet.getByLongname('Connection#read').filter(ignored)[0]; - const socketRead = docSet.getByLongname('Socket#read').filter(ignored)[0]; + it('should work with interface members whose names are specified in the comment', () => { + const connectionRead = docSet.getByLongname('Connection#read').filter(ignored)[0]; + const socketRead = docSet.getByLongname('Socket#read').filter(ignored)[0]; - expect(socketRead).toBeObject(); - expect(socketRead.description).toBe(connectionRead.description); - }); + expect(socketRead).toBeObject(); + expect(socketRead.description).toBe(connectionRead.description); + }); }); diff --git a/packages/jsdoc/test/specs/tags/interfacetag.js b/packages/jsdoc/test/specs/tags/interfacetag.js index af20ebc2..e665afb0 100644 --- a/packages/jsdoc/test/specs/tags/interfacetag.js +++ b/packages/jsdoc/test/specs/tags/interfacetag.js @@ -1,118 +1,123 @@ describe('@interface tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/interface-implements.js'); - const testerInterface = docSet.getByLongname('ITester')[0]; - const testerImplementation = docSet.getByLongname('MyTester')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/interface-implements.js'); + const testerInterface = docSet.getByLongname('ITester')[0]; + const testerImplementation = docSet.getByLongname('MyTester')[0]; - it('ITester has its kind set to "interface"', () => { - expect(testerInterface.kind).toBe('interface'); + it('ITester has its kind set to "interface"', () => { + expect(testerInterface.kind).toBe('interface'); + }); + + it('MyTester class has its kind set to "class" (not "interface")', () => { + expect(testerImplementation.kind).toBe('class'); + }); + + describe('virtual doclets', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - it('MyTester class has its kind set to "class" (not "interface")', () => { - expect(testerImplementation.kind).toBe('class'); + it('should support virtual doclets with the JSDoc tag dictionary', () => { + let docSet2; + let virtualInterface; + + function getDocSet() { + jsdoc.replaceTagDictionary('jsdoc'); + + return jsdoc.getDocSetFromFile('test/fixtures/interfacetag2.js'); + } + + expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); + + docSet2 = getDocSet(); + virtualInterface = docSet2.getByLongname('VirtualInterface')[0]; + + expect(virtualInterface).toBeObject(); + expect(virtualInterface.longname).toBe('VirtualInterface'); }); - describe('virtual doclets', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('should not support virtual doclets with the Closure tag dictionary', () => { + let docSet2; + let virtualInterface; - it('should support virtual doclets with the JSDoc tag dictionary', () => { - let docSet2; - let virtualInterface; + function getDocSet() { + jsdoc.replaceTagDictionary('closure'); - function getDocSet() { - jsdoc.replaceTagDictionary('jsdoc'); + return jsdoc.getDocSetFromFile('test/fixtures/interfacetag2.js'); + } - return jsdoc.getDocSetFromFile('test/fixtures/interfacetag2.js'); - } + expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); - expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); + docSet2 = getDocSet(); + virtualInterface = docSet2.getByLongname('VirtualInterface')[0]; - docSet2 = getDocSet(); - virtualInterface = docSet2.getByLongname('VirtualInterface')[0]; + expect(virtualInterface).toBeUndefined(); + }); + }); - expect(virtualInterface).toBeObject(); - expect(virtualInterface.longname).toBe('VirtualInterface'); - }); + describe('ES2015 classes as interfaces', () => { + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/interface-implements2.js'); + const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/interface-assignment.js'); - it('should not support virtual doclets with the Closure tag dictionary', () => { - let docSet2; - let virtualInterface; + it('should set the correct kind on the interface', () => { + const workerInterface = docSet2.getByLongname('IWorker').filter((d) => !d.undocumented)[0]; - function getDocSet() { - jsdoc.replaceTagDictionary('closure'); - - return jsdoc.getDocSetFromFile('test/fixtures/interfacetag2.js'); - } - - expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); - - docSet2 = getDocSet(); - virtualInterface = docSet2.getByLongname('VirtualInterface')[0]; - - expect(virtualInterface).toBeUndefined(); - }); + expect(workerInterface.kind).toBe('interface'); }); - describe('ES2015 classes as interfaces', () => { - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/interface-implements2.js'); - const docSet3 = jsdoc.getDocSetFromFile('test/fixtures/interface-assignment.js'); + it('should set the correct kind on methods in the interface', () => { + const workerInterfaceWork = docSet2 + .getByLongname('IWorker#work') + .filter((d) => !d.undocumented)[0]; - it('should set the correct kind on the interface', () => { - const workerInterface = docSet2.getByLongname('IWorker').filter(d => !d.undocumented)[0]; - - expect(workerInterface.kind).toBe('interface'); - }); - - it('should set the correct kind on methods in the interface', () => { - const workerInterfaceWork = docSet2.getByLongname('IWorker#work') - .filter(d => !d.undocumented)[0]; - - expect(workerInterfaceWork.kind).toBe('function'); - }); - - it('should set the correct kind on the implementing class', () => { - const workerImpl = docSet2.getByLongname('MyWorker').filter(d => !d.undocumented)[0]; - - expect(workerImpl.kind).toBe('class'); - }); - - it('should set the correct kind on an interface assigned to a variable', () => { - const workerInterface = docSet3.getByLongname('myCorp.IWorker').filter(d => !d.undocumented)[0]; - - expect(workerInterface.kind).toBe('interface'); - }); - - it('should set the correct kind on methods in an interface assigned to a variable', () => { - const workerInterfaceWork = docSet3.getByLongname('myCorp.IWorker#work') - .filter(d => !d.undocumented)[0]; - - expect(workerInterfaceWork.kind).toBe('function'); - }); - - it('should set the correct kind on other members in an interface assigned to a variable', () => { - const workerName = docSet3.getByLongname('myCorp.IWorker#workerName') - .filter(d => !d.undocumented)[0]; - - expect(workerName.kind).toBe('member'); - }); + expect(workerInterfaceWork.kind).toBe('function'); }); - describe('Closure Compiler tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('should set the correct kind on the implementing class', () => { + const workerImpl = docSet2.getByLongname('MyWorker').filter((d) => !d.undocumented)[0]; - it('should support @record as a synonym for @interface', () => { - let docSet2; - let myStructuralInterface; - - jsdoc.replaceTagDictionary('closure'); - - docSet2 = jsdoc.getDocSetFromFile('test/fixtures/interfacetag3.js'); - myStructuralInterface = docSet2.getByLongname('MyStructuralInterface')[0]; - - expect(myStructuralInterface.kind).toBe('interface'); - }); + expect(workerImpl.kind).toBe('class'); }); + + it('should set the correct kind on an interface assigned to a variable', () => { + const workerInterface = docSet3 + .getByLongname('myCorp.IWorker') + .filter((d) => !d.undocumented)[0]; + + expect(workerInterface.kind).toBe('interface'); + }); + + it('should set the correct kind on methods in an interface assigned to a variable', () => { + const workerInterfaceWork = docSet3 + .getByLongname('myCorp.IWorker#work') + .filter((d) => !d.undocumented)[0]; + + expect(workerInterfaceWork.kind).toBe('function'); + }); + + it('should set the correct kind on other members in an interface assigned to a variable', () => { + const workerName = docSet3 + .getByLongname('myCorp.IWorker#workerName') + .filter((d) => !d.undocumented)[0]; + + expect(workerName.kind).toBe('member'); + }); + }); + + describe('Closure Compiler tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); + }); + + it('should support @record as a synonym for @interface', () => { + let docSet2; + let myStructuralInterface; + + jsdoc.replaceTagDictionary('closure'); + + docSet2 = jsdoc.getDocSetFromFile('test/fixtures/interfacetag3.js'); + myStructuralInterface = docSet2.getByLongname('MyStructuralInterface')[0]; + + expect(myStructuralInterface.kind).toBe('interface'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/kindtag.js b/packages/jsdoc/test/specs/tags/kindtag.js index 47fa7af4..1497aef0 100644 --- a/packages/jsdoc/test/specs/tags/kindtag.js +++ b/packages/jsdoc/test/specs/tags/kindtag.js @@ -1,8 +1,8 @@ describe('@kind tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/kindtag.js'); - const doc = docSet.getByLongname('x')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/kindtag.js'); + const doc = docSet.getByLongname('x')[0]; - it("sets the doclet's 'kind' property to the tag value", () => { - expect(doc.kind).toBe('function'); - }); + it("sets the doclet's 'kind' property to the tag value", () => { + expect(doc.kind).toBe('function'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/lendstag.js b/packages/jsdoc/test/specs/tags/lendstag.js index 00ba8076..9e94c258 100644 --- a/packages/jsdoc/test/specs/tags/lendstag.js +++ b/packages/jsdoc/test/specs/tags/lendstag.js @@ -1,17 +1,17 @@ describe('@lends tag', () => { - // see also specs/documentation/lends.js for tests on @lends behaviour. - const { Doclet } = require('jsdoc/doclet'); + // see also specs/documentation/lends.js for tests on @lends behaviour. + const { Doclet } = require('jsdoc/doclet'); - const doc = new Doclet('/** @lends */', {}); - const doc2 = new Doclet('/** @lends MyClass# */', {}); + const doc = new Doclet('/** @lends */', {}); + const doc2 = new Doclet('/** @lends MyClass# */', {}); - it("sets the doclet's 'alias' property to the tag value or ", () => { - expect(doc.alias).toBe(''); - expect(doc2.alias).toBe('MyClass#'); - }); + it("sets the doclet's 'alias' property to the tag value or ", () => { + expect(doc.alias).toBe(''); + expect(doc2.alias).toBe('MyClass#'); + }); - it("sets the doclet's 'undocumented' property to 'true'", () => { - expect(doc.undocumented).toBeTrue(); - expect(doc2.undocumented).toBeTrue(); - }); + it("sets the doclet's 'undocumented' property to 'true'", () => { + expect(doc.undocumented).toBeTrue(); + expect(doc2.undocumented).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/licensetag.js b/packages/jsdoc/test/specs/tags/licensetag.js index eb57c3fe..8c6f6dce 100644 --- a/packages/jsdoc/test/specs/tags/licensetag.js +++ b/packages/jsdoc/test/specs/tags/licensetag.js @@ -1,8 +1,8 @@ describe('@license tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/licensetag.js'); - const doc = docSet.getByLongname('x')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/licensetag.js'); + const doc = docSet.getByLongname('x')[0]; - it("sets the doclet's 'license' property to the tag value", () => { - expect(doc.license).toBe('GPL v2'); - }); + it("sets the doclet's 'license' property to the tag value", () => { + expect(doc.license).toBe('GPL v2'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/listenstag.js b/packages/jsdoc/test/specs/tags/listenstag.js index 0b6e01f9..6981a57a 100644 --- a/packages/jsdoc/test/specs/tags/listenstag.js +++ b/packages/jsdoc/test/specs/tags/listenstag.js @@ -1,15 +1,15 @@ describe('@listens tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/listenstag.js'); - const doc = docSet.getByLongname('module:myModule~MyHandler')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/listenstag.js'); + const doc = docSet.getByLongname('module:myModule~MyHandler')[0]; - it("should create a 'listens' property on the doclet, an array, with the events that are listened to (with event namespace)", () => { - expect(doc.listens).toBeArray(); - expect(doc.listens).toContain('module:myModule.event:MyEvent'); - expect(doc.listens).toContain('module:myModule~Events.event:Event2'); - }); + it("should create a 'listens' property on the doclet, an array, with the events that are listened to (with event namespace)", () => { + expect(doc.listens).toBeArray(); + expect(doc.listens).toContain('module:myModule.event:MyEvent'); + expect(doc.listens).toContain('module:myModule~Events.event:Event2'); + }); - it('includes events that do not have their own documentation', () => { - expect(doc.listens).toBeArrayOfSize(3); - expect(doc.listens).toContain('event:fakeEvent'); - }); + it('includes events that do not have their own documentation', () => { + expect(doc.listens).toBeArrayOfSize(3); + expect(doc.listens).toContain('event:fakeEvent'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/memberoftag.js b/packages/jsdoc/test/specs/tags/memberoftag.js index 0c159385..ac199f59 100644 --- a/packages/jsdoc/test/specs/tags/memberoftag.js +++ b/packages/jsdoc/test/specs/tags/memberoftag.js @@ -1,91 +1,91 @@ describe('@memberof tag', () => { - it('When a symbol has a @member tag, the doclet has a long name that includes the parent.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag.js'); - const Data = docSet.getByLongname('mathlib.Data')[0]; - const point = docSet.getByLongname('mathlib.Data#point')[0]; + it('When a symbol has a @member tag, the doclet has a long name that includes the parent.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag.js'); + const Data = docSet.getByLongname('mathlib.Data')[0]; + const point = docSet.getByLongname('mathlib.Data#point')[0]; - expect(Data).toBeObject(); - expect(point).toBeObject(); + expect(Data).toBeObject(); + expect(point).toBeObject(); - expect(Data.memberof).toBe('mathlib'); - expect(Data.name).toBe('Data'); + expect(Data.memberof).toBe('mathlib'); + expect(Data.name).toBe('Data'); + }); + + it('A symbol within a namespace for which no scope is specified.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag4.js'); + const doOtherStuff = docSet.getByLongname('doStuff.doOtherStuff')[0]; + + expect(doOtherStuff).toBeObject(); + expect(doOtherStuff.scope).toBe('static'); + }); + + it('A symbol in which name === memberof.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag4.js'); + const doStuff = docSet.getByLongname('doStuff.doStuff')[0]; + + expect(doStuff).toBeObject(); + expect(doStuff.scope).toBe('static'); + }); + + describe('static', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag2.js'); + const publish = docSet.getByLongname('Observable#publish')[0]; + const cache = docSet.getByLongname('Observable.cache')[0]; + + it('A symbol is documented as a static @memberof a class.', () => { + // it should appear as a static member of that class + expect(cache).toBeObject(); + expect(cache.memberof).toBe('Observable'); + expect(cache.scope).toBe('static'); + expect(cache.name).toBe('cache'); + expect(cache.longname).toBe('Observable.cache'); }); - it('A symbol within a namespace for which no scope is specified.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag4.js'); - const doOtherStuff = docSet.getByLongname('doStuff.doOtherStuff')[0]; + it('A symbol is documented as a static @memberof a class prototype.', () => { + // it should appear as an instance member of that class + expect(publish).toBeObject(); + expect(publish.memberof).toBe('Observable'); + expect(publish.scope).toBe('instance'); + expect(publish.name).toBe('publish'); + expect(publish.longname).toBe('Observable#publish'); + }); + }); - expect(doOtherStuff).toBeObject(); - expect(doOtherStuff.scope).toBe('static'); + describe('forced', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftagforced.js'); + const maproutes = docSet.getByLongname('map.routes')[0]; + const datapointy = docSet.getByLongname('Data#point.y')[0]; + + it('A nested symbol with a @memberof! tag set to .', () => { + expect(maproutes.name).toBe('map.routes'); }); - it('A symbol in which name === memberof.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag4.js'); - const doStuff = docSet.getByLongname('doStuff.doStuff')[0]; - - expect(doStuff).toBeObject(); - expect(doStuff.scope).toBe('static'); + // TODO: This test is failing; should it be? + xit('A nested symbol with a @memberof! tag set to another symbol.', () => { + expect(datapointy.name).toBe('point.y'); }); + }); - describe('static', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag2.js'); - const publish = docSet.getByLongname('Observable#publish')[0]; - const cache = docSet.getByLongname('Observable.cache')[0]; + it('A symbol that is a nested class with a @memberof tag.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag3.js'); + const tree = docSet.getByLongname('module:terrain.Forest#Tree')[0]; - it('A symbol is documented as a static @memberof a class.', () => { - // it should appear as a static member of that class - expect(cache).toBeObject(); - expect(cache.memberof).toBe('Observable'); - expect(cache.scope).toBe('static'); - expect(cache.name).toBe('cache'); - expect(cache.longname).toBe('Observable.cache'); - }); + expect(tree.longname).toBe('module:terrain.Forest#Tree'); + }); - it('A symbol is documented as a static @memberof a class prototype.', () => { - // it should appear as an instance member of that class - expect(publish).toBeObject(); - expect(publish.memberof).toBe('Observable'); - expect(publish.scope).toBe('instance'); - expect(publish.name).toBe('publish'); - expect(publish.longname).toBe('Observable#publish'); - }); - }); + it('A symbol that is an instance member of a nested class with a @memberof tag.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag3.js'); + const leaf = docSet.getByLongname('module:terrain.Forest#Tree#leaf')[0]; - describe('forced', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftagforced.js'); - const maproutes = docSet.getByLongname('map.routes')[0]; - const datapointy = docSet.getByLongname('Data#point.y')[0]; + expect(leaf.longname).toBe('module:terrain.Forest#Tree#leaf'); + }); - it('A nested symbol with a @memberof! tag set to .', () => { - expect(maproutes.name).toBe('map.routes'); - }); + it('Properties of a symbol with a @memberof tag inherit the @memberof info.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag5.js'); + const open = docSet.getByLongname('module:network.Socket#open')[0]; + const uid = docSet.getByLongname('module:network.Socket.uid')[0]; - // TODO: This test is failing; should it be? - xit('A nested symbol with a @memberof! tag set to another symbol.', () => { - expect(datapointy.name).toBe('point.y'); - }); - }); - - it('A symbol that is a nested class with a @memberof tag.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag3.js'); - const tree = docSet.getByLongname('module:terrain.Forest#Tree')[0]; - - expect(tree.longname).toBe('module:terrain.Forest#Tree'); - }); - - it('A symbol that is an instance member of a nested class with a @memberof tag.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag3.js'); - const leaf = docSet.getByLongname('module:terrain.Forest#Tree#leaf')[0]; - - expect(leaf.longname).toBe('module:terrain.Forest#Tree#leaf'); - }); - - it('Properties of a symbol with a @memberof tag inherit the @memberof info.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/memberoftag5.js'); - const open = docSet.getByLongname('module:network.Socket#open')[0]; - const uid = docSet.getByLongname('module:network.Socket.uid')[0]; - - expect(open).toBeObject(); - expect(uid).toBeObject(); - }); + expect(open).toBeObject(); + expect(uid).toBeObject(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/membertag.js b/packages/jsdoc/test/specs/tags/membertag.js index f2242ff8..42377374 100644 --- a/packages/jsdoc/test/specs/tags/membertag.js +++ b/packages/jsdoc/test/specs/tags/membertag.js @@ -1,34 +1,34 @@ describe('@member tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/membertag.js'); - const doc = docSet.getByLongname('x')[0]; - const doc2 = docSet.getByLongname('foobar')[0]; - const doc3 = docSet.getByLongname('baz')[0]; - const doc4 = docSet.getByLongname('y')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/membertag.js'); + const doc = docSet.getByLongname('x')[0]; + const doc2 = docSet.getByLongname('foobar')[0]; + const doc3 = docSet.getByLongname('baz')[0]; + const doc4 = docSet.getByLongname('y')[0]; - it("sets the doclet's 'kind' property to 'member'", () => { - expect(doc.kind).toBe('member'); - expect(doc2.kind).toBe('member'); - expect(doc3.kind).toBe('member'); - expect(doc4.kind).toBe('member'); - }); + it("sets the doclet's 'kind' property to 'member'", () => { + expect(doc.kind).toBe('member'); + expect(doc2.kind).toBe('member'); + expect(doc3.kind).toBe('member'); + expect(doc4.kind).toBe('member'); + }); - it("If specified with a name, sets the doclet's name property", () => { - expect(doc.name).toBe('x'); - expect(doc2.name).toBe('foobar'); - expect(doc3.name).toBe('baz'); - }); + it("If specified with a name, sets the doclet's name property", () => { + expect(doc.name).toBe('x'); + expect(doc2.name).toBe('foobar'); + expect(doc3.name).toBe('baz'); + }); - it("If specified with a type and name, sets the doclet's type appropriately", () => { - expect(doc3.type.names).toBeArrayOfSize(1); - expect(doc3.type.names[0]).toBe('string'); - }); + it("If specified with a type and name, sets the doclet's type appropriately", () => { + expect(doc3.type.names).toBeArrayOfSize(1); + expect(doc3.type.names[0]).toBe('string'); + }); - it("If specified with a type but no name, sets the doclet's name from the following JavaScript syntax", () => { - expect(doc4.name).toBe('y'); - }); + it("If specified with a type but no name, sets the doclet's name from the following JavaScript syntax", () => { + expect(doc4.name).toBe('y'); + }); - it("If specified with a type but no name, sets the doclet's type appropriately", () => { - expect(doc4.type.names).toBeArrayOfSize(1); - expect(doc4.type.names[0]).toBe('Object'); - }); + it("If specified with a type but no name, sets the doclet's type appropriately", () => { + expect(doc4.type.names).toBeArrayOfSize(1); + expect(doc4.type.names[0]).toBe('Object'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/mixestag.js b/packages/jsdoc/test/specs/tags/mixestag.js index 10e52c56..4f8076dd 100644 --- a/packages/jsdoc/test/specs/tags/mixestag.js +++ b/packages/jsdoc/test/specs/tags/mixestag.js @@ -1,16 +1,16 @@ describe('@mixes tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag.js'); - const FormButton = docSet.getByLongname('FormButton')[0]; - const MyClass = docSet.getByLongname('MyClass')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag.js'); + const FormButton = docSet.getByLongname('FormButton')[0]; + const MyClass = docSet.getByLongname('MyClass')[0]; - it("When a symbol has a @mixes tag, it gets an array property 'mixes' with the name of the mixin", () => { - expect(FormButton.mixes).toBeArrayOfSize(1); - expect(FormButton.mixes[0]).toBe('Eventful'); - }); + it("When a symbol has a @mixes tag, it gets an array property 'mixes' with the name of the mixin", () => { + expect(FormButton.mixes).toBeArrayOfSize(1); + expect(FormButton.mixes[0]).toBe('Eventful'); + }); - it('When a symbol has more than one @mixes tag, all of the mixins are added', () => { - expect(MyClass.mixes).toBeArrayOfSize(2); - expect(MyClass.mixes).toContain('Eventful'); - expect(MyClass.mixes).toContain('AnotherMixin'); - }); + it('When a symbol has more than one @mixes tag, all of the mixins are added', () => { + expect(MyClass.mixes).toBeArrayOfSize(2); + expect(MyClass.mixes).toContain('Eventful'); + expect(MyClass.mixes).toContain('AnotherMixin'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/mixintag.js b/packages/jsdoc/test/specs/tags/mixintag.js index 8e9dd70a..7b7c2fcf 100644 --- a/packages/jsdoc/test/specs/tags/mixintag.js +++ b/packages/jsdoc/test/specs/tags/mixintag.js @@ -1,13 +1,13 @@ describe('@mixin tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag.js'); - const Eventful = docSet.getByLongname('Eventful')[0]; - const Mixin = docSet.getByLongname('AnotherMixin')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/mixintag.js'); + const Eventful = docSet.getByLongname('Eventful')[0]; + const Mixin = docSet.getByLongname('AnotherMixin')[0]; - it("When a symbol has a @mixin tag, the doclet's 'kind' property is set to 'mixin'", () => { - expect(Eventful.kind).toBe('mixin'); - }); + it("When a symbol has a @mixin tag, the doclet's 'kind' property is set to 'mixin'", () => { + expect(Eventful.kind).toBe('mixin'); + }); - it("When a symbol has a @mixin tag, its name is set to the tag's value (if present)", () => { - expect(Mixin).toBeObject(); - }); + it("When a symbol has a @mixin tag, its name is set to the tag's value (if present)", () => { + expect(Mixin).toBeObject(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/modifiestag.js b/packages/jsdoc/test/specs/tags/modifiestag.js index 28f2deb8..8210b4ef 100644 --- a/packages/jsdoc/test/specs/tags/modifiestag.js +++ b/packages/jsdoc/test/specs/tags/modifiestag.js @@ -1,12 +1,12 @@ describe('@modifies tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/modifiestag.js'); - const mutator = docSet.getByLongname('mutator')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/modifiestag.js'); + const mutator = docSet.getByLongname('mutator')[0]; - it('should add the specified types to the doclet\'s `modifies` property', () => { - expect(mutator.modifies).toBeArrayOfSize(1); - expect(mutator.modifies[0].type).toBeObject(); - expect(mutator.modifies[0].type.names).toBeArrayOfSize(2); - expect(mutator.modifies[0].type.names[0]).toBe('foo'); - expect(mutator.modifies[0].type.names[1]).toBe('bar'); - }); + it("should add the specified types to the doclet's `modifies` property", () => { + expect(mutator.modifies).toBeArrayOfSize(1); + expect(mutator.modifies[0].type).toBeObject(); + expect(mutator.modifies[0].type.names).toBeArrayOfSize(2); + expect(mutator.modifies[0].type.names[0]).toBe('foo'); + expect(mutator.modifies[0].type.names[1]).toBe('bar'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/moduletag.js b/packages/jsdoc/test/specs/tags/moduletag.js index 5f70056a..d93884d4 100644 --- a/packages/jsdoc/test/specs/tags/moduletag.js +++ b/packages/jsdoc/test/specs/tags/moduletag.js @@ -1,181 +1,182 @@ -function filter({undocumented}) { - return !undocumented; +function filter({ undocumented }) { + return !undocumented; } describe('@module tag', () => { - describe("using 'this'", () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag.js'); - const book = docSet.getByLongname('module:bookshelf.Book')[0]; - const title = docSet.getByLongname('module:bookshelf.Book#title')[0]; + describe("using 'this'", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag.js'); + const book = docSet.getByLongname('module:bookshelf.Book')[0]; + const title = docSet.getByLongname('module:bookshelf.Book#title')[0]; - it('When a global symbol starts with "this" and is in a file with a @module tag, the symbol is documented as a member of that module.', () => { - expect(book).toBeObject(); - expect(book.memberof).toBe('module:bookshelf'); - }); - - it('When an inner symbol starts with "this" and is in a file with a @module tag, the symbol is documented as a member of its enclosing constructor.', () => { - expect(title).toBeObject(); - expect(title.memberof).toBe('module:bookshelf.Book'); - }); + it('When a global symbol starts with "this" and is in a file with a @module tag, the symbol is documented as a member of that module.', () => { + expect(book).toBeObject(); + expect(book.memberof).toBe('module:bookshelf'); }); - describe('misc', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag2.js'); - const mixer = docSet.getByLongname('module:color/mixer').filter(filter)[0]; + it('When an inner symbol starts with "this" and is in a file with a @module tag, the symbol is documented as a member of its enclosing constructor.', () => { + expect(title).toBeObject(); + expect(title.memberof).toBe('module:bookshelf.Book'); + }); + }); + + describe('misc', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag2.js'); + const mixer = docSet.getByLongname('module:color/mixer').filter(filter)[0]; + const blend = docSet.getByLongname('module:color/mixer.blend')[0]; + const darken = docSet.getByLongname('module:color/mixer.darken')[0]; + + it('When a @module tag defines a module, a symbol of kind "module" is documented', () => { + expect(mixer).toBeObject(); + expect(mixer.kind).toBe('module'); + }); + + it('When a @module tag defines a module, the module doclet does not have a "scope" property', () => { + expect(mixer.scope).toBeUndefined(); + }); + + it('When an object literal is lent to a module with a @lends tag, a member of that object literal is documented as a member of the module', () => { + expect(blend).toBeObject(); + expect(blend.kind).toBe('function'); + }); + + it('When a documented symbol is a member of a namespace "exports", it is documented as a member of the module', () => { + expect(darken).toBeObject(); + expect(darken.kind).toBe('function'); + }); + }); + + describe('virtual comments', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag4.js'); + const clickProperties = docSet.getByLongname('module:M1~ClickProperties')[0]; + const virtFunc = docSet.getByLongname('module:M1.VirtualComment')[0]; + const virtFunc2 = docSet.getByLongname('module:M1#VirtualComment2')[0]; + + it('When a virtual comment typedef is inside a module, the typedef is a memberof the module', () => { + expect(clickProperties.memberof).toBe('module:M1'); + }); + + it('When a virtual comment typedef is inside a module, the typedef longname contains the module name', () => { + expect(clickProperties.longname).toBe('module:M1~ClickProperties'); + }); + + it('When a virtual comment typedef is inside a module, the typedef scope is "inner"', () => { + expect(clickProperties.scope).toBe('inner'); + }); + + it('When a virtual comment function is inside a module with a static scope, the function has the correct memberof and longname', () => { + expect(virtFunc.longname).toBe('module:M1.VirtualComment'); + expect(virtFunc.memberof).toBe('module:M1'); + }); + + it('When a virtual comment function is inside a module with an instance scope, the function has the correct memberof and longname', () => { + expect(virtFunc2.longname).toBe('module:M1#VirtualComment2'); + expect(virtFunc2.memberof).toBe('module:M1'); + }); + }); + + describe('"module:" namespace included in the name', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag5.js'); + const bookshelf = docSet.getByLongname('module:bookshelf')[0]; + + it('When the name for a @module tag begins with the "module:" namespace, we remove the namespace', () => { + expect(bookshelf).toBeObject(); + expect(bookshelf.name).toBe('bookshelf'); + }); + }); + + describe('ES 2015 modules', () => { + describe('that export a default', () => { + describe('value type', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag6.js'); + const exports = docSet + .getByLongname('module:appname') + .filter(({ kind }) => kind === 'member')[0]; + + it('When a value type is exported, it has the same name as the module longname', () => { + expect(exports.name).toBe('module:appname'); + }); + }); + + describe('object', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag7.js'); const blend = docSet.getByLongname('module:color/mixer.blend')[0]; - const darken = docSet.getByLongname('module:color/mixer.darken')[0]; - it('When a @module tag defines a module, a symbol of kind "module" is documented', () => { - expect(mixer).toBeObject(); - expect(mixer.kind).toBe('module'); - }); - - it('When a @module tag defines a module, the module doclet does not have a "scope" property', () => { - expect(mixer.scope).toBeUndefined(); - }); - - it('When an object literal is lent to a module with a @lends tag, a member of that object literal is documented as a member of the module', () => { - expect(blend).toBeObject(); - expect(blend.kind).toBe('function'); - }); - - it('When a documented symbol is a member of a namespace "exports", it is documented as a member of the module', () => { - expect(darken).toBeObject(); - expect(darken.kind).toBe('function'); + it('When an object is exported, its members have the correct name, memberof, and kind', () => { + expect(blend.name).toBe('blend'); + expect(blend.memberof).toBe('module:color/mixer'); + expect(blend.kind).toBe('function'); }); + }); }); - describe('virtual comments', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag4.js'); - const clickProperties = docSet.getByLongname('module:M1~ClickProperties')[0]; - const virtFunc = docSet.getByLongname('module:M1.VirtualComment')[0]; - const virtFunc2 = docSet.getByLongname('module:M1#VirtualComment2')[0]; + describe('that export named values', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag8.js'); + const blend = docSet.getByLongname('module:color/mixer.blend')[0]; + const lastColor = docSet.getByLongname('module:color/mixer.lastColor')[0]; + const name = docSet.getByLongname('module:color/mixer.name')[0]; + const toRgb = docSet.getByLongname('module:color/mixer.toRgb')[0]; - it('When a virtual comment typedef is inside a module, the typedef is a memberof the module', () => { - expect(clickProperties.memberof).toBe('module:M1'); - }); + it('When a method is exported, it has the correct name, memberof, and kind', () => { + expect(blend.name).toBe('blend'); + expect(blend.memberof).toBe('module:color/mixer'); + expect(blend.kind).toBe('function'); + }); - it('When a virtual comment typedef is inside a module, the typedef longname contains the module name', () => { - expect(clickProperties.longname).toBe('module:M1~ClickProperties'); - }); + it('When a variable is exported, it has the correct name, memberof, and kind', () => { + expect(lastColor.name).toBe('lastColor'); + expect(lastColor.memberof).toBe('module:color/mixer'); + expect(lastColor.kind).toBe('member'); + }); - it('When a virtual comment typedef is inside a module, the typedef scope is "inner"', () => { - expect(clickProperties.scope).toBe('inner'); - }); + it('When a constant is exported, it has the correct name, memberof, and kind', () => { + expect(name.name).toBe('name'); + expect(name.memberof).toBe('module:color/mixer'); + expect(name.kind).toBe('constant'); + }); - it('When a virtual comment function is inside a module with a static scope, the function has the correct memberof and longname', () => { - expect(virtFunc.longname).toBe('module:M1.VirtualComment'); - expect(virtFunc.memberof).toBe('module:M1'); - }); - - it('When a virtual comment function is inside a module with an instance scope, the function has the correct memberof and longname', () => { - expect(virtFunc2.longname).toBe('module:M1#VirtualComment2'); - expect(virtFunc2.memberof).toBe('module:M1'); - }); + it('When a symbol is exported under a different name, it has the correct name, memberof, and kind', () => { + expect(toRgb.name).toBe('toRgb'); + expect(toRgb.memberof).toBe('module:color/mixer'); + expect(toRgb.kind).toBe('function'); + }); }); - describe('"module:" namespace included in the name', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag5.js'); - const bookshelf = docSet.getByLongname('module:bookshelf')[0]; + describe('that export another module in its entirety', () => { + it('should not crash JSDoc', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/moduletag9.js'); + } - it('When the name for a @module tag begins with the "module:" namespace, we remove the namespace', () => { - expect(bookshelf).toBeObject(); - expect(bookshelf.name).toBe('bookshelf'); - }); + expect(getDocSet).not.toThrow(); + }); }); - describe('ES 2015 modules', () => { - describe('that export a default', () => { - describe('value type', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag6.js'); - const exports = docSet.getByLongname('module:appname').filter(({kind}) => kind === 'member')[0]; + describe('that export an unnamed default function', () => { + it('should not crash JSDoc', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/moduletag10.js'); + } - it('When a value type is exported, it has the same name as the module longname', () => { - expect(exports.name).toBe('module:appname'); - }); - }); - - describe('object', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag7.js'); - const blend = docSet.getByLongname('module:color/mixer.blend')[0]; - - it('When an object is exported, its members have the correct name, memberof, and kind', () => { - expect(blend.name).toBe('blend'); - expect(blend.memberof).toBe('module:color/mixer'); - expect(blend.kind).toBe('function'); - }); - }); - }); - - describe('that export named values', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag8.js'); - const blend = docSet.getByLongname('module:color/mixer.blend')[0]; - const lastColor = docSet.getByLongname('module:color/mixer.lastColor')[0]; - const name = docSet.getByLongname('module:color/mixer.name')[0]; - const toRgb = docSet.getByLongname('module:color/mixer.toRgb')[0]; - - it('When a method is exported, it has the correct name, memberof, and kind', () => { - expect(blend.name).toBe('blend'); - expect(blend.memberof).toBe('module:color/mixer'); - expect(blend.kind).toBe('function'); - }); - - it('When a variable is exported, it has the correct name, memberof, and kind', () => { - expect(lastColor.name).toBe('lastColor'); - expect(lastColor.memberof).toBe('module:color/mixer'); - expect(lastColor.kind).toBe('member'); - }); - - it('When a constant is exported, it has the correct name, memberof, and kind', () => { - expect(name.name).toBe('name'); - expect(name.memberof).toBe('module:color/mixer'); - expect(name.kind).toBe('constant'); - }); - - it('When a symbol is exported under a different name, it has the correct name, memberof, and kind', () => { - expect(toRgb.name).toBe('toRgb'); - expect(toRgb.memberof).toBe('module:color/mixer'); - expect(toRgb.kind).toBe('function'); - }); - }); - - describe('that export another module in its entirety', () => { - it('should not crash JSDoc', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/moduletag9.js'); - } - - expect(getDocSet).not.toThrow(); - }); - }); - - describe('that export an unnamed default function', () => { - it('should not crash JSDoc', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/moduletag10.js'); - } - - expect(getDocSet).not.toThrow(); - }); - }); - - describe('that export a class', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag11.js'); - const foo = docSet.getByLongname('module:foo.Foo').filter(filter)[0]; - const testMethod = docSet.getByLongname('module:foo.Foo#testMethod')[0]; - - it('should identify the correct scope for the exported class', () => { - expect(foo).toBeObject(); - }); - - it('should merge the doclet for the constructor with the doclet for the ' + - 'class', () => { - expect(foo.description).toBe('Test class constructor.'); - }); - - it('should identify the correct scope for the exported class\'s methods', () => { - expect(testMethod).toBeObject(); - }); - }); + expect(getDocSet).not.toThrow(); + }); }); + + describe('that export a class', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/moduletag11.js'); + const foo = docSet.getByLongname('module:foo.Foo').filter(filter)[0]; + const testMethod = docSet.getByLongname('module:foo.Foo#testMethod')[0]; + + it('should identify the correct scope for the exported class', () => { + expect(foo).toBeObject(); + }); + + it('should merge the doclet for the constructor with the doclet for the ' + 'class', () => { + expect(foo.description).toBe('Test class constructor.'); + }); + + it("should identify the correct scope for the exported class's methods", () => { + expect(testMethod).toBeObject(); + }); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/namespacetag.js b/packages/jsdoc/test/specs/tags/namespacetag.js index b36e0416..c05be08d 100644 --- a/packages/jsdoc/test/specs/tags/namespacetag.js +++ b/packages/jsdoc/test/specs/tags/namespacetag.js @@ -1,30 +1,29 @@ describe('@namespace tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/namespacetag.js'); - const x = docSet.getByLongname('x')[0]; - const Foo = docSet.getByLongname('Foo')[0]; - const Bar = docSet.getByLongname('Bar')[0]; - const Socket = docSet.getByLongname('S.Socket')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/namespacetag.js'); + const x = docSet.getByLongname('x')[0]; + const Foo = docSet.getByLongname('Foo')[0]; + const Bar = docSet.getByLongname('Bar')[0]; + const Socket = docSet.getByLongname('S.Socket')[0]; - it("sets the doclet's kind to 'namespace'", () => { - expect(x.kind).toBe('namespace'); - expect(Foo.kind).toBe('namespace'); - expect(Bar.kind).toBe('namespace'); - }); + it("sets the doclet's kind to 'namespace'", () => { + expect(x.kind).toBe('namespace'); + expect(Foo.kind).toBe('namespace'); + expect(Bar.kind).toBe('namespace'); + }); - it("sets the doclet's name to the tag value (if provided)", () => { - expect(x.name).toBe('x'); - expect(Foo.name).toBe('Foo'); - expect(Bar.name).toBe('Bar'); - }); + it("sets the doclet's name to the tag value (if provided)", () => { + expect(x.name).toBe('x'); + expect(Foo.name).toBe('Foo'); + expect(Bar.name).toBe('Bar'); + }); - it("sets the doclet's type (if provided in @namespace)", () => { - expect(Bar.type.names).toBeArrayOfSize(1); - expect(Bar.type.names[0]).toBe('function'); - }); + it("sets the doclet's type (if provided in @namespace)", () => { + expect(Bar.type.names).toBeArrayOfSize(1); + expect(Bar.type.names[0]).toBe('function'); + }); - it("sets the doclet's longname correctly when the namespace is a substring of the name", - () => { - expect(Socket).toBeObject(); - expect(Socket.name).toBe('Socket'); - }); + it("sets the doclet's longname correctly when the namespace is a substring of the name", () => { + expect(Socket).toBeObject(); + expect(Socket.name).toBe('Socket'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/nametag.js b/packages/jsdoc/test/specs/tags/nametag.js index bc67a5b3..459726ee 100644 --- a/packages/jsdoc/test/specs/tags/nametag.js +++ b/packages/jsdoc/test/specs/tags/nametag.js @@ -1,24 +1,24 @@ describe('@name tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/nametag.js'); - const view = docSet.getByLongname('View')[0]; - const controller = docSet.getByLongname('Controller')[0]; - const addToParent = docSet.getByLongname('MvcHelpers~addToParent')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/nametag.js'); + const view = docSet.getByLongname('View')[0]; + const controller = docSet.getByLongname('Controller')[0]; + const addToParent = docSet.getByLongname('MvcHelpers~addToParent')[0]; - it('applies the specified name to the doclet', () => { - expect(view).toBeObject(); - }); + it('applies the specified name to the doclet', () => { + expect(view).toBeObject(); + }); - it('uses the name in the @name tag, ignoring the name in the code', () => { - expect(controller).toBeObject(); - }); + it('uses the name in the @name tag, ignoring the name in the code', () => { + expect(controller).toBeObject(); + }); - it('sets the doclet\'s scope to `global` by default', () => { - expect(view.scope).toBe('global'); - expect(controller.scope).toBe('global'); - }); + it("sets the doclet's scope to `global` by default", () => { + expect(view.scope).toBe('global'); + expect(controller.scope).toBe('global'); + }); - it('uses the specified scope if one is provided', () => { - expect(addToParent).toBeObject(); - expect(addToParent.scope).toBe('inner'); - }); + it('uses the specified scope if one is provided', () => { + expect(addToParent).toBeObject(); + expect(addToParent.scope).toBe('inner'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/noaliastag.js b/packages/jsdoc/test/specs/tags/noaliastag.js index 24ea8f5d..562c40af 100644 --- a/packages/jsdoc/test/specs/tags/noaliastag.js +++ b/packages/jsdoc/test/specs/tags/noaliastag.js @@ -1,42 +1,42 @@ describe('@noalias tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @noalias tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/noaliastag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @noalias tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/noaliastag.js'); + } - it('should not recognize the @noalias tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/noaliastag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @noalias tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/noaliastag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/nocollapsetag.js b/packages/jsdoc/test/specs/tags/nocollapsetag.js index 12c2fc39..30e398fa 100644 --- a/packages/jsdoc/test/specs/tags/nocollapsetag.js +++ b/packages/jsdoc/test/specs/tags/nocollapsetag.js @@ -1,42 +1,42 @@ describe('@nocollapse tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @nocollapse tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/nocollapsetag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @nocollapse tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/nocollapsetag.js'); + } - it('should not recognize the @nocollapse tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/nocollapsetag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @nocollapse tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/nocollapsetag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/nocompiletag.js b/packages/jsdoc/test/specs/tags/nocompiletag.js index 787f7ce1..10d5e14c 100644 --- a/packages/jsdoc/test/specs/tags/nocompiletag.js +++ b/packages/jsdoc/test/specs/tags/nocompiletag.js @@ -1,42 +1,42 @@ describe('@nocompile tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @nocompile tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/nocompiletag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @nocompile tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/nocompiletag.js'); + } - it('should not recognize the @nocompile tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/nocompiletag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @nocompile tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/nocompiletag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/nosideeffectstag.js b/packages/jsdoc/test/specs/tags/nosideeffectstag.js index 5e1a8a71..ba64174a 100644 --- a/packages/jsdoc/test/specs/tags/nosideeffectstag.js +++ b/packages/jsdoc/test/specs/tags/nosideeffectstag.js @@ -1,18 +1,18 @@ describe('@nosideeffects tag', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); + afterEach(() => { + jsdoc.restoreTagDictionary(); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); + it("should set the doclet's `modifies` property to an empty array", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/nosideeffectstag.js'); + const doNothing = docSet.getByLongname('doNothing')[0]; - it('should set the doclet\'s `modifies` property to an empty array', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/nosideeffectstag.js'); - const doNothing = docSet.getByLongname('doNothing')[0]; - - expect(doNothing.modifies).toBeEmptyArray(); - }); + expect(doNothing.modifies).toBeEmptyArray(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/overridetag.js b/packages/jsdoc/test/specs/tags/overridetag.js index 00b29a0b..a3927b8f 100644 --- a/packages/jsdoc/test/specs/tags/overridetag.js +++ b/packages/jsdoc/test/specs/tags/overridetag.js @@ -1,101 +1,100 @@ describe('@override tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); - function ignored({ignore}) { - return ignore !== true; - } + function ignored({ ignore }) { + return ignore !== true; + } + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @override tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/overridetag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + describe('classes', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/overridetag.js'); - it('should not recognize the @override tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/overridetag.js'); - } + it('should cause the symbol to be documented', () => { + const open = docSet.getByLongname('Socket#open'); - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); + expect(open).toBeArrayOfSize(2); + expect(open[0].ignore).toBeTrue(); + expect(open[1].ignore).toBeUndefined(); + expect(open[1].description).toBe('Open the connection.'); + }); + + it('should use any other tags that are defined', () => { + const close = docSet.getByLongname('Socket#close').filter(ignored)[0]; + + expect(close.description).toBe('Close the socket.'); + expect(close.params).toBeArrayOfSize(1); + }); + + it('should not say that the child symbol is abstract', () => { + const open = docSet.getByLongname('Socket#open').filter(ignored)[0]; + const parentOpen = docSet.getByLongname('Connection#open')[0]; + + expect(parentOpen.virtual).toBeTrue(); + expect(open.virtual).toBeUndefined(); + }); + + it('should work with class members whose names are specified in the comment', () => { + const connectionRead = docSet.getByLongname('Connection#read').filter(ignored)[0]; + const socketRead = docSet.getByLongname('Socket#read').filter(ignored)[0]; + + expect(socketRead).toBeObject(); + expect(socketRead.description).toBe(connectionRead.description); + }); }); - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); + describe('interfaces', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/overridetag2.js'); - describe('classes', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/overridetag.js'); + it('should cause the symbol to be documented', () => { + const open = docSet.getByLongname('Socket#open').filter(ignored); - it('should cause the symbol to be documented', () => { - const open = docSet.getByLongname('Socket#open'); + expect(open).toBeArrayOfSize(1); + expect(open[0].description).toBe('Open the connection.'); + }); - expect(open).toBeArrayOfSize(2); - expect(open[0].ignore).toBeTrue(); - expect(open[1].ignore).toBeUndefined(); - expect(open[1].description).toBe('Open the connection.'); - }); + it('should use any other tags that are defined', () => { + const close = docSet.getByLongname('Socket#close').filter(ignored)[0]; - it('should use any other tags that are defined', () => { - const close = docSet.getByLongname('Socket#close').filter(ignored)[0]; + expect(close.description).toBe('Close the socket.'); + expect(close.params).toBeArrayOfSize(1); + }); - expect(close.description).toBe('Close the socket.'); - expect(close.params).toBeArrayOfSize(1); - }); + it('should work with interface members whose names are specified in the comment', () => { + const connectionRead = docSet.getByLongname('Connection#read').filter(ignored)[0]; + const socketRead = docSet.getByLongname('Socket#read').filter(ignored)[0]; - it('should not say that the child symbol is abstract', () => { - const open = docSet.getByLongname('Socket#open').filter(ignored)[0]; - const parentOpen = docSet.getByLongname('Connection#open')[0]; - - expect(parentOpen.virtual).toBeTrue(); - expect(open.virtual).toBeUndefined(); - }); - - it('should work with class members whose names are specified in the comment', () => { - const connectionRead = docSet.getByLongname('Connection#read').filter(ignored)[0]; - const socketRead = docSet.getByLongname('Socket#read').filter(ignored)[0]; - - expect(socketRead).toBeObject(); - expect(socketRead.description).toBe(connectionRead.description); - }); - }); - - describe('interfaces', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/overridetag2.js'); - - it('should cause the symbol to be documented', () => { - const open = docSet.getByLongname('Socket#open').filter(ignored); - - expect(open).toBeArrayOfSize(1); - expect(open[0].description).toBe('Open the connection.'); - }); - - it('should use any other tags that are defined', () => { - const close = docSet.getByLongname('Socket#close').filter(ignored)[0]; - - expect(close.description).toBe('Close the socket.'); - expect(close.params).toBeArrayOfSize(1); - }); - - it('should work with interface members whose names are specified in the comment', - () => { - const connectionRead = docSet.getByLongname('Connection#read').filter(ignored)[0]; - const socketRead = docSet.getByLongname('Socket#read').filter(ignored)[0]; - - expect(socketRead).toBeObject(); - expect(socketRead.description).toBe(connectionRead.description); - }); - }); + expect(socketRead).toBeObject(); + expect(socketRead.description).toBe(connectionRead.description); + }); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/overviewtag.js b/packages/jsdoc/test/specs/tags/overviewtag.js index 0de4d762..29950bb8 100644 --- a/packages/jsdoc/test/specs/tags/overviewtag.js +++ b/packages/jsdoc/test/specs/tags/overviewtag.js @@ -1,66 +1,67 @@ describe('@overview tag', () => { - const env = require('jsdoc/env'); - const path = require('path'); + const env = require('jsdoc/env'); + const path = require('path'); - let doclets; + let doclets; - let srcParser; - const sourceFiles = env.sourceFiles.slice(0); - const sourcePaths = env.opts._.slice(0); + let srcParser; + const sourceFiles = env.sourceFiles.slice(0); + const sourcePaths = env.opts._.slice(0); - beforeEach(() => { - env.opts._ = [path.normalize(`${__dirname}/../../fixtures`)]; - env.sourceFiles = []; - srcParser = jsdoc.createParser(); - require('jsdoc/src/handlers').attachTo(srcParser); - }); + beforeEach(() => { + env.opts._ = [path.normalize(`${__dirname}/../../fixtures`)]; + env.sourceFiles = []; + srcParser = jsdoc.createParser(); + require('jsdoc/src/handlers').attachTo(srcParser); + }); - afterEach(() => { - env.opts._ = sourcePaths; - env.sourceFiles = sourceFiles; - }); + afterEach(() => { + env.opts._ = sourcePaths; + env.sourceFiles = sourceFiles; + }); - it('When a file overview tag appears in a doclet, the name of the doclet should contain the path to the file.', () => { - const filename = path.resolve(env.dirname, 'test/fixtures/file.js'); + it('When a file overview tag appears in a doclet, the name of the doclet should contain the path to the file.', () => { + const filename = path.resolve(env.dirname, 'test/fixtures/file.js'); - env.sourceFiles.push(filename); - doclets = srcParser.parse(filename); + env.sourceFiles.push(filename); + doclets = srcParser.parse(filename); - expect(doclets[0].name).toMatch(/^file\.js$/); - }); + expect(doclets[0].name).toMatch(/^file\.js$/); + }); - it('The name and longname should be equal', () => { - const filename = 'test/fixtures/file.js'; + it('The name and longname should be equal', () => { + const filename = 'test/fixtures/file.js'; - env.sourceFiles.push(filename); - doclets = srcParser.parse( - path.normalize( path.join(env.dirname, filename) ) - ); + env.sourceFiles.push(filename); + doclets = srcParser.parse(path.normalize(path.join(env.dirname, filename))); - expect(doclets[0].name).toBe(doclets[0].longname); - }); + expect(doclets[0].name).toBe(doclets[0].longname); + }); - it('The name should not include the entire filepath when the source file is outside the ' + - 'JSDoc directory', () => { - const Doclet = require('jsdoc/doclet').Doclet; + it( + 'The name should not include the entire filepath when the source file is outside the ' + + 'JSDoc directory', + () => { + const Doclet = require('jsdoc/doclet').Doclet; - let doclet; - let docletMeta; - let docletSrc; - let fakePath = path.resolve(path.join(env.dirname, '..', 'somefile.js')); + let doclet; + let docletMeta; + let docletSrc; + let fakePath = path.resolve(path.join(env.dirname, '..', 'somefile.js')); - // set up the environment to reflect the fake filepath - env.opts._ = [fakePath]; + // set up the environment to reflect the fake filepath + env.opts._ = [fakePath]; - // create a doclet with a fake filepath, then add a `@file` tag - docletSrc = '/** @class */'; - docletMeta = { - lineno: 1, - filename: fakePath - }; - doclet = new Doclet(docletSrc, docletMeta); - doclet.addTag('file', 'A random file.'); + // create a doclet with a fake filepath, then add a `@file` tag + docletSrc = '/** @class */'; + docletMeta = { + lineno: 1, + filename: fakePath, + }; + doclet = new Doclet(docletSrc, docletMeta); + doclet.addTag('file', 'A random file.'); - expect(doclet.name).toBe('somefile.js'); - }); + expect(doclet.name).toBe('somefile.js'); + } + ); }); diff --git a/packages/jsdoc/test/specs/tags/packagetag.js b/packages/jsdoc/test/specs/tags/packagetag.js index e10ff621..d7f1d0fb 100644 --- a/packages/jsdoc/test/specs/tags/packagetag.js +++ b/packages/jsdoc/test/specs/tags/packagetag.js @@ -1,58 +1,55 @@ describe('@package tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/packagetag.js'); - const foo = docSet.getByLongname('foo')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/packagetag.js'); + const foo = docSet.getByLongname('foo')[0]; - it('When a symbol has a @package tag, the doclet has an `access` property set to `package`.', - () => { - expect(foo.access).toBe('package'); - }); + it('When a symbol has a @package tag, the doclet has an `access` property set to `package`.', () => { + expect(foo.access).toBe('package'); + }); - describe('JSDoc tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); - - it('When JSDoc tags are enabled, the @package tag does not accept a value.', () => { - function getDocSet() { - jsdoc.replaceTagDictionary('jsdoc'); - jsdoc.getDocSetFromFile('test/fixtures/packagetag2.js'); - } - - expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); - }); + describe('JSDoc tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - describe('Closure Compiler tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('When JSDoc tags are enabled, the @package tag does not accept a value.', () => { + function getDocSet() { + jsdoc.replaceTagDictionary('jsdoc'); + jsdoc.getDocSetFromFile('test/fixtures/packagetag2.js'); + } - it('When Closure Compiler tags are enabled, the @package tag accepts a type expression.', - () => { - function getDocSet() { - jsdoc.replaceTagDictionary('closure'); - jsdoc.getDocSetFromFile('test/fixtures/packagetag2.js'); - } - - expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); - }); - - it('When Closure Compiler tags are enabled, the @package tag parses the type expression.', - () => { - let connectionPorts; - let privateDocs; - - jsdoc.replaceTagDictionary('closure'); - - privateDocs = jsdoc.getDocSetFromFile('test/fixtures/packagetag2.js'); - connectionPorts = privateDocs.getByLongname('connectionPorts')[0]; - - expect(connectionPorts).toBeObject(); - expect(connectionPorts.access).toBe('package'); - - expect(connectionPorts.type).toBeObject(); - expect(connectionPorts.type.names).toBeArrayOfSize(1); - expect(connectionPorts.type.names[0]).toBe('Object.'); - }); + expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); }); + }); + + describe('Closure Compiler tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); + }); + + it('When Closure Compiler tags are enabled, the @package tag accepts a type expression.', () => { + function getDocSet() { + jsdoc.replaceTagDictionary('closure'); + jsdoc.getDocSetFromFile('test/fixtures/packagetag2.js'); + } + + expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); + }); + + it('When Closure Compiler tags are enabled, the @package tag parses the type expression.', () => { + let connectionPorts; + let privateDocs; + + jsdoc.replaceTagDictionary('closure'); + + privateDocs = jsdoc.getDocSetFromFile('test/fixtures/packagetag2.js'); + connectionPorts = privateDocs.getByLongname('connectionPorts')[0]; + + expect(connectionPorts).toBeObject(); + expect(connectionPorts.access).toBe('package'); + + expect(connectionPorts.type).toBeObject(); + expect(connectionPorts.type.names).toBeArrayOfSize(1); + expect(connectionPorts.type.names[0]).toBe('Object.'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/paramtag.js b/packages/jsdoc/test/specs/tags/paramtag.js index 1644e794..286f289e 100644 --- a/packages/jsdoc/test/specs/tags/paramtag.js +++ b/packages/jsdoc/test/specs/tags/paramtag.js @@ -1,106 +1,106 @@ describe('@param tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/paramtag.js'); - const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/paramtag2.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/paramtag.js'); + const docSet2 = jsdoc.getDocSetFromFile('test/fixtures/paramtag2.js'); - it('When a symbol has an @param tag with a type before the name, the doclet has a params property that includes that param.', () => { - const find = docSet.getByLongname('find')[0]; + it('When a symbol has an @param tag with a type before the name, the doclet has a params property that includes that param.', () => { + const find = docSet.getByLongname('find')[0]; - expect(find.params).toBeArrayOfSize(1); - expect(find.params[0].type.names.join(', ')).toBe('String, Array.'); - expect(find.params[0].name).toBe('targetName'); - expect(find.params[0].description).toBe('The name (or names) of what to find.'); - }); + expect(find.params).toBeArrayOfSize(1); + expect(find.params[0].type.names.join(', ')).toBe('String, Array.'); + expect(find.params[0].name).toBe('targetName'); + expect(find.params[0].description).toBe('The name (or names) of what to find.'); + }); - it('When a symbol has an @param tag with only a type and name, the doclet has a params property that includes that param.', () => { - const bind = docSet.getByLongname('bind')[0]; + it('When a symbol has an @param tag with only a type and name, the doclet has a params property that includes that param.', () => { + const bind = docSet.getByLongname('bind')[0]; - expect(bind.params).toBeArrayOfSize(1); - expect(bind.params[0].type.names.join(', ')).toBe('function'); - expect(bind.params[0].name).toBe('callback'); - expect(bind.params[0].description).toBeUndefined(); - }); + expect(bind.params).toBeArrayOfSize(1); + expect(bind.params[0].type.names.join(', ')).toBe('function'); + expect(bind.params[0].name).toBe('callback'); + expect(bind.params[0].description).toBeUndefined(); + }); - it('When a symbol has an @param tag with only a type, the doclet has a params property that includes that param.', () => { - const unbind = docSet.getByLongname('unbind')[0]; + it('When a symbol has an @param tag with only a type, the doclet has a params property that includes that param.', () => { + const unbind = docSet.getByLongname('unbind')[0]; - expect(unbind.params).toBeArrayOfSize(1); - expect(unbind.params[0].type.names.join(', ')).toBe('function'); - expect(unbind.params[0].description).toBeUndefined(); - }); + expect(unbind.params).toBeArrayOfSize(1); + expect(unbind.params[0].type.names.join(', ')).toBe('function'); + expect(unbind.params[0].description).toBeUndefined(); + }); - it('When a symbol has an @param tag with no type, the doclet has a params property that includes that param.', () => { - const getElement = docSet.getByLongname('getElement')[0]; + it('When a symbol has an @param tag with no type, the doclet has a params property that includes that param.', () => { + const getElement = docSet.getByLongname('getElement')[0]; - expect(getElement.params).toBeArrayOfSize(1); - expect(getElement.params[0].type).toBeUndefined(); - expect(getElement.params[0].name).toBe('id'); - expect(getElement.params[0].description).toBe('The id of the element.'); - }); + expect(getElement.params).toBeArrayOfSize(1); + expect(getElement.params[0].type).toBeUndefined(); + expect(getElement.params[0].name).toBe('id'); + expect(getElement.params[0].description).toBe('The id of the element.'); + }); - it('When a symbol has an @param tag with a non-alpha name like "...", the doclet has a params property that includes that param.', () => { - const combine = docSet.getByLongname('combine')[0]; + it('When a symbol has an @param tag with a non-alpha name like "...", the doclet has a params property that includes that param.', () => { + const combine = docSet.getByLongname('combine')[0]; - expect(combine.params).toBeArrayOfSize(1); - expect(combine.params[0].type).toBeUndefined(); - expect(combine.params[0].name).toBe('...'); - expect(combine.params[0].description).toBe('Two or more elements.'); - }); + expect(combine.params).toBeArrayOfSize(1); + expect(combine.params[0].type).toBeUndefined(); + expect(combine.params[0].name).toBe('...'); + expect(combine.params[0].description).toBe('Two or more elements.'); + }); - it('When a symbol has an @param tag with name followed by a dash, the doclet has a params property that includes that param.', () => { - const split = docSet.getByLongname('split')[0]; + it('When a symbol has an @param tag with name followed by a dash, the doclet has a params property that includes that param.', () => { + const split = docSet.getByLongname('split')[0]; - expect(split.params).toBeArrayOfSize(1); - expect(split.params[0].type).toBeUndefined(); - expect(split.params[0].name).toBe('delimiter'); - expect(split.params[0].description).toBe('What to split on.'); - }); + expect(split.params).toBeArrayOfSize(1); + expect(split.params[0].type).toBeUndefined(); + expect(split.params[0].name).toBe('delimiter'); + expect(split.params[0].description).toBe('What to split on.'); + }); - it('When a symbol has an @param tag with no name or type, the doclet has a params property that includes that param.', () => { - const commit = docSet.getByLongname('commit')[0]; + it('When a symbol has an @param tag with no name or type, the doclet has a params property that includes that param.', () => { + const commit = docSet.getByLongname('commit')[0]; - expect(commit.params).toBeArrayOfSize(1); - expect(commit.params[0].type).toBeUndefined(); - expect(commit.params[0].description).toBe('If true make the commit atomic.'); - }); + expect(commit.params).toBeArrayOfSize(1); + expect(commit.params[0].type).toBeUndefined(); + expect(commit.params[0].description).toBe('If true make the commit atomic.'); + }); - it('When a symbol has a @param tag with no type but a name that indicates a default value or optional type, this is copied over to the params property.', () => { - const request = docSet.getByLongname('request')[0]; + it('When a symbol has a @param tag with no type but a name that indicates a default value or optional type, this is copied over to the params property.', () => { + const request = docSet.getByLongname('request')[0]; - expect(request.params).toBeArrayOfSize(1); - expect(request.params[0].type).toBeUndefined(); - expect(request.params[0].name).toBe('async'); - expect(request.params[0].defaultvalue).toBeTrue(); - expect(request.params[0].optional).toBeTrue(); - expect(request.params[0].description).toBe('whether to be asynchronous'); - }); + expect(request.params).toBeArrayOfSize(1); + expect(request.params[0].type).toBeUndefined(); + expect(request.params[0].name).toBe('async'); + expect(request.params[0].defaultvalue).toBeTrue(); + expect(request.params[0].optional).toBeTrue(); + expect(request.params[0].description).toBe('whether to be asynchronous'); + }); - it('When a symbol has a @param tag with no name, the doclet includes the param name from the code', () => { - const commit = docSet.getByLongname('commit')[0]; + it('When a symbol has a @param tag with no name, the doclet includes the param name from the code', () => { + const commit = docSet.getByLongname('commit')[0]; - expect(commit.params).toBeArrayOfSize(1); - expect(commit.params[0].name).toBe('atomic'); - }); + expect(commit.params).toBeArrayOfSize(1); + expect(commit.params[0].name).toBe('atomic'); + }); - it('When a symbol has a @param tag with no name, and the symbol is part of an assignment expression, the doclet includes the param name from the code', () => { - const classOpen = docSet.getByLongname('MySocket#open')[0]; - const moduleOpen = docSet2.getByLongname('module:mysocket.open')[0]; + it('When a symbol has a @param tag with no name, and the symbol is part of an assignment expression, the doclet includes the param name from the code', () => { + const classOpen = docSet.getByLongname('MySocket#open')[0]; + const moduleOpen = docSet2.getByLongname('module:mysocket.open')[0]; - expect(classOpen.params).toBeArrayOfSize(2); - expect(classOpen.params[0].name).toBe('hostname'); - expect(classOpen.params[1].name).toBe('port'); + expect(classOpen.params).toBeArrayOfSize(2); + expect(classOpen.params[0].name).toBe('hostname'); + expect(classOpen.params[1].name).toBe('port'); - expect(moduleOpen.params).toBeArrayOfSize(2); - expect(moduleOpen.params[0].name).toBe('hostname'); - expect(moduleOpen.params[1].name).toBe('port'); - }); + expect(moduleOpen.params).toBeArrayOfSize(2); + expect(moduleOpen.params[0].name).toBe('hostname'); + expect(moduleOpen.params[1].name).toBe('port'); + }); - it('When a symbol has a @param tag with an invalid type expression, the JSDoc comment is ignored.', () => { - const badDocSet = jsdoc.getDocSetFromFile('test/fixtures/paramtaginvalidtype.js'); - const test = badDocSet.getByLongname('Test#test')[0]; + it('When a symbol has a @param tag with an invalid type expression, the JSDoc comment is ignored.', () => { + const badDocSet = jsdoc.getDocSetFromFile('test/fixtures/paramtaginvalidtype.js'); + const test = badDocSet.getByLongname('Test#test')[0]; - expect(test).toBeObject(); - expect(test.meta).toBeObject(); - expect(test.meta.filename).toBe('[[string0]]'); - expect(test.description).toBeUndefined(); - }); + expect(test).toBeObject(); + expect(test.meta).toBeObject(); + expect(test.meta.filename).toBe('[[string0]]'); + expect(test.description).toBeUndefined(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/polymerbehaviortag.js b/packages/jsdoc/test/specs/tags/polymerbehaviortag.js index 22364000..a66d64ff 100644 --- a/packages/jsdoc/test/specs/tags/polymerbehaviortag.js +++ b/packages/jsdoc/test/specs/tags/polymerbehaviortag.js @@ -1,42 +1,42 @@ describe('@polymerBehavior tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @polymerBehavior tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/polymerbehaviortag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @polymerBehavior tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/polymerbehaviortag.js'); + } - it('should not recognize the @polymerBehavior tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/polymerbehaviortag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @polymerBehavior tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/polymerbehaviortag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/polymertag.js b/packages/jsdoc/test/specs/tags/polymertag.js index 5c79e25e..6a958ed0 100644 --- a/packages/jsdoc/test/specs/tags/polymertag.js +++ b/packages/jsdoc/test/specs/tags/polymertag.js @@ -1,42 +1,42 @@ describe('@polymer tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @polymer tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/polymertag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @polymer tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/polymertag.js'); + } - it('should not recognize the @polymer tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/polymertag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @polymer tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/polymertag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/preservetag.js b/packages/jsdoc/test/specs/tags/preservetag.js index f7b5df52..df11b9ae 100644 --- a/packages/jsdoc/test/specs/tags/preservetag.js +++ b/packages/jsdoc/test/specs/tags/preservetag.js @@ -1,41 +1,41 @@ describe('@preserve tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @preserve tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/preservetag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it("should set the doclet's `license` property to the tag value", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/preservetag.js'); + const x = docSet.getByLongname('x')[0]; - it('should not recognize the @preserve tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/preservetag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should set the doclet\'s `license` property to the tag value', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/preservetag.js'); - const x = docSet.getByLongname('x')[0]; - - expect(x.license).toBe('My cool license goes here.'); - }); + expect(x.license).toBe('My cool license goes here.'); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/privatetag.js b/packages/jsdoc/test/specs/tags/privatetag.js index 17d37c96..7231c5b7 100644 --- a/packages/jsdoc/test/specs/tags/privatetag.js +++ b/packages/jsdoc/test/specs/tags/privatetag.js @@ -1,65 +1,65 @@ describe('@private tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/privatetag.js'); - const foo = docSet.getByLongname('Foo')[0]; - const bar = docSet.getByLongname('Foo#bar')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/privatetag.js'); + const foo = docSet.getByLongname('Foo')[0]; + const bar = docSet.getByLongname('Foo#bar')[0]; - it('When a symbol has a @private tag, the doclet has an `access` property set to `private`.', - () => { - expect(foo.access).toBe('private'); - }); + it('When a symbol has a @private tag, the doclet has an `access` property set to `private`.', () => { + expect(foo.access).toBe('private'); + }); - it('When a symbol tagged with @private has members, the members do not inherit the @private ' + - 'tag.', () => { - expect(bar.access).toBeUndefined(); + it( + 'When a symbol tagged with @private has members, the members do not inherit the @private ' + + 'tag.', + () => { + expect(bar.access).toBeUndefined(); + } + ); + + describe('JSDoc tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - describe('JSDoc tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('When JSDoc tags are enabled, the @private tag does not accept a value.', () => { + function getDocSet() { + jsdoc.replaceTagDictionary('jsdoc'); + jsdoc.getDocSetFromFile('test/fixtures/privatetag2.js'); + } - it('When JSDoc tags are enabled, the @private tag does not accept a value.', () => { - function getDocSet() { - jsdoc.replaceTagDictionary('jsdoc'); - jsdoc.getDocSetFromFile('test/fixtures/privatetag2.js'); - } + expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); + }); + }); - expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); - }); + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); - - it('When Closure Compiler tags are enabled, the @private tag accepts a type expression.', - () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/privatetag2.js'); - } - - expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); - }); - - it('When Closure Compiler tags are enabled, the @private tag parses the type expression.', - () => { - let connectionPorts; - let privateDocs; - - privateDocs = jsdoc.getDocSetFromFile('test/fixtures/privatetag2.js'); - connectionPorts = privateDocs.getByLongname('connectionPorts')[0]; - - expect(connectionPorts).toBeObject(); - expect(connectionPorts.access).toBe('private'); - - expect(connectionPorts.type).toBeObject(); - expect(connectionPorts.type.names).toBeArrayOfSize(1); - expect(connectionPorts.type.names[0]).toBe('Object.'); - }); + afterEach(() => { + jsdoc.restoreTagDictionary(); }); + + it('When Closure Compiler tags are enabled, the @private tag accepts a type expression.', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/privatetag2.js'); + } + + expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); + }); + + it('When Closure Compiler tags are enabled, the @private tag parses the type expression.', () => { + let connectionPorts; + let privateDocs; + + privateDocs = jsdoc.getDocSetFromFile('test/fixtures/privatetag2.js'); + connectionPorts = privateDocs.getByLongname('connectionPorts')[0]; + + expect(connectionPorts).toBeObject(); + expect(connectionPorts.access).toBe('private'); + + expect(connectionPorts.type).toBeObject(); + expect(connectionPorts.type.names).toBeArrayOfSize(1); + expect(connectionPorts.type.names[0]).toBe('Object.'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/propertytag.js b/packages/jsdoc/test/specs/tags/propertytag.js index fdb12f05..aae696ef 100644 --- a/packages/jsdoc/test/specs/tags/propertytag.js +++ b/packages/jsdoc/test/specs/tags/propertytag.js @@ -1,30 +1,30 @@ describe('@property tag', () => { - it('When a symbol has a @property tag, the property appears in the doclet.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/propertytag.js'); - const myobject = docSet.getByLongname('myobject')[0]; + it('When a symbol has a @property tag, the property appears in the doclet.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/propertytag.js'); + const myobject = docSet.getByLongname('myobject')[0]; - expect(myobject.properties).toBeArrayOfSize(4); + expect(myobject.properties).toBeArrayOfSize(4); - expect(myobject.properties[0].name).toBe('id'); - expect(myobject.properties[1].name).toBe('defaults'); - expect(myobject.properties[2].name).toBe('defaults.a'); - expect(myobject.properties[3].name).toBe('defaults.b'); + expect(myobject.properties[0].name).toBe('id'); + expect(myobject.properties[1].name).toBe('defaults'); + expect(myobject.properties[2].name).toBe('defaults.a'); + expect(myobject.properties[3].name).toBe('defaults.b'); - expect(myobject.properties[0].defaultvalue).toBe('abc123'); - expect(myobject.properties[2].defaultvalue).toBe(1); + expect(myobject.properties[0].defaultvalue).toBe('abc123'); + expect(myobject.properties[2].defaultvalue).toBe(1); - expect(myobject.properties[1].description).toBe('The default values.'); - expect(myobject.properties[1].type.names[0]).toBe('Object'); - }); + expect(myobject.properties[1].description).toBe('The default values.'); + expect(myobject.properties[1].type.names[0]).toBe('Object'); + }); - it('When a symbol has a @property tag for a numeric property, the property appears in the doclet.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/numericpropertytag.js'); - const numericObject = docSet.getByLongname('numericObject')[0]; + it('When a symbol has a @property tag for a numeric property, the property appears in the doclet.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/numericpropertytag.js'); + const numericObject = docSet.getByLongname('numericObject')[0]; - expect(numericObject.properties).toBeArrayOfSize(3); + expect(numericObject.properties).toBeArrayOfSize(3); - expect(numericObject.properties[0].name).toBe('1'); - expect(numericObject.properties[1].name).toBe('2'); - expect(numericObject.properties[2].name).toBe('3'); - }); + expect(numericObject.properties[0].name).toBe('1'); + expect(numericObject.properties[1].name).toBe('2'); + expect(numericObject.properties[2].name).toBe('3'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/protectedtag.js b/packages/jsdoc/test/specs/tags/protectedtag.js index caf80572..8da237d4 100644 --- a/packages/jsdoc/test/specs/tags/protectedtag.js +++ b/packages/jsdoc/test/specs/tags/protectedtag.js @@ -1,64 +1,68 @@ describe('@protected tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/protectedtag.js'); - const uidCounter = docSet.getByLongname('module:uid~uidCounter')[0]; - const uidRoot = docSet.getByLongname('module:uid~uidObjects.root')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/protectedtag.js'); + const uidCounter = docSet.getByLongname('module:uid~uidCounter')[0]; + const uidRoot = docSet.getByLongname('module:uid~uidObjects.root')[0]; - it('When a symbol has a @protected tag, the doclet has an `access` property set to ' + - '`protected`.', () => { - expect(uidCounter.access).toBe('protected'); + it( + 'When a symbol has a @protected tag, the doclet has an `access` property set to ' + + '`protected`.', + () => { + expect(uidCounter.access).toBe('protected'); + } + ); + + it( + 'When a symbol tagged with @protected has members, the members do not inherit the ' + + '@protected tag.', + () => { + expect(uidRoot.access).toBeUndefined(); + } + ); + + describe('JSDoc tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - it('When a symbol tagged with @protected has members, the members do not inherit the ' + - '@protected tag.', () => { - expect(uidRoot.access).toBeUndefined(); + it('When JSDoc tags are enabled, the @protected tag does not accept a value.', () => { + function getDocSet() { + jsdoc.replaceTagDictionary('jsdoc'); + jsdoc.getDocSetFromFile('test/fixtures/protectedtag2.js'); + } + + expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - describe('JSDoc tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('When Closure Compiler tags are enabled, the @private tag accepts a type expression.', () => { + function getDocSet() { + jsdoc.replaceTagDictionary('closure'); + jsdoc.getDocSetFromFile('test/fixtures/protectedtag2.js'); + } - it('When JSDoc tags are enabled, the @protected tag does not accept a value.', () => { - function getDocSet() { - jsdoc.replaceTagDictionary('jsdoc'); - jsdoc.getDocSetFromFile('test/fixtures/protectedtag2.js'); - } - - expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); - }); + expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); }); - describe('Closure Compiler tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('When Closure Compiler tags are enabled, the @private tag parses the type expression.', () => { + let counter; + let protectedDocs; - it('When Closure Compiler tags are enabled, the @private tag accepts a type expression.', - () => { - function getDocSet() { - jsdoc.replaceTagDictionary('closure'); - jsdoc.getDocSetFromFile('test/fixtures/protectedtag2.js'); - } + jsdoc.replaceTagDictionary('closure'); - expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); - }); + protectedDocs = jsdoc.getDocSetFromFile('test/fixtures/protectedtag2.js'); + counter = protectedDocs.getByLongname('uidCounter')[0]; - it('When Closure Compiler tags are enabled, the @private tag parses the type expression.', - () => { - let counter; - let protectedDocs; + expect(counter).toBeObject(); + expect(counter.access).toBe('protected'); - jsdoc.replaceTagDictionary('closure'); - - protectedDocs = jsdoc.getDocSetFromFile('test/fixtures/protectedtag2.js'); - counter = protectedDocs.getByLongname('uidCounter')[0]; - - expect(counter).toBeObject(); - expect(counter.access).toBe('protected'); - - expect(counter.type).toBeObject(); - expect(counter.type.names).toBeArrayOfSize(1); - expect(counter.type.names[0]).toBe('number'); - }); + expect(counter.type).toBeObject(); + expect(counter.type.names).toBeArrayOfSize(1); + expect(counter.type.names[0]).toBe('number'); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/publictag.js b/packages/jsdoc/test/specs/tags/publictag.js index a57e8a55..60249c98 100644 --- a/packages/jsdoc/test/specs/tags/publictag.js +++ b/packages/jsdoc/test/specs/tags/publictag.js @@ -1,40 +1,40 @@ describe('@public tag', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); + afterEach(() => { + jsdoc.restoreTagDictionary(); + }); + + describe('JSDoc tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('jsdoc'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it("should set the doclet's `access` property to `public`", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/publictag.js'); + const foo = docSet.getByLongname('Foo')[0]; - it('should set the doclet\'s `access` property to `public`', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/publictag.js'); - const foo = docSet.getByLongname('Foo')[0]; + expect(foo.access).toBe('public'); + }); + }); - expect(foo.access).toBe('public'); - }); + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); + it("should set the doclet's `access` property to `public`", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/publictag2.js'); + const bar = docSet.getByLongname('bar')[0]; - it('should set the doclet\'s `access` property to `public`', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/publictag2.js'); - const bar = docSet.getByLongname('bar')[0]; - - expect(bar.access).toBe('public'); - }); - - it('should include the type if one is provided', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/publictag2.js'); - const bar = docSet.getByLongname('bar')[0]; - - expect(bar.type).toBeObject(); - expect(bar.type.names).toBeArrayOfSize(1); - expect(bar.type.names[0]).toBe('string'); - }); + expect(bar.access).toBe('public'); }); + + it('should include the type if one is provided', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/publictag2.js'); + const bar = docSet.getByLongname('bar')[0]; + + expect(bar.type).toBeObject(); + expect(bar.type.names).toBeArrayOfSize(1); + expect(bar.type.names[0]).toBe('string'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/readonlytag.js b/packages/jsdoc/test/specs/tags/readonlytag.js index f0a3a4ed..9ed8a7e0 100644 --- a/packages/jsdoc/test/specs/tags/readonlytag.js +++ b/packages/jsdoc/test/specs/tags/readonlytag.js @@ -1,8 +1,8 @@ describe('@readonly tag', () => { - it('When a symbol has an @readonly tag, the doclet has an readonly property that is true.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/readonlytag.js'); - const length = docSet.getByLongname('Collection#length')[0]; + it('When a symbol has an @readonly tag, the doclet has an readonly property that is true.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/readonlytag.js'); + const length = docSet.getByLongname('Collection#length')[0]; - expect(length.readonly).toBeTrue(); - }); + expect(length.readonly).toBeTrue(); + }); }); diff --git a/packages/jsdoc/test/specs/tags/requirestag.js b/packages/jsdoc/test/specs/tags/requirestag.js index bcce5b00..160ed331 100644 --- a/packages/jsdoc/test/specs/tags/requirestag.js +++ b/packages/jsdoc/test/specs/tags/requirestag.js @@ -1,23 +1,23 @@ describe('@requires tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/requirestag.js'); - const foo = docSet.getByLongname('foo')[0]; - const bar = docSet.getByLongname('bar')[0]; - const baz = docSet.getByLongname('baz')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/requirestag.js'); + const foo = docSet.getByLongname('foo')[0]; + const bar = docSet.getByLongname('bar')[0]; + const baz = docSet.getByLongname('baz')[0]; - it('When a symbol has a @requires tag, the doclet has a requires property that includes that value, with the "module:" namespace added.', () => { - expect(foo.requires).toBeArrayOfSize(1); - expect(foo.requires[0]).toBe('module:foo/helper'); + it('When a symbol has a @requires tag, the doclet has a requires property that includes that value, with the "module:" namespace added.', () => { + expect(foo.requires).toBeArrayOfSize(1); + expect(foo.requires[0]).toBe('module:foo/helper'); - expect(bar.requires).toBeArrayOfSize(2); - expect(bar.requires[0]).toBe('module:foo'); - expect(bar.requires[1]).toBe('module:Pez#blat'); - }); + expect(bar.requires).toBeArrayOfSize(2); + expect(bar.requires[0]).toBe('module:foo'); + expect(bar.requires[1]).toBe('module:Pez#blat'); + }); - it('When a symbol has a @requires tag whose value is an inline {@link} tag, the doclet has a requires property that includes that tag without modification.', () => { - expect(baz.requires).toBeArrayOfSize(3); - expect(baz.requires[0]).toBe('{@link module:zest}'); - expect(baz.requires[1]).toBe('{@linkplain module:zing}'); - // by design, we don't validate the tag name, as long as it starts with @link - expect(baz.requires[2]).toBe('{@linkstupid module:pizzazz}'); - }); + it('When a symbol has a @requires tag whose value is an inline {@link} tag, the doclet has a requires property that includes that tag without modification.', () => { + expect(baz.requires).toBeArrayOfSize(3); + expect(baz.requires[0]).toBe('{@link module:zest}'); + expect(baz.requires[1]).toBe('{@linkplain module:zing}'); + // by design, we don't validate the tag name, as long as it starts with @link + expect(baz.requires[2]).toBe('{@linkstupid module:pizzazz}'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/returnstag.js b/packages/jsdoc/test/specs/tags/returnstag.js index f0fdc0f9..3040cbe3 100644 --- a/packages/jsdoc/test/specs/tags/returnstag.js +++ b/packages/jsdoc/test/specs/tags/returnstag.js @@ -1,32 +1,32 @@ describe('@returns tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/returnstag.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/returnstag.js'); - it('When a symbol has a @returns tag with a type and description, the doclet has a "returns" property that includes that info.', () => { - const find = docSet.getByLongname('find')[0]; + it('When a symbol has a @returns tag with a type and description, the doclet has a "returns" property that includes that info.', () => { + const find = docSet.getByLongname('find')[0]; - expect(find.returns).toBeArrayOfSize(1); - expect(find.returns[0].type.names.join(', ')).toBe('string, Array.'); - expect(find.returns[0].description).toBe('The names of the found item(s).'); - }); + expect(find.returns).toBeArrayOfSize(1); + expect(find.returns[0].type.names.join(', ')).toBe('string, Array.'); + expect(find.returns[0].description).toBe('The names of the found item(s).'); + }); - it('When a symbol has a @returns tag with a non-nullable type, the doclet indicates that the type is non-nullable', () => { - const getName = docSet.getByLongname('getName')[0]; + it('When a symbol has a @returns tag with a non-nullable type, the doclet indicates that the type is non-nullable', () => { + const getName = docSet.getByLongname('getName')[0]; - expect(getName.returns).toBeArrayOfSize(1); - expect(getName.returns[0].nullable).toBeFalse(); - }); + expect(getName.returns).toBeArrayOfSize(1); + expect(getName.returns[0].nullable).toBeFalse(); + }); - it('When a symbol has a @returns tag with only a description, the doclet has a "returns" property that includes the description.', () => { - const bind = docSet.getByLongname('bind')[0]; + it('When a symbol has a @returns tag with only a description, the doclet has a "returns" property that includes the description.', () => { + const bind = docSet.getByLongname('bind')[0]; - expect(bind.returns).toBeArrayOfSize(1); - expect(bind.returns[0].description).toBe('The binding id.'); - }); + expect(bind.returns).toBeArrayOfSize(1); + expect(bind.returns[0].description).toBe('The binding id.'); + }); - it('When a symbol has a @returns tag without a type but with an inline tag, the inline tag is not mistaken for a type.', () => { - const convert = docSet.getByLongname('convert')[0]; + it('When a symbol has a @returns tag without a type but with an inline tag, the inline tag is not mistaken for a type.', () => { + const convert = docSet.getByLongname('convert')[0]; - expect(convert.returns).toBeArrayOfSize(1); - expect(convert.returns[0].description).toBe('An object to be passed to {@link find}.'); - }); + expect(convert.returns).toBeArrayOfSize(1); + expect(convert.returns[0].description).toBe('An object to be passed to {@link find}.'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/scopetags.js b/packages/jsdoc/test/specs/tags/scopetags.js index 72031c9b..40315e63 100644 --- a/packages/jsdoc/test/specs/tags/scopetags.js +++ b/packages/jsdoc/test/specs/tags/scopetags.js @@ -1,28 +1,28 @@ describe('scope tags', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/scopetags.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/scopetags.js'); - // @inner, @instance, @static (@global has its own file) - describe('@inner tag', () => { - const doc = docSet.getByLongname('module:scopetags~myInner')[0]; + // @inner, @instance, @static (@global has its own file) + describe('@inner tag', () => { + const doc = docSet.getByLongname('module:scopetags~myInner')[0]; - it("sets the doclet's 'scope' property to 'inner'", () => { - expect(doc.scope).toBe('inner'); - }); + it("sets the doclet's 'scope' property to 'inner'", () => { + expect(doc.scope).toBe('inner'); }); + }); - describe('@instance tag', () => { - const doc = docSet.getByLongname('module:scopetags#myInstance')[0]; + describe('@instance tag', () => { + const doc = docSet.getByLongname('module:scopetags#myInstance')[0]; - it("sets the doclet's 'scope' property to 'instance'", () => { - expect(doc.scope).toBe('instance'); - }); + it("sets the doclet's 'scope' property to 'instance'", () => { + expect(doc.scope).toBe('instance'); }); + }); - describe('@static tag', () => { - const doc = docSet.getByLongname('module:scopetags.myStatic')[0]; + describe('@static tag', () => { + const doc = docSet.getByLongname('module:scopetags.myStatic')[0]; - it("sets the doclet's 'scope' property to 'static'", () => { - expect(doc.scope).toBe('static'); - }); + it("sets the doclet's 'scope' property to 'static'", () => { + expect(doc.scope).toBe('static'); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/seetag.js b/packages/jsdoc/test/specs/tags/seetag.js index 57cf2bf8..f933b227 100644 --- a/packages/jsdoc/test/specs/tags/seetag.js +++ b/packages/jsdoc/test/specs/tags/seetag.js @@ -1,13 +1,13 @@ describe('@see tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/seetag.js'); - const foo = docSet.getByLongname('foo')[0]; - const bar = docSet.getByLongname('bar')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/seetag.js'); + const foo = docSet.getByLongname('foo')[0]; + const bar = docSet.getByLongname('bar')[0]; - it('When a symbol has an @see tag, the doclet has a see property that includes that value.', () => { - expect(foo.see).toBeArrayOfSize(1); - expect(foo.see[0]).toBe('{@link bar}'); + it('When a symbol has an @see tag, the doclet has a see property that includes that value.', () => { + expect(foo.see).toBeArrayOfSize(1); + expect(foo.see[0]).toBe('{@link bar}'); - expect(bar.see).toBeArrayOfSize(1); - expect(bar.see[0]).toBe('http://example.com/someref'); - }); + expect(bar.see).toBeArrayOfSize(1); + expect(bar.see[0]).toBe('http://example.com/someref'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/sincetag.js b/packages/jsdoc/test/specs/tags/sincetag.js index cf2279b3..a36d563a 100644 --- a/packages/jsdoc/test/specs/tags/sincetag.js +++ b/packages/jsdoc/test/specs/tags/sincetag.js @@ -1,8 +1,8 @@ describe('@since tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/sincetag.js'); - const foo = docSet.getByLongname('foo')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/sincetag.js'); + const foo = docSet.getByLongname('foo')[0]; - it('When a symbol has an @since tag, the doclet has a since property set to true.', () => { - expect(foo.since).toBe('1.2.3'); - }); + it('When a symbol has an @since tag, the doclet has a since property set to true.', () => { + expect(foo.since).toBe('1.2.3'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/structtag.js b/packages/jsdoc/test/specs/tags/structtag.js index 060f7df9..e32ef26b 100644 --- a/packages/jsdoc/test/specs/tags/structtag.js +++ b/packages/jsdoc/test/specs/tags/structtag.js @@ -1,42 +1,42 @@ describe('@struct tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @struct tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/structtag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @struct tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/structtag.js'); + } - it('should not recognize the @struct tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/structtag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @struct tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/structtag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/summarytag.js b/packages/jsdoc/test/specs/tags/summarytag.js index b04616a3..36fca395 100644 --- a/packages/jsdoc/test/specs/tags/summarytag.js +++ b/packages/jsdoc/test/specs/tags/summarytag.js @@ -1,8 +1,8 @@ describe('@summary tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/summarytag.js'); - const doc = docSet.getByLongname('Sam')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/summarytag.js'); + const doc = docSet.getByLongname('Sam')[0]; - it("sets the doclet's 'summary' property to the tag value", () => { - expect(doc.summary).toBe('I do not like green eggs and ham!'); - }); + it("sets the doclet's 'summary' property to the tag value", () => { + expect(doc.summary).toBe('I do not like green eggs and ham!'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/suppresstag.js b/packages/jsdoc/test/specs/tags/suppresstag.js index f3103db7..a13aa235 100644 --- a/packages/jsdoc/test/specs/tags/suppresstag.js +++ b/packages/jsdoc/test/specs/tags/suppresstag.js @@ -1,42 +1,42 @@ describe('@suppress tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @suppress tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/suppresstag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @suppress tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/suppresstag.js'); + } - it('should not recognize the @suppress tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/suppresstag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @suppress tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/suppresstag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/templatetag.js b/packages/jsdoc/test/specs/tags/templatetag.js index 9de35ced..20738bbc 100644 --- a/packages/jsdoc/test/specs/tags/templatetag.js +++ b/packages/jsdoc/test/specs/tags/templatetag.js @@ -1,42 +1,42 @@ describe('@template tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @template tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/templatetag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @template tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/templatetag.js'); + } - it('should not recognize the @template tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/templatetag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @template tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/templatetag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/thistag.js b/packages/jsdoc/test/specs/tags/thistag.js index 9d868952..7927af6b 100644 --- a/packages/jsdoc/test/specs/tags/thistag.js +++ b/packages/jsdoc/test/specs/tags/thistag.js @@ -1,58 +1,58 @@ describe('@this tag', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); + afterEach(() => { + jsdoc.restoreTagDictionary(); + }); + + describe('JSDoc tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('jsdoc'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it("should add a `this` property set to the @this tag's value", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag.js'); + const setName = docSet.getByLongname('setName')[0]; - it('should add a `this` property set to the @this tag\'s value', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag.js'); - const setName = docSet.getByLongname('setName')[0]; - - expect(setName.this).toBe('Foo'); - }); - - it('should change the memberof for symbols like `this.foo`', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag.js'); - const fooName = docSet.getByLongname('Foo#name')[0]; - - expect(fooName).toBeObject(); - expect(fooName.name).toBe('name'); - expect(fooName.memberof).toBe('Foo'); - expect(fooName.scope).toBe('instance'); - }); + expect(setName.this).toBe('Foo'); }); - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); + it('should change the memberof for symbols like `this.foo`', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag.js'); + const fooName = docSet.getByLongname('Foo#name')[0]; - it('should add a `this` property set to the @this tag\'s type expression', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag2.js'); - const setName = docSet.getByLongname('setName')[0]; - - expect(setName.this).toBe('Foo'); - }); - - it('should change the memberof for symbols like `this.foo`', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag2.js'); - const fooName = docSet.getByLongname('Foo#name')[0]; - - expect(fooName).toBeObject(); - expect(fooName.name).toBe('name'); - expect(fooName.memberof).toBe('Foo'); - expect(fooName.scope).toBe('instance'); - }); - - it('should work with type unions', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag2.js'); - const getName = docSet.getByLongname('getName')[0]; - - expect(getName.this).toBe('(Foo|Bar)'); - }); + expect(fooName).toBeObject(); + expect(fooName.name).toBe('name'); + expect(fooName.memberof).toBe('Foo'); + expect(fooName.scope).toBe('instance'); }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); + }); + + it("should add a `this` property set to the @this tag's type expression", () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag2.js'); + const setName = docSet.getByLongname('setName')[0]; + + expect(setName.this).toBe('Foo'); + }); + + it('should change the memberof for symbols like `this.foo`', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag2.js'); + const fooName = docSet.getByLongname('Foo#name')[0]; + + expect(fooName).toBeObject(); + expect(fooName.name).toBe('name'); + expect(fooName.memberof).toBe('Foo'); + expect(fooName.scope).toBe('instance'); + }); + + it('should work with type unions', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/thistag2.js'); + const getName = docSet.getByLongname('getName')[0]; + + expect(getName.this).toBe('(Foo|Bar)'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/todotag.js b/packages/jsdoc/test/specs/tags/todotag.js index 4e4090eb..a0dba6ee 100644 --- a/packages/jsdoc/test/specs/tags/todotag.js +++ b/packages/jsdoc/test/specs/tags/todotag.js @@ -1,10 +1,10 @@ describe('@todo tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/todotag.js'); - const doc = docSet.getByLongname('x')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/todotag.js'); + const doc = docSet.getByLongname('x')[0]; - it("adds the entries into a 'todo' array on the doclet", () => { - expect(doc.todo).toBeArrayOfSize(2); - expect(doc.todo).toContain('something'); - expect(doc.todo).toContain('something else'); - }); + it("adds the entries into a 'todo' array on the doclet", () => { + expect(doc.todo).toBeArrayOfSize(2); + expect(doc.todo).toContain('something'); + expect(doc.todo).toContain('something else'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/typedeftag.js b/packages/jsdoc/test/specs/tags/typedeftag.js index 1932c049..5f2b4ce8 100644 --- a/packages/jsdoc/test/specs/tags/typedeftag.js +++ b/packages/jsdoc/test/specs/tags/typedeftag.js @@ -1,90 +1,90 @@ describe('@typedef tag', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); + afterEach(() => { + jsdoc.restoreTagDictionary(); + }); + + describe('JSDoc tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('jsdoc'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('When a comment has a @typedef tag, the doclet has a kind property set to "typedef".', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); + const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - it('When a comment has a @typedef tag, the doclet has a kind property set to "typedef".', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); - const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - - expect(numberlike.kind).toBe('typedef'); - }); - - it('When a comment has a @typedef tag with a type, the doclet has a type property set to that type.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); - const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - - expect(numberlike.type).toBeObject(); - expect(numberlike.type.names).toBeArrayOfSize(2); - expect(numberlike.type.names[0]).toBe('string'); - expect(numberlike.type.names[1]).toBe('number'); - }); - - it('When a comment has a @typedef tag with a name, the doclet has a name property set to that name.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); - const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - - expect(numberlike.name).toBe('NumberLike'); - expect(numberlike.longname).toBe('calc.NumberLike'); - }); - - it('When a symbol has a @typedef tag without a name, the doclet has a name property set to the symbol name.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); - const operator = docSet.getByLongname('calc.Operator')[0]; - - expect(operator.name).toBe('Operator'); - expect(operator.longname).toBe('calc.Operator'); - }); - - it('When a symbol has a @typedef tag with a name, the name in the tag takes precedence over the symbol name.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); - const result = docSet.getByLongname('calc.Result')[0]; - - expect(result.name).toBe('Result'); - expect(result.longname).toBe('calc.Result'); - }); - - it('When a symbol has a @typedef tag with a name and no scope, the scope defaults to `global`.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); - const calculatorBattery = docSet.getByLongname('CalculatorBattery')[0]; - - expect(calculatorBattery).toBeObject(); - expect(calculatorBattery.scope).toBe('global'); - }); + expect(numberlike.kind).toBe('typedef'); }); - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); + it('When a comment has a @typedef tag with a type, the doclet has a type property set to that type.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); + const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - it('When a comment has a @typedef tag, the doclet has a kind property set to "typedef".', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag2.js'); - const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - - expect(numberlike.kind).toBe('typedef'); - }); - - it('When a comment has a @typedef tag with a type, the doclet has a type property set to that type.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag2.js'); - const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - - expect(numberlike.type).toBeObject(); - expect(numberlike.type.names).toBeArrayOfSize(2); - expect(numberlike.type.names[0]).toBe('string'); - expect(numberlike.type.names[1]).toBe('number'); - }); - - it('When a symbol has a @typedef tag, the doclet has a name property set to the symbol name.', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag2.js'); - const numberlike = docSet.getByLongname('calc.NumberLike')[0]; - - expect(numberlike.name).toBe('NumberLike'); - }); + expect(numberlike.type).toBeObject(); + expect(numberlike.type.names).toBeArrayOfSize(2); + expect(numberlike.type.names[0]).toBe('string'); + expect(numberlike.type.names[1]).toBe('number'); }); + + it('When a comment has a @typedef tag with a name, the doclet has a name property set to that name.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); + const numberlike = docSet.getByLongname('calc.NumberLike')[0]; + + expect(numberlike.name).toBe('NumberLike'); + expect(numberlike.longname).toBe('calc.NumberLike'); + }); + + it('When a symbol has a @typedef tag without a name, the doclet has a name property set to the symbol name.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); + const operator = docSet.getByLongname('calc.Operator')[0]; + + expect(operator.name).toBe('Operator'); + expect(operator.longname).toBe('calc.Operator'); + }); + + it('When a symbol has a @typedef tag with a name, the name in the tag takes precedence over the symbol name.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); + const result = docSet.getByLongname('calc.Result')[0]; + + expect(result.name).toBe('Result'); + expect(result.longname).toBe('calc.Result'); + }); + + it('When a symbol has a @typedef tag with a name and no scope, the scope defaults to `global`.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag.js'); + const calculatorBattery = docSet.getByLongname('CalculatorBattery')[0]; + + expect(calculatorBattery).toBeObject(); + expect(calculatorBattery.scope).toBe('global'); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); + }); + + it('When a comment has a @typedef tag, the doclet has a kind property set to "typedef".', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag2.js'); + const numberlike = docSet.getByLongname('calc.NumberLike')[0]; + + expect(numberlike.kind).toBe('typedef'); + }); + + it('When a comment has a @typedef tag with a type, the doclet has a type property set to that type.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag2.js'); + const numberlike = docSet.getByLongname('calc.NumberLike')[0]; + + expect(numberlike.type).toBeObject(); + expect(numberlike.type.names).toBeArrayOfSize(2); + expect(numberlike.type.names[0]).toBe('string'); + expect(numberlike.type.names[1]).toBe('number'); + }); + + it('When a symbol has a @typedef tag, the doclet has a name property set to the symbol name.', () => { + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typedeftag2.js'); + const numberlike = docSet.getByLongname('calc.NumberLike')[0]; + + expect(numberlike.name).toBe('NumberLike'); + }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/typekind.js b/packages/jsdoc/test/specs/tags/typekind.js index 2d845a6d..2cf62f37 100644 --- a/packages/jsdoc/test/specs/tags/typekind.js +++ b/packages/jsdoc/test/specs/tags/typekind.js @@ -1,15 +1,15 @@ describe('@kind tag with type', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typekind.js'); - const blog = docSet.getByLongname('module:blog/server')[0]; - const port = docSet.getByLongname('module:blog/server.port')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typekind.js'); + const blog = docSet.getByLongname('module:blog/server')[0]; + const port = docSet.getByLongname('module:blog/server.port')[0]; - it('When a module symbol has an kind tag, that includes a {type} clause, the doclet has a type property set to that {type} clause', () => { - expect(blog.type).toBeObject(); - expect(blog.type.names.join(', ')).toBe('ConnectServer'); - }); + it('When a module symbol has an kind tag, that includes a {type} clause, the doclet has a type property set to that {type} clause', () => { + expect(blog.type).toBeObject(); + expect(blog.type.names.join(', ')).toBe('ConnectServer'); + }); - it('When a property symbol has an kind tag, that includes a {type} clause, the doclet has a type property set to that {type} clause', () => { - expect(port.type).toBeObject(); - expect(port.type.names.join(', ')).toBe('number'); - }); + it('When a property symbol has an kind tag, that includes a {type} clause, the doclet has a type property set to that {type} clause', () => { + expect(port.type).toBeObject(); + expect(port.type.names.join(', ')).toBe('number'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/typetag.js b/packages/jsdoc/test/specs/tags/typetag.js index ae200848..f34f6b99 100644 --- a/packages/jsdoc/test/specs/tags/typetag.js +++ b/packages/jsdoc/test/specs/tags/typetag.js @@ -1,66 +1,66 @@ describe('@type tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/typetag.js'); + const docSet = jsdoc.getDocSetFromFile('test/fixtures/typetag.js'); - it('When a symbol has a @type tag, the doclet has a type property set to that value\'s type.', () => { - const foo = docSet.getByLongname('foo')[0]; + it("When a symbol has a @type tag, the doclet has a type property set to that value's type.", () => { + const foo = docSet.getByLongname('foo')[0]; - expect(foo.type).toBeObject(); - expect(foo.type.names).toBeArrayOfStrings(); - expect(foo.type.names.join(', ')).toBe('string, Array.'); + expect(foo.type).toBeObject(); + expect(foo.type.names).toBeArrayOfStrings(); + expect(foo.type.names.join(', ')).toBe('string, Array.'); + }); + + it("When a symbol has a @type tag set to a plain string, the doclet has a type property set to that value's type.", () => { + const bar = docSet.getByLongname('bar')[0]; + + expect(bar.type.names.join(', ')).toBe('integer'); + }); + + it('When a symbol has a @type tag for a non-nullable type, the doclet indicates that the type is non-nullable', () => { + const baz = docSet.getByLongname('baz')[0]; + + expect(baz.nullable).toBeFalse(); + }); + + describe('JSDoc tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - it('When a symbol has a @type tag set to a plain string, the doclet has a type property set to that value\'s type.', () => { - const bar = docSet.getByLongname('bar')[0]; + it('When JSDoc tags are enabled, the @type tag does not accept a description.', () => { + function getDocSet() { + jsdoc.replaceTagDictionary('jsdoc'); + jsdoc.getDocSetFromFile('test/fixtures/typetag2.js'); + } - expect(bar.type.names.join(', ')).toBe('integer'); + expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); + }); + }); + + describe('Closure tags', () => { + afterEach(() => { + jsdoc.restoreTagDictionary(); }); - it('When a symbol has a @type tag for a non-nullable type, the doclet indicates that the type is non-nullable', () => { - const baz = docSet.getByLongname('baz')[0]; + it('When Closure tags are enabled, the @type tag accepts a description.', () => { + function getDocSet() { + jsdoc.replaceTagDictionary('closure'); + jsdoc.getDocSetFromFile('test/fixtures/typetag2.js'); + } - expect(baz.nullable).toBeFalse(); + expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); }); - describe('JSDoc tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); + it('When Closure tags are enabled, the @type tag captures the description.', () => { + let stringOrNumber; + let typeDocs; - it('When JSDoc tags are enabled, the @type tag does not accept a description.', () => { - function getDocSet() { - jsdoc.replaceTagDictionary('jsdoc'); - jsdoc.getDocSetFromFile('test/fixtures/typetag2.js'); - } + jsdoc.replaceTagDictionary('closure'); - expect(jsdoc.didLog(getDocSet, 'warn')).toBeTrue(); - }); - }); - - describe('Closure tags', () => { - afterEach(() => { - jsdoc.restoreTagDictionary(); - }); - - it('When Closure tags are enabled, the @type tag accepts a description.', () => { - function getDocSet() { - jsdoc.replaceTagDictionary('closure'); - jsdoc.getDocSetFromFile('test/fixtures/typetag2.js'); - } - - expect(jsdoc.didLog(getDocSet, 'warn')).toBeFalse(); - }); - - it('When Closure tags are enabled, the @type tag captures the description.', () => { - let stringOrNumber; - let typeDocs; - - jsdoc.replaceTagDictionary('closure'); - - typeDocs = jsdoc.getDocSetFromFile('test/fixtures/typetag2.js'); - stringOrNumber = typeDocs.getByLongname('stringOrNumber')[0]; - - expect(stringOrNumber).toBeObject(); - expect(stringOrNumber.description).toBe('A string or a number.'); - }); + typeDocs = jsdoc.getDocSetFromFile('test/fixtures/typetag2.js'); + stringOrNumber = typeDocs.getByLongname('stringOrNumber')[0]; + + expect(stringOrNumber).toBeObject(); + expect(stringOrNumber.description).toBe('A string or a number.'); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/undocumentedtag.js b/packages/jsdoc/test/specs/tags/undocumentedtag.js index 32642978..1c88d237 100644 --- a/packages/jsdoc/test/specs/tags/undocumentedtag.js +++ b/packages/jsdoc/test/specs/tags/undocumentedtag.js @@ -1,12 +1,12 @@ describe('@undocumented tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/undocumentedtag.js'); - const doc = docSet.getByLongname('x')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/undocumentedtag.js'); + const doc = docSet.getByLongname('x')[0]; - it("sets the doclet's 'undocumented' property to true", () => { - expect(doc.undocumented).toBeTrue(); - }); + it("sets the doclet's 'undocumented' property to true", () => { + expect(doc.undocumented).toBeTrue(); + }); - it("clears the doclet's 'comment' property", () => { - expect(doc.comment).toBe(''); - }); + it("clears the doclet's 'comment' property", () => { + expect(doc.comment).toBe(''); + }); }); diff --git a/packages/jsdoc/test/specs/tags/unrestrictedtag.js b/packages/jsdoc/test/specs/tags/unrestrictedtag.js index 55c0e693..89a46b5a 100644 --- a/packages/jsdoc/test/specs/tags/unrestrictedtag.js +++ b/packages/jsdoc/test/specs/tags/unrestrictedtag.js @@ -1,42 +1,42 @@ describe('@unrestricted tag', () => { - const env = require('jsdoc/env'); + const env = require('jsdoc/env'); - const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + const allowUnknownTags = Boolean(env.conf.tags.allowUnknownTags); + beforeEach(() => { + env.conf.tags.allowUnknownTags = false; + }); + + afterEach(() => { + jsdoc.restoreTagDictionary(); + env.conf.tags.allowUnknownTags = allowUnknownTags; + }); + + describe('JSDoc tags', () => { beforeEach(() => { - env.conf.tags.allowUnknownTags = false; + jsdoc.replaceTagDictionary('jsdoc'); }); - afterEach(() => { - jsdoc.restoreTagDictionary(); - env.conf.tags.allowUnknownTags = allowUnknownTags; + it('should not recognize the @unrestricted tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/unrestrictedtag.js'); + } + + expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); + }); + }); + + describe('Closure Compiler tags', () => { + beforeEach(() => { + jsdoc.replaceTagDictionary('closure'); }); - describe('JSDoc tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('jsdoc'); - }); + it('should recognize the @unrestricted tag', () => { + function getDocSet() { + jsdoc.getDocSetFromFile('test/fixtures/unrestrictedtag.js'); + } - it('should not recognize the @unrestricted tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/unrestrictedtag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeTrue(); - }); - }); - - describe('Closure Compiler tags', () => { - beforeEach(() => { - jsdoc.replaceTagDictionary('closure'); - }); - - it('should recognize the @unrestricted tag', () => { - function getDocSet() { - jsdoc.getDocSetFromFile('test/fixtures/unrestrictedtag.js'); - } - - expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); - }); + expect(jsdoc.didLog(getDocSet, 'error')).toBeFalse(); }); + }); }); diff --git a/packages/jsdoc/test/specs/tags/variationtag.js b/packages/jsdoc/test/specs/tags/variationtag.js index 6dbddc69..2ea40fc3 100644 --- a/packages/jsdoc/test/specs/tags/variationtag.js +++ b/packages/jsdoc/test/specs/tags/variationtag.js @@ -1,19 +1,19 @@ describe('@variation tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/variationtag.js'); - const someObject2 = docSet.getByLongname('someObject(2)')[0]; - const someObject2Method = docSet.getByLongname('someObject(2).someMethod')[0]; - const someObject3 = docSet.getByLongname('someObject(3)')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/variationtag.js'); + const someObject2 = docSet.getByLongname('someObject(2)')[0]; + const someObject2Method = docSet.getByLongname('someObject(2).someMethod')[0]; + const someObject3 = docSet.getByLongname('someObject(3)')[0]; - it('When a symbol has a variation tag, the longname includes that variation.', () => { - expect(someObject2.longname).toBe('someObject(2)'); - }); + it('When a symbol has a variation tag, the longname includes that variation.', () => { + expect(someObject2.longname).toBe('someObject(2)'); + }); - it('When a symbol is a member of a variation, the longname includes the variation.', () => { - expect(someObject2Method.longname).toBe('someObject(2).someMethod'); - }); + it('When a symbol is a member of a variation, the longname includes the variation.', () => { + expect(someObject2Method.longname).toBe('someObject(2).someMethod'); + }); - it('When the variation tag\'s value is enclosed in parentheses, the parentheses are removed', () => { - expect(someObject3).toBeObject(); - expect(someObject3.variation).toBe('3'); - }); + it("When the variation tag's value is enclosed in parentheses, the parentheses are removed", () => { + expect(someObject3).toBeObject(); + expect(someObject3.variation).toBe('3'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/versiontag.js b/packages/jsdoc/test/specs/tags/versiontag.js index 48a4db68..211fc4ea 100644 --- a/packages/jsdoc/test/specs/tags/versiontag.js +++ b/packages/jsdoc/test/specs/tags/versiontag.js @@ -1,8 +1,8 @@ describe('@version tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/versiontag.js'); - const foo = docSet.getByLongname('foo')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/versiontag.js'); + const foo = docSet.getByLongname('foo')[0]; - it('When a symbol has a @version tag, the doclet has a version property set to that value.', () => { - expect(foo.version).toBe('1.2.3'); - }); + it('When a symbol has a @version tag, the doclet has a version property set to that value.', () => { + expect(foo.version).toBe('1.2.3'); + }); }); diff --git a/packages/jsdoc/test/specs/tags/yieldstag.js b/packages/jsdoc/test/specs/tags/yieldstag.js index 17f67860..5b7a8f13 100644 --- a/packages/jsdoc/test/specs/tags/yieldstag.js +++ b/packages/jsdoc/test/specs/tags/yieldstag.js @@ -1,24 +1,24 @@ describe('@yields tag', () => { - const docSet = jsdoc.getDocSetFromFile('test/fixtures/yieldstag.js'); - const fibonacci = docSet.getByLongname('fibonacci')[0]; - const fibonacci2 = docSet.getByLongname('fibonacci2')[0]; - const fibonacci3 = docSet.getByLongname('fibonacci3')[0]; + const docSet = jsdoc.getDocSetFromFile('test/fixtures/yieldstag.js'); + const fibonacci = docSet.getByLongname('fibonacci')[0]; + const fibonacci2 = docSet.getByLongname('fibonacci2')[0]; + const fibonacci3 = docSet.getByLongname('fibonacci3')[0]; - it('should add the type and description to the doclet\'s `yields` property', () => { - expect(fibonacci.yields).toBeArrayOfSize(1); - expect(fibonacci.yields[0].type.names.join(', ')).toBe('number'); - expect(fibonacci.yields[0].description).toBe('The next number in the Fibonacci sequence.'); - }); + it("should add the type and description to the doclet's `yields` property", () => { + expect(fibonacci.yields).toBeArrayOfSize(1); + expect(fibonacci.yields[0].type.names.join(', ')).toBe('number'); + expect(fibonacci.yields[0].description).toBe('The next number in the Fibonacci sequence.'); + }); - it('should work when only a description is present', () => { - expect(fibonacci2.yields).toBeArrayOfSize(1); - expect(fibonacci2.yields[0].type).toBeUndefined(); - expect(fibonacci2.yields[0].description).toBe('The next number in the Fibonacci sequence.'); - }); + it('should work when only a description is present', () => { + expect(fibonacci2.yields).toBeArrayOfSize(1); + expect(fibonacci2.yields[0].type).toBeUndefined(); + expect(fibonacci2.yields[0].description).toBe('The next number in the Fibonacci sequence.'); + }); - it('should work when only a type is present', () => { - expect(fibonacci3.yields).toBeArrayOfSize(1); - expect(fibonacci3.yields[0].type.names.join(', ')).toBe('number'); - expect(fibonacci3.yields[0].description).toBeUndefined(); - }); + it('should work when only a type is present', () => { + expect(fibonacci3.yields).toBeArrayOfSize(1); + expect(fibonacci3.yields[0].type.names.join(', ')).toBe('number'); + expect(fibonacci3.yields[0].description).toBeUndefined(); + }); });