added all files to project

This commit is contained in:
2022-03-10 10:36:59 +01:00
parent 09dd957b33
commit 46a936d7de
25351 changed files with 3883356 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
{
"plugins": [
"@babel/plugin-syntax-class-properties"
],
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": 10
}
}
]
],
"env": {
"test": {
"plugins": [ "istanbul" ]
}
}
}
+15
View File
@@ -0,0 +1,15 @@
; EditorConfig file: https://EditorConfig.org
; Install the "EditorConfig" plugin into your editor to use
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
[*.md]
indent_size = 4
+4
View File
@@ -0,0 +1,4 @@
coverage
node_modules
dist
!.*.js
+29
View File
@@ -0,0 +1,29 @@
'use strict';
module.exports = {
extends: [
'ash-nazg/sauron-node-overrides'
],
settings: {
polyfills: [
'console',
'Error',
'Set'
]
},
overrides: [
{
files: 'test/**'
}
],
// Auto-set dynamically by config but needs to be explicit for Atom
parserOptions: {
ecmaVersion: 2021
},
rules: {
// https://github.com/benmosher/eslint-plugin-import/issues/1868
'import/no-unresolved': 'off'
}
};
+201
View File
@@ -0,0 +1,201 @@
# CHANGES for `@es-joy/jsdoccomment`
## 0.10.8
### User-impacting
- npm: Liberalize `engines` as per `comment-parser` change
- npm: Bump `comment-parser`
### Dev-impacting
- Linting: As per latest ash-nazg
- npm: Update devDeps.
## 0.10.7
- npm: Update comment-parser with CJS fix and re-exports
- npm: Update devDeps.
## 0.10.6
- Fix: Ensure copying latest build of `comment-parser`'s ESM utils
## 0.10.5
- npm: Bump fixed `jsdoc-type-pratt-parser` and devDeps.
## 0.10.4
- Fix: Bundle `comment-parser` nested imports so that IDEs (like Atom)
bundling older Node versions can still work. Still mirroring the
stricter `comment-parser` `engines` for now, however.
## 0.10.3
- npm: Avoid exporting nested subpaths for sake of older Node versions
## 0.10.2
- npm: Specify exact supported range: `^12.20 || ^14.14.0 || ^16`
## 0.10.1
- npm: Apply patch version of `comment-parser`
## 0.10.0
- npm: Point to stable `comment-parser`
## 0.9.0-alpha.6
### User-impacting
- Update: For `comment-parser` update, add `lineEnd`
## 0.9.0-alpha.5
### User-impacting
- npm: Bump `comment-parser` (for true ESM)
- Update: Remove extensions for packages for native ESM in `comment-parser` fix
### Dev-impacting
- npm: Update devDeps.
## 0.9.0-alpha.4
- Docs: Update repo info in `package.json`
## 0.9.0-alpha.3
- Fix: Due to `comment-parser` still needing changes, revert for now to alpha.1
## 0.9.0-alpha.2
### User-impacting
- npm: Bump `comment-parser` (for true ESM)
- Update: Remove extensions for packages for native ESM in `comment-parser` fix
### Dev-impacting
- npm: Update devDeps.
## 0.9.0-alpha.1
### User-impacting
- Breaking change: Indicate minimum for `engines` as Node >= 12
- npm: Bump `comment-parser`
### Dev-impacting
- npm: Lint cjs files
- npm: Fix eslint script
- npm: Update devDeps.
## 0.8.0
### User-impacting
- npm: Update `jsdoc-type-pratt-parser` (prerelease to stable patch)
### Dev-impacting
- npm: Update devDeps.
## 0.8.0-alpha.2
- Fix: Avoid erring with missing `typeLines`
## 0.8.0-alpha.1
- Breaking change: Export globally as `JsdocComment`
- Breaking change: Change `JSDoc` prefixes of all node types to `Jsdoc`
- Breaking change: Drop `jsdoctypeparserToESTree`
- Breaking enhancement: Switch to `jsdoc-type-pratt-parser` (toward greater
TypeScript expressivity and compatibility/support with catharsis)
- Enhancement: Export `jsdocTypeVisitorKeys` (from `jsdoc-type-pratt-parser`)
## 0.7.2
- Fix: Add `@description` to `noNames`
## 0.7.1
- Fix: Add `@summary` to `noNames`
## 0.7.0
- Enhancement: Allow specifying `noNames` and `noTypes` on `parseComment`
to override (or add to) tags which should have no names or types.
- Enhancement: Export `hasSeeWithLink` utility and `defaultNoTypes` and
`defaultNoNames`.
## 0.6.0
- Change `comment-parser` `tag` AST to avoid initial `@`
## 0.5.1
- Fix: Avoid setting `variation` name (just the description) (including in
dist)
- npm: Add `prepublishOnly` script
## 0.5.0
- Fix: Avoid setting `variation` name (just the description)
## 0.4.4
- Fix: Avoid setting `name` and `description` for simple `@template SomeName`
## 0.4.3
- npm: Ignores Github file
## 0.4.2
- Fix: Ensure replacement of camel-casing (used in `jsdoctypeparser` nodes and
visitor keys is global. The practical effect is that
`JSDocTypeNamed_parameter` -> `JSDocTypeNamedParameter`,
`JSDocTypeRecord_entry` -> `JSDocTypeRecordEntry`
`JSDocTypeNot_nullable` -> `JSDocTypeNotNullable`
`JSDocTypeInner_member` -> `JSDocTypeInnerMember`
`JSDocTypeInstance_member` -> `JSDocTypeInstanceMember`
`JSDocTypeString_value` -> `JSDocTypeStringValue`
`JSDocTypeNumber_value` -> `JSDocTypeNumberValue`
`JSDocTypeFile_path` -> `JSDocTypeFilePath`
`JSDocTypeType_query` -> `JSDocTypeTypeQuery`
`JSDocTypeKey_query` -> `JSDocTypeKeyQuery`
- Fix: Add missing `JSDocTypeLine` to visitor keys
- Docs: Explain AST structure/differences
## 0.4.1
- Docs: Indicate available methods with brief summary on README
## 0.4.0
- Enhancement: Expose `parseComment` and `getTokenizers`.
## 0.3.0
- Enhancement: Expose `toCamelCase` as new method rather than within a
utility file.
## 0.2.0
- Enhancement: Exposes new methods: `commentHandler`,
`commentParserToESTree`, `jsdocVisitorKeys`, `jsdoctypeparserToESTree`,
`jsdocTypeVisitorKeys`,
## 0.1.1
- Build: Add Babel to work with earlier Node
## 0.1.0
- Initial version
+20
View File
@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors, https://js.foundation
Copyright (c) 2021 Brett Zamir
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+190
View File
@@ -0,0 +1,190 @@
# @es-joy/jsdoccomment
[![Node.js CI status](https://github.com/brettz9/getJSDocComment/workflows/Node.js%20CI/badge.svg)](https://github.com/brettz9/getJSDocComment/actions)
This project aims to preserve and expand upon the
`SourceCode#getJSDocComment` functionality of the deprecated ESLint method.
It also exports a number of functions currently for working with JSDoc:
## API
### `parseComment`
For parsing `comment-parser` in a JSDoc-specific manner.
Might wish to have tags with or without tags, etc. derived from a split off
JSON file.
### `commentParserToESTree`
Converts [comment-parser](https://github.com/syavorsky/comment-parser)
AST to ESTree/ESLint/Babel friendly AST. See the "ESLint AST..." section below.
### `jsdocVisitorKeys`
The [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
for `JsdocBlock`, `JsdocDescriptionLine`, and `JsdocTag`. More likely to be
subject to change or dropped in favor of another type parser.
### `jsdocTypeVisitorKeys`
Just a re-export of [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
from [`jsdoc-type-pratt-parser`](https://github.com/simonseyock/jsdoc-type-pratt-parser/).
### `getDefaultTagStructureForMode`
Provides info on JSDoc tags:
- `nameContents` ('namepath-referencing'|'namepath-defining'|
'dual-namepath-referencing'|false) - Whether and how a name is allowed
following any type. Tags without a proper name (value `false`) may still
have a description (which can appear like a name); `descriptionAllowed`
in such cases would be `true`.
The presence of a truthy `nameContents` value is therefore only intended
to signify whether separate parsing should occur for a name vs. a
description, and what its nature should be.
- `nameRequired` (boolean) - Whether a name must be present following any type.
- `descriptionAllowed` (boolean) - Whether a description (following any name)
is allowed.
- `typeAllowed` (boolean) - Whether the tag accepts a curly bracketed portion.
Even without a type, a tag may still have a name and/or description.
- `typeRequired` (boolean) - Whether a curly bracketed type must be present.
- `typeOrNameRequired` (boolean) - Whether either a curly bracketed type is
required or a name, but not necessarily both.
### Miscellaneous
Also currently exports these utilities, though they might be removed in the
future:
- `getTokenizers` - Used with `parseComment` (its main core)
- `toCamelCase` - Convert to CamelCase.
- `hasSeeWithLink` - A utility to detect if a tag is `@see` and has a `@link`
- `commentHandler` - Used by `eslint-plugin-jsdoc`. Might be removed in future.
- `commentParserToESTree`- Converts [comment-parser](https://github.com/syavorsky/comment-parser)
AST to ESTree/ESLint/Babel friendly AST
- `jsdocVisitorKeys` - The [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
for `JSDocBlock`, `JSDocDescriptionLine`, and `JSDocTag`. Might change.
- `jsdocTypeVisitorKeys` - [VisitorKeys](https://github.com/eslint/eslint-visitor-keys)
for `jsdoc-type-pratt-parser`.
- `getTokenizers` - A utility. Might be removed in future.
- `toCamelCase` - A utility. Might be removed in future.
- `hasSeeWithLink` - A utility to detect if a tag is `@see` and has a `@link`
- `defaultNoTypes` = The tags which allow no types by default:
`default`, `defaultvalue`, `see`;
- `defaultNoNames` - The tags which allow no names by default:
`access`, `author`, `default`, `defaultvalue`, `description`, `example`,
`exception`, `license`, `return`, `returns`, `since`, `summary`, `throws`,
`version`, `variation`
## ESLint AST produced for `comment-parser` nodes (`JsdocBlock`, `JsdocTag`, and `JsdocDescriptionLine`)
Note: Although not added in this package, `@es-joy/jsdoc-eslint-parser` adds
a `jsdoc` property to other ES nodes (using this project's `getJSDocComment`
to determine the specific comment-block that will be attached as AST).
### `JsdocBlock`
Has two visitable properties:
1. `tags` (an array of `JsdocTag`; see below)
2. `descriptionLines` (an array of `JsdocDescriptionLine` for multiline
descriptions).
Has the following custom non-visitable property:
1. `lastDescriptionLine` - A number
May also have the following non-visitable properties from `comment-parser`:
1. `description` - Same as `descriptionLines` but as a string with newlines.
2. `delimiter`
3. `postDelimiter`
4. `end`
### `JsdocTag`
Has three visitable properties:
1. `parsedType` (the `jsdoc-type-pratt-parser` AST representaiton of the tag's
type (see the `jsdoc-type-pratt-parser` section below)).
2. `descriptionLines`' (an array of `JsdocDescriptionLine` for multiline
descriptions)
3. `typeLines` (an array of `JsdocTypeLine` for multiline type strings)
May also have the following non-visitable properties from `comment-parser`
(note that all are included from `comment-parser` except `end` as that is only
for JSDoc blocks and note that `type` is renamed to `rawType`):
1. `description` - Same as `descriptionLines` but as a string with newlines.
2. `rawType` - `comment-parser` has this named as `type`, but because of a
conflict with ESTree using `type` for Node type, we renamed it to
`rawType`. It is otherwise the same as in `comment-parser`, i.e., a string
with newlines, though with the initial `{` and final `}` stripped out.
See `typeLines` for the array version of this property.
3. `start`
4. `delimiter`
5. `postDelimiter`
6. `tag` (this does differ from `comment-parser` now in terms of our stripping
the initial `@`)
7. `postTag`
8. `name`
9. `postName`
10. `type`
11. `postType`
### `JsdocDescriptionLine`
No visitable properties.
May also have the following non-visitable properties from `comment-parser`:
1. `delimiter`
2. `postDelimiter`
3. `start`
4. `description`
### `JsdocTypeLine`
No visitable properties.
May also have the following non-visitable properties from `comment-parser`:
1. `delimiter`
2. `postDelimiter`
3. `start`
4. `rawType` - Renamed from `comment-parser` to avoid a conflict. See
explanation under `JsdocTag`
## ESLint AST produced for `jsdoc-type-pratt-parser`
The AST, including `type`, remains as is from [jsdoc-type-pratt-parser](https://github.com/simonseyock/jsdoc-type-pratt-parser/).
The type will always begin with a `JsdocType` prefix added, along with a
camel-cased type name, e.g., `JsdocTypeUnion`.
The `jsdoc-type-pratt-parser` visitor keys are also preserved without change.
## Installation
```shell
npm i @es-joy/jsdoccomment
```
## Changelog
The changelog can be found on the [CHANGES.md](./CHANGES.md).
<!--## Contributing
Everyone is welcome to contribute. Please take a moment to review the [contributing guidelines](CONTRIBUTING.md).
-->
## Authors and license
[Brett Zamir](http://brett-zamir.me/) and
[contributors](https://github.com/es-joy/jsdoc-eslint-parser/graphs/contributors).
MIT License, see the included [LICENSE-MIT.txt](LICENSE-MIT.txt) file.
## To-dos
1. Get complete code coverage
+534
View File
@@ -0,0 +1,534 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsdocTypePrattParser = require('jsdoc-type-pratt-parser');
var esquery = require('esquery');
var commentParser = require('comment-parser');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var esquery__default = /*#__PURE__*/_interopDefaultLegacy(esquery);
const stripEncapsulatingBrackets = (container, isArr) => {
if (isArr) {
const firstItem = container[0];
firstItem.rawType = firstItem.rawType.replace(/^\{/u, '');
const lastItem = container[container.length - 1];
lastItem.rawType = lastItem.rawType.replace(/\}$/u, '');
return;
}
container.rawType = container.rawType.replace(/^\{/u, '').replace(/\}$/u, '');
};
const commentParserToESTree = (jsdoc, mode) => {
const {
tokens: {
delimiter: delimiterRoot,
lineEnd: lineEndRoot,
postDelimiter: postDelimiterRoot,
end: endRoot,
description: descriptionRoot
}
} = jsdoc.source[0];
const ast = {
delimiter: delimiterRoot,
description: descriptionRoot,
descriptionLines: [],
// `end` will be overwritten if there are other entries
end: endRoot,
postDelimiter: postDelimiterRoot,
lineEnd: lineEndRoot,
type: 'JsdocBlock'
};
const tags = [];
let lastDescriptionLine;
let lastTag = null;
jsdoc.source.slice(1).forEach((info, idx) => {
const {
tokens
} = info;
const {
delimiter,
description,
postDelimiter,
start,
tag,
end,
type: rawType
} = tokens;
if (tag || end) {
if (lastDescriptionLine === undefined) {
lastDescriptionLine = idx;
} // Clean-up with last tag before end or new tag
if (lastTag) {
// Strip out `}` that encapsulates and is not part of
// the type
stripEncapsulatingBrackets(lastTag);
if (lastTag.typeLines.length) {
stripEncapsulatingBrackets(lastTag.typeLines, true);
} // With even a multiline type now in full, add parsing
let parsedType = null;
try {
parsedType = jsdocTypePrattParser.parse(lastTag.rawType, mode);
} catch {// Ignore
}
lastTag.parsedType = parsedType;
}
if (end) {
ast.end = end;
return;
}
const {
end: ed,
...tkns
} = tokens;
const tagObj = { ...tkns,
descriptionLines: [],
rawType: '',
type: 'JsdocTag',
typeLines: []
};
tagObj.tag = tagObj.tag.replace(/^@/u, '');
lastTag = tagObj;
tags.push(tagObj);
}
if (rawType) {
// Will strip rawType brackets after this tag
lastTag.typeLines.push({
delimiter,
postDelimiter,
rawType,
start,
type: 'JsdocTypeLine'
});
lastTag.rawType += rawType;
}
if (description) {
const holder = lastTag || ast;
holder.descriptionLines.push({
delimiter,
description,
postDelimiter,
start,
type: 'JsdocDescriptionLine'
});
holder.description += holder.description ? '\n' + description : description;
}
});
ast.lastDescriptionLine = lastDescriptionLine;
ast.tags = tags;
return ast;
};
const jsdocVisitorKeys = {
JsdocBlock: ['tags', 'descriptionLines'],
JsdocDescriptionLine: [],
JsdocTypeLine: [],
JsdocTag: ['descriptionLines', 'typeLines', 'parsedType']
};
/**
* @callback CommentHandler
* @param {string} commentSelector
* @param {Node} jsdoc
* @returns {boolean}
*/
/**
* @param {Settings} settings
* @returns {CommentHandler}
*/
const commentHandler = settings => {
/**
* @type {CommentHandler}
*/
return (commentSelector, jsdoc) => {
const {
mode
} = settings;
const selector = esquery__default['default'].parse(commentSelector);
const ast = commentParserToESTree(jsdoc, mode);
return esquery__default['default'].matches(ast, selector, null, {
visitorKeys: { ...jsdocTypePrattParser.visitorKeys,
...jsdocVisitorKeys
}
});
};
};
const toCamelCase = str => {
return str.toLowerCase().replace(/^[a-z]/gu, init => {
return init.toUpperCase();
}).replace(/_(?<wordInit>[a-z])/gu, (_, n1, o, s, {
wordInit
}) => {
return wordInit.toUpperCase();
});
};
/* eslint-disable prefer-named-capture-group -- Temporary */
const {
seedBlock,
seedTokens
} = commentParser.util;
const {
name: nameTokenizer,
tag: tagTokenizer,
type: typeTokenizer,
description: descriptionTokenizer
} = commentParser.tokenizers;
const hasSeeWithLink = spec => {
return spec.tag === 'see' && /\{@link.+?\}/u.test(spec.source[0].source);
};
const defaultNoTypes = ['default', 'defaultvalue', 'see'];
const defaultNoNames = ['access', 'author', 'default', 'defaultvalue', 'description', 'example', 'exception', 'license', 'return', 'returns', 'since', 'summary', 'throws', 'version', 'variation'];
const getTokenizers = ({
noTypes = defaultNoTypes,
noNames = defaultNoNames
} = {}) => {
// trim
return [// Tag
tagTokenizer(), // Type
spec => {
if (noTypes.includes(spec.tag)) {
return spec;
}
return typeTokenizer()(spec);
}, // Name
spec => {
if (spec.tag === 'template') {
// const preWS = spec.postTag;
const remainder = spec.source[0].tokens.description;
const pos = remainder.search(/(?<![\s,])\s/u);
const name = pos === -1 ? remainder : remainder.slice(0, pos);
const extra = remainder.slice(pos + 1);
let postName = '',
description = '',
lineEnd = '';
if (pos > -1) {
[, postName, description, lineEnd] = extra.match(/(\s*)([^\r]*)(\r)?/u);
}
spec.name = name;
spec.optional = false;
const {
tokens
} = spec.source[0];
tokens.name = name;
tokens.postName = postName;
tokens.description = description;
tokens.lineEnd = lineEnd || '';
return spec;
}
if (noNames.includes(spec.tag) || hasSeeWithLink(spec)) {
return spec;
}
return nameTokenizer()(spec);
}, // Description
spec => {
return descriptionTokenizer('preserve')(spec);
}];
};
/**
*
* @param {PlainObject} commentNode
* @param {string} indent Whitespace
* @returns {PlainObject}
*/
const parseComment = (commentNode, indent) => {
// Preserve JSDoc block start/end indentation.
return commentParser.parse(`/*${commentNode.value}*/`, {
// @see https://github.com/yavorskiy/comment-parser/issues/21
tokenizers: getTokenizers()
})[0] || seedBlock({
source: [{
number: 0,
tokens: seedTokens({
delimiter: '/**'
})
}, {
number: 1,
tokens: seedTokens({
end: '*/',
start: indent + ' '
})
}]
});
};
/**
* Obtained originally from {@link https://github.com/eslint/eslint/blob/master/lib/util/source-code.js#L313}.
*
* @license MIT
*/
/**
* Checks if the given token is a comment token or not.
*
* @param {Token} token - The token to check.
* @returns {boolean} `true` if the token is a comment token.
*/
const isCommentToken = token => {
return token.type === 'Line' || token.type === 'Block' || token.type === 'Shebang';
};
const getDecorator = node => {
var _node$declaration, _node$declaration$dec, _node$decorators, _node$parent, _node$parent$decorato;
return (node === null || node === void 0 ? void 0 : (_node$declaration = node.declaration) === null || _node$declaration === void 0 ? void 0 : (_node$declaration$dec = _node$declaration.decorators) === null || _node$declaration$dec === void 0 ? void 0 : _node$declaration$dec[0]) || (node === null || node === void 0 ? void 0 : (_node$decorators = node.decorators) === null || _node$decorators === void 0 ? void 0 : _node$decorators[0]) || (node === null || node === void 0 ? void 0 : (_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : (_node$parent$decorato = _node$parent.decorators) === null || _node$parent$decorato === void 0 ? void 0 : _node$parent$decorato[0]);
};
/**
* Check to see if its a ES6 export declaration.
*
* @param {ASTNode} astNode An AST node.
* @returns {boolean} whether the given node represents an export declaration.
* @private
*/
const looksLikeExport = function (astNode) {
return astNode.type === 'ExportDefaultDeclaration' || astNode.type === 'ExportNamedDeclaration' || astNode.type === 'ExportAllDeclaration' || astNode.type === 'ExportSpecifier';
};
const getTSFunctionComment = function (astNode) {
const {
parent
} = astNode;
const grandparent = parent.parent;
const greatGrandparent = grandparent.parent;
const greatGreatGrandparent = greatGrandparent && greatGrandparent.parent; // istanbul ignore if
if (parent.type !== 'TSTypeAnnotation') {
return astNode;
}
switch (grandparent.type) {
case 'ClassProperty':
case 'TSDeclareFunction':
case 'TSMethodSignature':
case 'TSPropertySignature':
return grandparent;
case 'ArrowFunctionExpression':
// istanbul ignore else
if (greatGrandparent.type === 'VariableDeclarator' // && greatGreatGrandparent.parent.type === 'VariableDeclaration'
) {
return greatGreatGrandparent.parent;
} // istanbul ignore next
return astNode;
case 'FunctionExpression':
// istanbul ignore else
if (greatGrandparent.type === 'MethodDefinition') {
return greatGrandparent;
}
// Fallthrough
default:
// istanbul ignore if
if (grandparent.type !== 'Identifier') {
// istanbul ignore next
return astNode;
}
} // istanbul ignore next
switch (greatGrandparent.type) {
case 'ArrowFunctionExpression':
// istanbul ignore else
if (greatGreatGrandparent.type === 'VariableDeclarator' && greatGreatGrandparent.parent.type === 'VariableDeclaration') {
return greatGreatGrandparent.parent;
} // istanbul ignore next
return astNode;
case 'FunctionDeclaration':
return greatGrandparent;
case 'VariableDeclarator':
// istanbul ignore else
if (greatGreatGrandparent.type === 'VariableDeclaration') {
return greatGreatGrandparent;
}
// Fallthrough
default:
// istanbul ignore next
return astNode;
}
};
const invokedExpression = new Set(['CallExpression', 'OptionalCallExpression', 'NewExpression']);
const allowableCommentNode = new Set(['VariableDeclaration', 'ExpressionStatement', 'MethodDefinition', 'Property', 'ObjectProperty', 'ClassProperty']);
/**
* Reduces the provided node to the appropriate node for evaluating
* JSDoc comment status.
*
* @param {ASTNode} node An AST node.
* @param {SourceCode} sourceCode The ESLint SourceCode.
* @returns {ASTNode} The AST node that can be evaluated for appropriate
* JSDoc comments.
* @private
*/
const getReducedASTNode = function (node, sourceCode) {
let {
parent
} = node;
switch (node.type) {
case 'TSFunctionType':
return getTSFunctionComment(node);
case 'TSInterfaceDeclaration':
case 'TSTypeAliasDeclaration':
case 'TSEnumDeclaration':
case 'ClassDeclaration':
case 'FunctionDeclaration':
return looksLikeExport(parent) ? parent : node;
case 'TSDeclareFunction':
case 'ClassExpression':
case 'ObjectExpression':
case 'ArrowFunctionExpression':
case 'TSEmptyBodyFunctionExpression':
case 'FunctionExpression':
if (!invokedExpression.has(parent.type)) {
while (!sourceCode.getCommentsBefore(parent).length && !/Function/u.test(parent.type) && !allowableCommentNode.has(parent.type)) {
({
parent
} = parent);
if (!parent) {
break;
}
}
if (parent && parent.type !== 'FunctionDeclaration' && parent.type !== 'Program') {
if (parent.parent && parent.parent.type === 'ExportNamedDeclaration') {
return parent.parent;
}
return parent;
}
}
return node;
default:
return node;
}
};
/**
* Checks for the presence of a JSDoc comment for the given node and returns it.
*
* @param {ASTNode} astNode The AST node to get the comment for.
* @param {SourceCode} sourceCode
* @param {{maxLines: Integer, minLines: Integer}} settings
* @returns {Token|null} The Block comment token containing the JSDoc comment
* for the given node or null if not found.
* @private
*/
const findJSDocComment = (astNode, sourceCode, settings) => {
const {
minLines,
maxLines
} = settings;
let currentNode = astNode;
let tokenBefore = null;
while (currentNode) {
const decorator = getDecorator(currentNode);
if (decorator) {
currentNode = decorator;
}
tokenBefore = sourceCode.getTokenBefore(currentNode, {
includeComments: true
});
if (!tokenBefore || !isCommentToken(tokenBefore)) {
return null;
}
if (tokenBefore.type === 'Line') {
currentNode = tokenBefore;
continue;
}
break;
}
if (tokenBefore.type === 'Block' && tokenBefore.value.charAt(0) === '*' && currentNode.loc.start.line - tokenBefore.loc.end.line >= minLines && currentNode.loc.start.line - tokenBefore.loc.end.line <= maxLines) {
return tokenBefore;
}
return null;
};
/**
* Retrieves the JSDoc comment for a given node.
*
* @param {SourceCode} sourceCode The ESLint SourceCode
* @param {ASTNode} node The AST node to get the comment for.
* @param {PlainObject} settings The settings in context
* @returns {Token|null} The Block comment token containing the JSDoc comment
* for the given node or null if not found.
* @public
*/
const getJSDocComment = function (sourceCode, node, settings) {
const reducedNode = getReducedASTNode(node, sourceCode);
return findJSDocComment(reducedNode, sourceCode, settings);
};
Object.defineProperty(exports, 'jsdocTypeVisitorKeys', {
enumerable: true,
get: function () {
return jsdocTypePrattParser.visitorKeys;
}
});
exports.commentHandler = commentHandler;
exports.commentParserToESTree = commentParserToESTree;
exports.defaultNoNames = defaultNoNames;
exports.defaultNoTypes = defaultNoTypes;
exports.findJSDocComment = findJSDocComment;
exports.getDecorator = getDecorator;
exports.getJSDocComment = getJSDocComment;
exports.getReducedASTNode = getReducedASTNode;
exports.getTokenizers = getTokenizers;
exports.hasSeeWithLink = hasSeeWithLink;
exports.jsdocVisitorKeys = jsdocVisitorKeys;
exports.parseComment = parseComment;
exports.toCamelCase = toCamelCase;
+113
View File
@@ -0,0 +1,113 @@
{
"_args": [
[
"@es-joy/jsdoccomment@0.10.8",
"/home/pi/Desktop/smartMirrorTestEnvironment/MagicMirror"
]
],
"_development": true,
"_from": "@es-joy/jsdoccomment@0.10.8",
"_id": "@es-joy/jsdoccomment@0.10.8",
"_inBundle": false,
"_integrity": "sha512-3P1JiGL4xaR9PoTKUHa2N/LKwa2/eUdRqGwijMWWgBqbFEqJUVpmaOi2TcjcemrsRMgFLBzQCK4ToPhrSVDiFQ==",
"_location": "/@es-joy/jsdoccomment",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "@es-joy/jsdoccomment@0.10.8",
"name": "@es-joy/jsdoccomment",
"escapedName": "@es-joy%2fjsdoccomment",
"scope": "@es-joy",
"rawSpec": "0.10.8",
"saveSpec": null,
"fetchSpec": "0.10.8"
},
"_requiredBy": [
"/eslint-plugin-jsdoc"
],
"_resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.10.8.tgz",
"_spec": "0.10.8",
"_where": "/home/pi/Desktop/smartMirrorTestEnvironment/MagicMirror",
"author": {
"name": "Brett Zamir",
"email": "brettz9@yahoo.com"
},
"browserslist": [
"cover 100%"
],
"bugs": {
"url": "https://github.com/es-joy/jsdoccomment/issues"
},
"c8": {
"checkCoverage": true,
"branches": 100,
"statements": 100,
"lines": 100,
"functions": 100
},
"contributors": [],
"dependencies": {
"comment-parser": "1.2.4",
"esquery": "^1.4.0",
"jsdoc-type-pratt-parser": "1.1.1"
},
"description": "Maintained replacement for ESLint's deprecated SourceCode#getJSDocComment along with other jsdoc utilities",
"devDependencies": {
"@babel/core": "^7.15.0",
"@babel/plugin-syntax-class-properties": "^7.12.13",
"@babel/preset-env": "^7.15.0",
"@brettz9/eslint-plugin": "^1.0.3",
"@rollup/plugin-babel": "^5.3.0",
"c8": "^7.8.0",
"chai": "^4.3.4",
"eslint": "^7.32.0",
"eslint-config-ash-nazg": "31.2.2",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-array-func": "^3.1.7",
"eslint-plugin-compat": "^3.13.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-html": "^6.1.2",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jsdoc": "^36.0.7",
"eslint-plugin-markdown": "^2.2.0",
"eslint-plugin-no-unsanitized": "^3.1.5",
"eslint-plugin-no-use-extend-native": "^0.5.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-sonarjs": "^0.10.0",
"eslint-plugin-unicorn": "^35.0.0",
"mocha": "^9.1.0",
"rollup": "^2.56.3"
},
"engines": {
"node": "^12 || ^14 || ^16"
},
"exports": {
"import": "./src/index.js",
"require": "./dist/index.cjs.cjs"
},
"homepage": "https://github.com/es-joy/jsdoccomment",
"keywords": [
"eslint",
"sourcecode"
],
"license": "MIT",
"main": "./dist/index.cjs.cjs",
"name": "@es-joy/jsdoccomment",
"repository": {
"type": "git",
"url": "git+https://github.com/es-joy/jsdoccomment.git"
},
"scripts": {
"c8": "c8 npm run mocha",
"eslint": "eslint --ext=js,cjs,md,html .",
"lint": "npm run eslint",
"mocha": "mocha --parallel --require chai/register-expect",
"prepublishOnly": "pnpm i && npm run rollup",
"rollup": "rollup -c",
"test": "npm run lint && npm run rollup && npm run c8"
},
"type": "module",
"version": "0.10.8"
}
+42
View File
@@ -0,0 +1,42 @@
import esquery from 'esquery';
import {
visitorKeys as jsdocTypePrattParserVisitorKeys
} from 'jsdoc-type-pratt-parser';
import {
commentParserToESTree, jsdocVisitorKeys
} from './commentParserToESTree.js';
/**
* @callback CommentHandler
* @param {string} commentSelector
* @param {Node} jsdoc
* @returns {boolean}
*/
/**
* @param {Settings} settings
* @returns {CommentHandler}
*/
const commentHandler = (settings) => {
/**
* @type {CommentHandler}
*/
return (commentSelector, jsdoc) => {
const {mode} = settings;
const selector = esquery.parse(commentSelector);
const ast = commentParserToESTree(jsdoc, mode);
return esquery.matches(ast, selector, null, {
visitorKeys: {
...jsdocTypePrattParserVisitorKeys,
...jsdocVisitorKeys
}
});
};
};
export default commentHandler;
+149
View File
@@ -0,0 +1,149 @@
import {parse as jsdocTypePrattParse} from 'jsdoc-type-pratt-parser';
const stripEncapsulatingBrackets = (container, isArr) => {
if (isArr) {
const firstItem = container[0];
firstItem.rawType = firstItem.rawType.replace(
/^\{/u, ''
);
const lastItem = container[container.length - 1];
lastItem.rawType = lastItem.rawType.replace(/\}$/u, '');
return;
}
container.rawType = container.rawType.replace(
/^\{/u, ''
).replace(/\}$/u, '');
};
const commentParserToESTree = (jsdoc, mode) => {
const {tokens: {
delimiter: delimiterRoot,
lineEnd: lineEndRoot,
postDelimiter: postDelimiterRoot,
end: endRoot,
description: descriptionRoot
}} = jsdoc.source[0];
const ast = {
delimiter: delimiterRoot,
description: descriptionRoot,
descriptionLines: [],
// `end` will be overwritten if there are other entries
end: endRoot,
postDelimiter: postDelimiterRoot,
lineEnd: lineEndRoot,
type: 'JsdocBlock'
};
const tags = [];
let lastDescriptionLine;
let lastTag = null;
jsdoc.source.slice(1).forEach((info, idx) => {
const {tokens} = info;
const {
delimiter,
description,
postDelimiter,
start,
tag,
end,
type: rawType
} = tokens;
if (tag || end) {
if (lastDescriptionLine === undefined) {
lastDescriptionLine = idx;
}
// Clean-up with last tag before end or new tag
if (lastTag) {
// Strip out `}` that encapsulates and is not part of
// the type
stripEncapsulatingBrackets(lastTag);
if (lastTag.typeLines.length) {
stripEncapsulatingBrackets(lastTag.typeLines, true);
}
// With even a multiline type now in full, add parsing
let parsedType = null;
try {
parsedType = jsdocTypePrattParse(lastTag.rawType, mode);
} catch {
// Ignore
}
lastTag.parsedType = parsedType;
}
if (end) {
ast.end = end;
return;
}
const {
end: ed,
...tkns
} = tokens;
const tagObj = {
...tkns,
descriptionLines: [],
rawType: '',
type: 'JsdocTag',
typeLines: []
};
tagObj.tag = tagObj.tag.replace(/^@/u, '');
lastTag = tagObj;
tags.push(tagObj);
}
if (rawType) {
// Will strip rawType brackets after this tag
lastTag.typeLines.push(
{
delimiter,
postDelimiter,
rawType,
start,
type: 'JsdocTypeLine'
}
);
lastTag.rawType += rawType;
}
if (description) {
const holder = lastTag || ast;
holder.descriptionLines.push({
delimiter,
description,
postDelimiter,
start,
type: 'JsdocDescriptionLine'
});
holder.description += holder.description
? '\n' + description
: description;
}
});
ast.lastDescriptionLine = lastDescriptionLine;
ast.tags = tags;
return ast;
};
const jsdocVisitorKeys = {
JsdocBlock: ['tags', 'descriptionLines'],
JsdocDescriptionLine: [],
JsdocTypeLine: [],
JsdocTag: ['descriptionLines', 'typeLines', 'parsedType']
};
export {commentParserToESTree, jsdocVisitorKeys};
+11
View File
@@ -0,0 +1,11 @@
export {visitorKeys as jsdocTypeVisitorKeys} from 'jsdoc-type-pratt-parser';
export {default as commentHandler} from './commentHandler.js';
export {default as toCamelCase} from './toCamelCase.js';
export * from './parseComment.js';
export * from './commentParserToESTree.js';
export * from './jsdoccomment.js';
+245
View File
@@ -0,0 +1,245 @@
/**
* Obtained originally from {@link https://github.com/eslint/eslint/blob/master/lib/util/source-code.js#L313}.
*
* @license MIT
*/
/**
* Checks if the given token is a comment token or not.
*
* @param {Token} token - The token to check.
* @returns {boolean} `true` if the token is a comment token.
*/
const isCommentToken = (token) => {
return token.type === 'Line' || token.type === 'Block' ||
token.type === 'Shebang';
};
const getDecorator = (node) => {
return node?.declaration?.decorators?.[0] || node?.decorators?.[0] ||
node?.parent?.decorators?.[0];
};
/**
* Check to see if its a ES6 export declaration.
*
* @param {ASTNode} astNode An AST node.
* @returns {boolean} whether the given node represents an export declaration.
* @private
*/
const looksLikeExport = function (astNode) {
return astNode.type === 'ExportDefaultDeclaration' ||
astNode.type === 'ExportNamedDeclaration' ||
astNode.type === 'ExportAllDeclaration' ||
astNode.type === 'ExportSpecifier';
};
const getTSFunctionComment = function (astNode) {
const {parent} = astNode;
const grandparent = parent.parent;
const greatGrandparent = grandparent.parent;
const greatGreatGrandparent = greatGrandparent && greatGrandparent.parent;
// istanbul ignore if
if (parent.type !== 'TSTypeAnnotation') {
return astNode;
}
switch (grandparent.type) {
case 'ClassProperty':
case 'TSDeclareFunction':
case 'TSMethodSignature':
case 'TSPropertySignature':
return grandparent;
case 'ArrowFunctionExpression':
// istanbul ignore else
if (
greatGrandparent.type === 'VariableDeclarator'
// && greatGreatGrandparent.parent.type === 'VariableDeclaration'
) {
return greatGreatGrandparent.parent;
}
// istanbul ignore next
return astNode;
case 'FunctionExpression':
// istanbul ignore else
if (greatGrandparent.type === 'MethodDefinition') {
return greatGrandparent;
}
// Fallthrough
default:
// istanbul ignore if
if (grandparent.type !== 'Identifier') {
// istanbul ignore next
return astNode;
}
}
// istanbul ignore next
switch (greatGrandparent.type) {
case 'ArrowFunctionExpression':
// istanbul ignore else
if (
greatGreatGrandparent.type === 'VariableDeclarator' &&
greatGreatGrandparent.parent.type === 'VariableDeclaration'
) {
return greatGreatGrandparent.parent;
}
// istanbul ignore next
return astNode;
case 'FunctionDeclaration':
return greatGrandparent;
case 'VariableDeclarator':
// istanbul ignore else
if (greatGreatGrandparent.type === 'VariableDeclaration') {
return greatGreatGrandparent;
}
// Fallthrough
default:
// istanbul ignore next
return astNode;
}
};
const invokedExpression = new Set(
['CallExpression', 'OptionalCallExpression', 'NewExpression']
);
const allowableCommentNode = new Set([
'VariableDeclaration',
'ExpressionStatement',
'MethodDefinition',
'Property',
'ObjectProperty',
'ClassProperty'
]);
/**
* Reduces the provided node to the appropriate node for evaluating
* JSDoc comment status.
*
* @param {ASTNode} node An AST node.
* @param {SourceCode} sourceCode The ESLint SourceCode.
* @returns {ASTNode} The AST node that can be evaluated for appropriate
* JSDoc comments.
* @private
*/
const getReducedASTNode = function (node, sourceCode) {
let {parent} = node;
switch (node.type) {
case 'TSFunctionType':
return getTSFunctionComment(node);
case 'TSInterfaceDeclaration':
case 'TSTypeAliasDeclaration':
case 'TSEnumDeclaration':
case 'ClassDeclaration':
case 'FunctionDeclaration':
return looksLikeExport(parent) ? parent : node;
case 'TSDeclareFunction':
case 'ClassExpression':
case 'ObjectExpression':
case 'ArrowFunctionExpression':
case 'TSEmptyBodyFunctionExpression':
case 'FunctionExpression':
if (
!invokedExpression.has(parent.type)
) {
while (
!sourceCode.getCommentsBefore(parent).length &&
!(/Function/u).test(parent.type) &&
!allowableCommentNode.has(parent.type)
) {
({parent} = parent);
if (!parent) {
break;
}
}
if (parent && parent.type !== 'FunctionDeclaration' &&
parent.type !== 'Program'
) {
if (parent.parent && parent.parent.type === 'ExportNamedDeclaration') {
return parent.parent;
}
return parent;
}
}
return node;
default:
return node;
}
};
/**
* Checks for the presence of a JSDoc comment for the given node and returns it.
*
* @param {ASTNode} astNode The AST node to get the comment for.
* @param {SourceCode} sourceCode
* @param {{maxLines: Integer, minLines: Integer}} settings
* @returns {Token|null} The Block comment token containing the JSDoc comment
* for the given node or null if not found.
* @private
*/
const findJSDocComment = (astNode, sourceCode, settings) => {
const {minLines, maxLines} = settings;
let currentNode = astNode;
let tokenBefore = null;
while (currentNode) {
const decorator = getDecorator(currentNode);
if (decorator) {
currentNode = decorator;
}
tokenBefore = sourceCode.getTokenBefore(
currentNode, {includeComments: true}
);
if (!tokenBefore || !isCommentToken(tokenBefore)) {
return null;
}
if (tokenBefore.type === 'Line') {
currentNode = tokenBefore;
continue;
}
break;
}
if (
tokenBefore.type === 'Block' &&
tokenBefore.value.charAt(0) === '*' &&
currentNode.loc.start.line - tokenBefore.loc.end.line >= minLines &&
currentNode.loc.start.line - tokenBefore.loc.end.line <= maxLines
) {
return tokenBefore;
}
return null;
};
/**
* Retrieves the JSDoc comment for a given node.
*
* @param {SourceCode} sourceCode The ESLint SourceCode
* @param {ASTNode} node The AST node to get the comment for.
* @param {PlainObject} settings The settings in context
* @returns {Token|null} The Block comment token containing the JSDoc comment
* for the given node or null if not found.
* @public
*/
const getJSDocComment = function (sourceCode, node, settings) {
const reducedNode = getReducedASTNode(node, sourceCode);
return findJSDocComment(reducedNode, sourceCode, settings);
};
export {
getReducedASTNode, getJSDocComment, getDecorator, findJSDocComment
};
+126
View File
@@ -0,0 +1,126 @@
/* eslint-disable prefer-named-capture-group -- Temporary */
import {
parse as commentParser,
tokenizers,
util
} from 'comment-parser';
const {
seedBlock,
seedTokens
} = util;
const {
name: nameTokenizer,
tag: tagTokenizer,
type: typeTokenizer,
description: descriptionTokenizer
} = tokenizers;
export const hasSeeWithLink = (spec) => {
return spec.tag === 'see' && (/\{@link.+?\}/u).test(spec.source[0].source);
};
export const defaultNoTypes = ['default', 'defaultvalue', 'see'];
export const defaultNoNames = [
'access', 'author',
'default', 'defaultvalue',
'description',
'example', 'exception',
'license',
'return', 'returns',
'since', 'summary',
'throws',
'version', 'variation'
];
const getTokenizers = ({
noTypes = defaultNoTypes,
noNames = defaultNoNames
} = {}) => {
// trim
return [
// Tag
tagTokenizer(),
// Type
(spec) => {
if (noTypes.includes(spec.tag)) {
return spec;
}
return typeTokenizer()(spec);
},
// Name
(spec) => {
if (spec.tag === 'template') {
// const preWS = spec.postTag;
const remainder = spec.source[0].tokens.description;
const pos = remainder.search(/(?<![\s,])\s/u);
const name = pos === -1 ? remainder : remainder.slice(0, pos);
const extra = remainder.slice(pos + 1);
let postName = '', description = '', lineEnd = '';
if (pos > -1) {
[, postName, description, lineEnd] = extra.match(/(\s*)([^\r]*)(\r)?/u);
}
spec.name = name;
spec.optional = false;
const {tokens} = spec.source[0];
tokens.name = name;
tokens.postName = postName;
tokens.description = description;
tokens.lineEnd = lineEnd || '';
return spec;
}
if (noNames.includes(spec.tag) || hasSeeWithLink(spec)) {
return spec;
}
return nameTokenizer()(spec);
},
// Description
(spec) => {
return descriptionTokenizer('preserve')(spec);
}
];
};
/**
*
* @param {PlainObject} commentNode
* @param {string} indent Whitespace
* @returns {PlainObject}
*/
const parseComment = (commentNode, indent) => {
// Preserve JSDoc block start/end indentation.
return commentParser(`/*${commentNode.value}*/`, {
// @see https://github.com/yavorskiy/comment-parser/issues/21
tokenizers: getTokenizers()
})[0] || seedBlock({
source: [
{
number: 0,
tokens: seedTokens({
delimiter: '/**'
})
},
{
number: 1,
tokens: seedTokens({
end: '*/',
start: indent + ' '
})
}
]
});
};
export {getTokenizers, parseComment};
+9
View File
@@ -0,0 +1,9 @@
const toCamelCase = (str) => {
return str.toLowerCase().replace(/^[a-z]/gu, (init) => {
return init.toUpperCase();
}).replace(/_(?<wordInit>[a-z])/gu, (_, n1, o, s, {wordInit}) => {
return wordInit.toUpperCase();
});
};
export default toCamelCase;